From f24dba97f4dff436ebbc8866de8c9e6fa99b85c9 Mon Sep 17 00:00:00 2001
From: Seth Hillbrand <seth@kipro-pcb.com>
Date: Mon, 13 Jan 2025 10:21:07 -0800
Subject: [PATCH] Block preview while menus are shown

When the user is navigating a drop down menu, they don't want the
preview window to pop over their screen.  This glues between the
LIB_TREE and the frame to block these preview events

Fixes https://gitlab.com/kicad/code/kicad/-/issues/19117
---
 eeschema/widgets/panel_symbol_chooser.cpp  | 18 ++++++++++++++++++
 eeschema/widgets/panel_symbol_chooser.h    |  6 ++++++
 eeschema/widgets/symbol_tree_pane.cpp      | 20 ++++++++++++++++++++
 eeschema/widgets/symbol_tree_pane.h        |  6 ++++++
 include/widgets/lib_tree.h                 |  5 +++++
 pcbnew/footprint_tree_pane.cpp             | 20 ++++++++++++++++++++
 pcbnew/footprint_tree_pane.h               |  7 +++++++
 pcbnew/widgets/panel_footprint_chooser.cpp | 18 ++++++++++++++++++
 pcbnew/widgets/panel_footprint_chooser.h   |  6 ++++++
 9 files changed, 106 insertions(+)

diff --git a/eeschema/widgets/panel_symbol_chooser.cpp b/eeschema/widgets/panel_symbol_chooser.cpp
index 35fa7e602d..4c3f98fdf0 100644
--- a/eeschema/widgets/panel_symbol_chooser.cpp
+++ b/eeschema/widgets/panel_symbol_chooser.cpp
@@ -268,6 +268,8 @@ PANEL_SYMBOL_CHOOSER::PANEL_SYMBOL_CHOOSER( SCH_BASE_FRAME* aFrame, wxWindow* aP
     Bind( EVT_LIBITEM_SELECTED, &PANEL_SYMBOL_CHOOSER::onSymbolSelected, this );
     Bind( EVT_LIBITEM_CHOSEN, &PANEL_SYMBOL_CHOOSER::onSymbolChosen, this );
     Bind( wxEVT_CHAR_HOOK, &PANEL_SYMBOL_CHOOSER::OnChar, this );
+    aFrame->Bind( wxEVT_MENU_OPEN, &PANEL_SYMBOL_CHOOSER::onMenuOpen, this );
+    aFrame->Bind( wxEVT_MENU_CLOSE, &PANEL_SYMBOL_CHOOSER::onMenuClose, this );
 
     if( m_fp_sel_ctrl )
     {
@@ -291,6 +293,8 @@ PANEL_SYMBOL_CHOOSER::PANEL_SYMBOL_CHOOSER( SCH_BASE_FRAME* aFrame, wxWindow* aP
 
 PANEL_SYMBOL_CHOOSER::~PANEL_SYMBOL_CHOOSER()
 {
+    m_frame->Unbind( wxEVT_MENU_OPEN, &PANEL_SYMBOL_CHOOSER::onMenuOpen, this );
+    m_frame->Unbind( wxEVT_MENU_CLOSE, &PANEL_SYMBOL_CHOOSER::onMenuClose, this );
     Unbind( wxEVT_TIMER, &PANEL_SYMBOL_CHOOSER::onCloseTimer, this );
     Unbind( EVT_LIBITEM_SELECTED, &PANEL_SYMBOL_CHOOSER::onSymbolSelected, this );
     Unbind( EVT_LIBITEM_CHOSEN, &PANEL_SYMBOL_CHOOSER::onSymbolChosen, this );
@@ -338,6 +342,20 @@ PANEL_SYMBOL_CHOOSER::~PANEL_SYMBOL_CHOOSER()
 }
 
 
+void PANEL_SYMBOL_CHOOSER::onMenuOpen( wxMenuEvent& aEvent )
+{
+    m_tree->BlockPreview( true );
+    aEvent.Skip();
+}
+
+
+void PANEL_SYMBOL_CHOOSER::onMenuClose( wxMenuEvent& aEvent )
+{
+    m_tree->BlockPreview( false );
+    aEvent.Skip();
+}
+
+
 void PANEL_SYMBOL_CHOOSER::OnChar( wxKeyEvent& aEvent )
 {
     if( aEvent.GetKeyCode() == WXK_ESCAPE )
diff --git a/eeschema/widgets/panel_symbol_chooser.h b/eeschema/widgets/panel_symbol_chooser.h
index ce003da9e5..9bbf86c741 100644
--- a/eeschema/widgets/panel_symbol_chooser.h
+++ b/eeschema/widgets/panel_symbol_chooser.h
@@ -111,6 +111,12 @@ protected:
     void onFootprintSelected( wxCommandEvent& aEvent );
     void onSymbolSelected( wxCommandEvent& aEvent );
 
+    /**
+     * Handle parent frame menu events to block tree preview
+     */
+    void onMenuOpen( wxMenuEvent& aEvent );
+    void onMenuClose( wxMenuEvent& aEvent );
+
     /**
      * Handle the selection of an item. This is called when either the search box or the tree
      * receive an Enter, or the tree receives a double click.
diff --git a/eeschema/widgets/symbol_tree_pane.cpp b/eeschema/widgets/symbol_tree_pane.cpp
index 9da1e5824b..8851e1150b 100644
--- a/eeschema/widgets/symbol_tree_pane.cpp
+++ b/eeschema/widgets/symbol_tree_pane.cpp
@@ -53,15 +53,35 @@ SYMBOL_TREE_PANE::SYMBOL_TREE_PANE( SYMBOL_EDIT_FRAME* aParent,
     // Event handlers
     Bind( EVT_LIBITEM_CHOSEN, &SYMBOL_TREE_PANE::onSymbolSelected, this );
     m_tree->Bind( wxEVT_UPDATE_UI, &SYMBOL_TREE_PANE::onUpdateUI, this );
+    m_symbolEditFrame->Bind( wxEVT_MENU_OPEN, &SYMBOL_TREE_PANE::onMenuOpen, this );
+    m_symbolEditFrame->Bind( wxEVT_MENU_CLOSE, &SYMBOL_TREE_PANE::onMenuClose, this );
 }
 
 
 SYMBOL_TREE_PANE::~SYMBOL_TREE_PANE()
 {
+    m_symbolEditFrame->Unbind( wxEVT_MENU_OPEN, &SYMBOL_TREE_PANE::onMenuOpen, this );
+    m_symbolEditFrame->Unbind( wxEVT_MENU_CLOSE, &SYMBOL_TREE_PANE::onMenuClose, this );
+    m_tree->Unbind( wxEVT_UPDATE_UI, &SYMBOL_TREE_PANE::onUpdateUI, this );
+    Unbind( EVT_LIBITEM_CHOSEN, &SYMBOL_TREE_PANE::onSymbolSelected, this );
     m_tree->Destroy();
 }
 
 
+void SYMBOL_TREE_PANE::onMenuOpen( wxMenuEvent& aEvent )
+{
+    m_tree->BlockPreview( true );
+    aEvent.Skip();
+}
+
+
+void SYMBOL_TREE_PANE::onMenuClose( wxMenuEvent& aEvent )
+{
+    m_tree->BlockPreview( false );
+    aEvent.Skip();
+}
+
+
 void SYMBOL_TREE_PANE::onSymbolSelected( wxCommandEvent& aEvent )
 {
     m_symbolEditFrame->GetToolManager()->RunAction( EE_ACTIONS::editSymbol );
diff --git a/eeschema/widgets/symbol_tree_pane.h b/eeschema/widgets/symbol_tree_pane.h
index 564d6547cc..c7b90cfdb8 100644
--- a/eeschema/widgets/symbol_tree_pane.h
+++ b/eeschema/widgets/symbol_tree_pane.h
@@ -53,6 +53,12 @@ protected:
     void onSymbolSelected( wxCommandEvent& aEvent );
     void onUpdateUI( wxUpdateUIEvent& aEvent );
 
+    /**
+     * Handle parent menu events to block preview updates while the menu is open.
+     */
+    void onMenuOpen( wxMenuEvent& aEvent );
+    void onMenuClose( wxMenuEvent& aEvent );
+
     SYMBOL_EDIT_FRAME*          m_symbolEditFrame;
     LIB_TREE*                   m_tree;             ///< symbol search tree widget
     LIB_SYMBOL_LIBRARY_MANAGER* m_libMgr;
diff --git a/include/widgets/lib_tree.h b/include/widgets/lib_tree.h
index cfe008b547..25bbde5556 100644
--- a/include/widgets/lib_tree.h
+++ b/include/widgets/lib_tree.h
@@ -162,6 +162,11 @@ public:
 
     void ShowChangedLanguage();
 
+    void BlockPreview( bool aBlock )
+    {
+        m_previewDisabled = aBlock;
+    }
+
 protected:
     /**
      * Expand or collapse a node, switching it to the opposite state.
diff --git a/pcbnew/footprint_tree_pane.cpp b/pcbnew/footprint_tree_pane.cpp
index 3d361447fc..2058cbc5f1 100644
--- a/pcbnew/footprint_tree_pane.cpp
+++ b/pcbnew/footprint_tree_pane.cpp
@@ -47,6 +47,8 @@ FOOTPRINT_TREE_PANE::FOOTPRINT_TREE_PANE( FOOTPRINT_EDIT_FRAME* aParent )
     // Event handlers
     Bind( EVT_LIBITEM_CHOSEN, &FOOTPRINT_TREE_PANE::onComponentSelected, this );
     m_tree->Bind( wxEVT_UPDATE_UI, &FOOTPRINT_TREE_PANE::onUpdateUI, this );
+    m_frame->Bind( wxEVT_MENU_OPEN, &FOOTPRINT_TREE_PANE::onMenuOpen, this );
+    m_frame->Bind( wxEVT_MENU_CLOSE, &FOOTPRINT_TREE_PANE::onMenuClose, this );
 }
 
 
@@ -61,10 +63,28 @@ void FOOTPRINT_TREE_PANE::FocusSearchFieldIfExists()
 
 FOOTPRINT_TREE_PANE::~FOOTPRINT_TREE_PANE()
 {
+    m_frame->Unbind( wxEVT_MENU_OPEN, &FOOTPRINT_TREE_PANE::onMenuOpen, this );
+    m_frame->Unbind( wxEVT_MENU_CLOSE, &FOOTPRINT_TREE_PANE::onMenuClose, this );
+    m_tree->Unbind( wxEVT_UPDATE_UI, &FOOTPRINT_TREE_PANE::onUpdateUI, this );
+    Unbind( EVT_LIBITEM_CHOSEN, &FOOTPRINT_TREE_PANE::onComponentSelected, this );
     m_tree->Destroy();
 }
 
 
+void FOOTPRINT_TREE_PANE::onMenuOpen( wxMenuEvent& aEvent )
+{
+    m_tree->BlockPreview( true );
+    aEvent.Skip();
+}
+
+
+void FOOTPRINT_TREE_PANE::onMenuClose( wxMenuEvent& aEvent )
+{
+    m_tree->BlockPreview( false );
+    aEvent.Skip();
+}
+
+
 void FOOTPRINT_TREE_PANE::onComponentSelected( wxCommandEvent& aEvent )
 {
     m_frame->LoadFootprintFromLibrary( GetLibTree()->GetSelectedLibId() );
diff --git a/pcbnew/footprint_tree_pane.h b/pcbnew/footprint_tree_pane.h
index 8e79ec25d1..8d63879780 100644
--- a/pcbnew/footprint_tree_pane.h
+++ b/pcbnew/footprint_tree_pane.h
@@ -54,6 +54,13 @@ public:
     void FocusSearchFieldIfExists();
 
 protected:
+
+    /**
+     * Handle parent menu events to block preview updates while the menu is open.
+     */
+    void onMenuOpen( wxMenuEvent& aEvent );
+    void onMenuClose( wxMenuEvent& aEvent );
+
     void onComponentSelected( wxCommandEvent& aEvent );
     void onUpdateUI( wxUpdateUIEvent& aEvent );
 
diff --git a/pcbnew/widgets/panel_footprint_chooser.cpp b/pcbnew/widgets/panel_footprint_chooser.cpp
index 65abf4706a..1800c6b39d 100644
--- a/pcbnew/widgets/panel_footprint_chooser.cpp
+++ b/pcbnew/widgets/panel_footprint_chooser.cpp
@@ -164,6 +164,8 @@ PANEL_FOOTPRINT_CHOOSER::PANEL_FOOTPRINT_CHOOSER( PCB_BASE_FRAME* aFrame, wxTopL
     Bind( wxEVT_TIMER, &PANEL_FOOTPRINT_CHOOSER::onOpenLibsTimer, this, m_open_libs_timer->GetId() );
     Bind( EVT_LIBITEM_SELECTED, &PANEL_FOOTPRINT_CHOOSER::onFootprintSelected, this );
     Bind( EVT_LIBITEM_CHOSEN, &PANEL_FOOTPRINT_CHOOSER::onFootprintChosen, this );
+    m_frame->Bind( wxEVT_MENU_OPEN, &PANEL_FOOTPRINT_CHOOSER::onMenuOpen, this );
+    m_frame->Bind( wxEVT_MENU_CLOSE, &PANEL_FOOTPRINT_CHOOSER::onMenuClose, this );
 
     m_details->Connect( wxEVT_CHAR_HOOK,
                         wxKeyEventHandler( PANEL_FOOTPRINT_CHOOSER::OnDetailsCharHook ),
@@ -211,6 +213,8 @@ PANEL_FOOTPRINT_CHOOSER::PANEL_FOOTPRINT_CHOOSER( PCB_BASE_FRAME* aFrame, wxTopL
 
 PANEL_FOOTPRINT_CHOOSER::~PANEL_FOOTPRINT_CHOOSER()
 {
+    m_frame->Unbind( wxEVT_MENU_OPEN, &PANEL_FOOTPRINT_CHOOSER::onMenuOpen, this );
+    m_frame->Unbind( wxEVT_MENU_CLOSE, &PANEL_FOOTPRINT_CHOOSER::onMenuClose, this );
     Unbind( wxEVT_TIMER, &PANEL_FOOTPRINT_CHOOSER::onCloseTimer, this );
     Unbind( EVT_LIBITEM_SELECTED, &PANEL_FOOTPRINT_CHOOSER::onFootprintSelected, this );
     Unbind( EVT_LIBITEM_CHOSEN, &PANEL_FOOTPRINT_CHOOSER::onFootprintChosen, this );
@@ -252,6 +256,20 @@ PANEL_FOOTPRINT_CHOOSER::~PANEL_FOOTPRINT_CHOOSER()
 }
 
 
+void PANEL_FOOTPRINT_CHOOSER::onMenuOpen( wxMenuEvent& aEvent )
+{
+    m_tree->BlockPreview( true );
+    aEvent.Skip();
+}
+
+
+void PANEL_FOOTPRINT_CHOOSER::onMenuClose( wxMenuEvent& aEvent )
+{
+    m_tree->BlockPreview( false );
+    aEvent.Skip();
+}
+
+
 void PANEL_FOOTPRINT_CHOOSER::FinishSetup()
 {
     if( auto* settings = Pgm().GetSettingsManager().GetAppSettings<PCBNEW_SETTINGS>( "pcbnew" ) )
diff --git a/pcbnew/widgets/panel_footprint_chooser.h b/pcbnew/widgets/panel_footprint_chooser.h
index 2fa6844c6f..882ac26775 100644
--- a/pcbnew/widgets/panel_footprint_chooser.h
+++ b/pcbnew/widgets/panel_footprint_chooser.h
@@ -86,6 +86,12 @@ protected:
     void onCloseTimer( wxTimerEvent& aEvent );
     void onOpenLibsTimer( wxTimerEvent& aEvent );
 
+    /**
+     * Handle parent frame menu events to block tree preview
+     */
+    void onMenuOpen( wxMenuEvent& aEvent );
+    void onMenuClose( wxMenuEvent& aEvent );
+
     void onFootprintSelected( wxCommandEvent& aEvent );
 
     /**