diff --git a/common/eda_draw_frame.cpp b/common/eda_draw_frame.cpp index 944a3fdc27..e61a024718 100644 --- a/common/eda_draw_frame.cpp +++ b/common/eda_draw_frame.cpp @@ -122,45 +122,51 @@ EDA_DRAW_FRAME::EDA_DRAW_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aFrame m_auimgr.SetFlags( wxAUI_MGR_DEFAULT ); - CreateStatusBar( 8 )->SetDoubleBuffered( true ); + if( ( aStyle & wxFRAME_NO_TASKBAR ) == 0 ) + { + CreateStatusBar( 8 )->SetDoubleBuffered( true ); // set the size of the status bar subwindows: - wxWindow* stsbar = GetStatusBar(); - int spacer = KIUI::GetTextSize( wxT( "M" ), stsbar ).x * 2; + wxWindow* stsbar = GetStatusBar(); + int spacer = KIUI::GetTextSize( wxT( "M" ), stsbar ).x * 2; - int dims[] = { + int dims[] = + { + // remainder of status bar on far left is set to a default or whatever is left over. + -1, - // remainder of status bar on far left is set to a default or whatever is left over. - -1, + // When using GetTextSize() remember the width of character '1' is not the same + // as the width of '0' unless the font is fixed width, and it usually won't be. - // When using GetTextSize() remember the width of character '1' is not the same - // as the width of '0' unless the font is fixed width, and it usually won't be. + // zoom: + KIUI::GetTextSize( wxT( "Z 762000" ), stsbar ).x, - // zoom: - KIUI::GetTextSize( wxT( "Z 762000" ), stsbar ).x + spacer, + // cursor coords + KIUI::GetTextSize( wxT( "X 1234.1234 Y 1234.1234" ), stsbar ).x, - // cursor coords - KIUI::GetTextSize( wxT( "X 1234.1234 Y 1234.1234" ), stsbar ).x + spacer, + // delta distances + KIUI::GetTextSize( wxT( "dx 1234.1234 dy 1234.1234 dist 1234.1234" ), stsbar ).x, - // delta distances - KIUI::GetTextSize( wxT( "dx 1234.1234 dy 1234.1234 dist 1234.1234" ), stsbar ).x + spacer, + // grid size + KIUI::GetTextSize( wxT( "grid X 1234.1234 Y 1234.1234" ), stsbar ).x, - // grid size - KIUI::GetTextSize( wxT( "grid X 1234.1234 Y 1234.1234" ), stsbar ).x + spacer, + // units display, Inches is bigger than mm + KIUI::GetTextSize( _( "Inches" ), stsbar ).x, - // units display, Inches is bigger than mm - KIUI::GetTextSize( _( "Inches" ), stsbar ).x + spacer, + // Size for the "Current Tool" panel; longest string from SetTool() + KIUI::GetTextSize( wxT( "Add layer alignment target" ), stsbar ).x, - // Size for the "Current Tool" panel; longest string from SetTool() - KIUI::GetTextSize( wxT( "Add layer alignment target" ), stsbar ).x + spacer, + // constraint mode + KIUI::GetTextSize( _( "Constrain to H, V, 45" ), stsbar ).x + }; - // constraint mode - KIUI::GetTextSize( _( "Constrain to H, V, 45" ), stsbar ).x + spacer - }; + for( size_t ii = 1; ii < arrayDim( dims ); ii++ ) + dims[ii] += spacer; - SetStatusWidths( arrayDim( dims ), dims ); - stsbar->SetFont( KIUI::GetStatusFont( this ) ); + SetStatusWidths( arrayDim( dims ), dims ); + stsbar->SetFont( KIUI::GetStatusFont( this ) ); + } // Create child subwindows. GetClientSize( &m_frameSize.x, &m_frameSize.y ); diff --git a/common/kiway.cpp b/common/kiway.cpp index 494a037f47..019cd23cfe 100644 --- a/common/kiway.cpp +++ b/common/kiway.cpp @@ -381,7 +381,7 @@ KIWAY::FACE_T KIWAY::KifaceType( FRAME_T aFrameType ) case FRAME_PCB_EDITOR: case FRAME_FOOTPRINT_EDITOR: case FRAME_FOOTPRINT_VIEWER: - case FRAME_FOOTPRINT_VIEWER_MODAL: + case FRAME_FOOTPRINT_CHOOSER: case FRAME_FOOTPRINT_WIZARD: case FRAME_PCB_DISPLAY3D: return FACE_PCB; diff --git a/common/tool/common_tools.cpp b/common/tool/common_tools.cpp index 0c33960be7..fc0de94fe4 100644 --- a/common/tool/common_tools.cpp +++ b/common/tool/common_tools.cpp @@ -354,8 +354,9 @@ int COMMON_TOOLS::doZoomFit( ZOOM_FIT_TYPE_T aFitType ) { // Leave a bigger margin for library editors & viewers - if( frame->IsType( FRAME_FOOTPRINT_VIEWER ) || frame->IsType( FRAME_FOOTPRINT_VIEWER_MODAL ) - || frame->IsType( FRAME_SCH_VIEWER ) || frame->IsType( FRAME_SCH_VIEWER_MODAL ) ) + if( frame->IsType( FRAME_FOOTPRINT_VIEWER ) + || frame->IsType( FRAME_SCH_VIEWER ) + || frame->IsType( FRAME_SCH_VIEWER_MODAL ) ) { margin_scale_factor = 1.30; } diff --git a/common/widgets/grid_text_button_helpers.cpp b/common/widgets/grid_text_button_helpers.cpp index aa7af50f6f..0817c19de9 100644 --- a/common/widgets/grid_text_button_helpers.cpp +++ b/common/widgets/grid_text_button_helpers.cpp @@ -267,7 +267,7 @@ protected: if( fpid.IsEmpty() ) fpid = m_preselect; - KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_FOOTPRINT_VIEWER_MODAL, true, m_dlg ); + KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_FOOTPRINT_CHOOSER, true, m_dlg ); if( !m_symbolNetlist.empty() ) { diff --git a/eeschema/dialogs/dialog_field_properties.cpp b/eeschema/dialogs/dialog_field_properties.cpp index e2a368aef0..68f55b7e1e 100644 --- a/eeschema/dialogs/dialog_field_properties.cpp +++ b/eeschema/dialogs/dialog_field_properties.cpp @@ -220,7 +220,7 @@ void DIALOG_FIELD_PROPERTIES::OnTextValueSelectButtonClick( wxCommandEvent& aEve else fpid = m_TextCtrl->GetValue(); - if( KIWAY_PLAYER* frame = Kiway().Player( FRAME_FOOTPRINT_VIEWER_MODAL, true ) ) + if( KIWAY_PLAYER* frame = Kiway().Player( FRAME_FOOTPRINT_CHOOSER, true ) ) { if( frame->ShowModal( &fpid, this ) ) { diff --git a/eeschema/dialogs/dialog_symbol_fields_table.cpp b/eeschema/dialogs/dialog_symbol_fields_table.cpp index 5e6b8f3985..6422088616 100644 --- a/eeschema/dialogs/dialog_symbol_fields_table.cpp +++ b/eeschema/dialogs/dialog_symbol_fields_table.cpp @@ -110,8 +110,7 @@ protected: // pick a footprint using the footprint picker. wxString fpid = m_grid->GetCellValue( m_grid->GetGridCursorRow(), FOOTPRINT_FIELD ); - KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_FOOTPRINT_VIEWER_MODAL, true, - m_dlg ); + KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_FOOTPRINT_CHOOSER, true, m_dlg ); if( frame->ShowModal( &fpid, m_dlg ) ) m_grid->SetCellValue( m_grid->GetGridCursorRow(), FOOTPRINT_FIELD, fpid ); diff --git a/eeschema/fields_grid_table.cpp b/eeschema/fields_grid_table.cpp index ef6b353fe5..955fd80b55 100644 --- a/eeschema/fields_grid_table.cpp +++ b/eeschema/fields_grid_table.cpp @@ -896,7 +896,7 @@ void FIELDS_GRID_TRICKS::doPopupSelection( wxCommandEvent& event ) { // pick a footprint using the footprint picker. wxString fpid = m_grid->GetCellValue( FOOTPRINT_FIELD, FDC_VALUE ); - KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_FOOTPRINT_VIEWER_MODAL, true, m_dlg ); + KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_FOOTPRINT_CHOOSER, true, m_dlg ); if( frame->ShowModal( &fpid, m_dlg ) ) m_grid->SetCellValue( FOOTPRINT_FIELD, FDC_VALUE, fpid ); diff --git a/include/eda_draw_frame.h b/include/eda_draw_frame.h index 284bc9da37..7789b4101f 100644 --- a/include/eda_draw_frame.h +++ b/include/eda_draw_frame.h @@ -56,14 +56,14 @@ namespace KIGFX using KIGFX::COLOR4D; using KIGFX::RENDER_SETTINGS; -#define LIB_EDIT_FRAME_NAME wxT( "LibeditFrame" ) -#define SCH_EDIT_FRAME_NAME wxT( "SchematicFrame" ) -#define PL_EDITOR_FRAME_NAME wxT( "PlEditorFrame" ) -#define FOOTPRINT_WIZARD_FRAME_NAME wxT( "FootprintWizard" ) -#define FOOTPRINT_EDIT_FRAME_NAME wxT( "ModEditFrame" ) -#define FOOTPRINT_VIEWER_FRAME_NAME wxT( "ModViewFrame" ) -#define FOOTPRINT_VIEWER_FRAME_NAME_MODAL wxT( "ModViewFrameModal" ) -#define PCB_EDIT_FRAME_NAME wxT( "PcbFrame" ) +#define LIB_EDIT_FRAME_NAME wxT( "LibeditFrame" ) +#define SCH_EDIT_FRAME_NAME wxT( "SchematicFrame" ) +#define PL_EDITOR_FRAME_NAME wxT( "PlEditorFrame" ) +#define FOOTPRINT_WIZARD_FRAME_NAME wxT( "FootprintWizard" ) +#define FOOTPRINT_CHOOSER_FRAME_NAME wxT( "FootprintChooserFrame" ) +#define FOOTPRINT_EDIT_FRAME_NAME wxT( "ModEditFrame" ) +#define FOOTPRINT_VIEWER_FRAME_NAME wxT( "ModViewFrame" ) +#define PCB_EDIT_FRAME_NAME wxT( "PcbFrame" ) /** diff --git a/include/frame_type.h b/include/frame_type.h index 5a024c8a70..8fb496b44a 100644 --- a/include/frame_type.h +++ b/include/frame_type.h @@ -39,8 +39,8 @@ enum FRAME_T FRAME_PCB_EDITOR, FRAME_FOOTPRINT_EDITOR, + FRAME_FOOTPRINT_CHOOSER, FRAME_FOOTPRINT_VIEWER, - FRAME_FOOTPRINT_VIEWER_MODAL, FRAME_FOOTPRINT_WIZARD, FRAME_PCB_DISPLAY3D, FRAME_FOOTPRINT_PREVIEW, diff --git a/include/pcb_base_frame.h b/include/pcb_base_frame.h index bab79bb7f0..2dea52d8a5 100644 --- a/include/pcb_base_frame.h +++ b/include/pcb_base_frame.h @@ -290,7 +290,7 @@ public: * * @param aPreslect if valid, the #LIB_ID to select (otherwise the global history is used). */ - FOOTPRINT* SelectFootprintFromLibTree( LIB_ID aPreselect = LIB_ID() ); + FOOTPRINT* SelectFootprintFromLibrary( LIB_ID aPreselect = LIB_ID() ); /** * Add the given footprint to the board. @@ -299,13 +299,6 @@ public: */ virtual void AddFootprintToBoard( FOOTPRINT* aFootprint ); - /** - * Launch the footprint viewer to select the name of a footprint to load. - * - * @return the selected footprint name or an empty string if no selection was made. - */ - wxString SelectFootprintFromLibBrowser(); - /** * Create the entire board ratsnest. * diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 51ce6e928a..2b8fedbc72 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -37,7 +37,6 @@ set( PCBNEW_DIALOGS dialogs/dialog_board_statistics_base.cpp dialogs/dialog_board_reannotate.cpp dialogs/dialog_board_reannotate_base.cpp - dialogs/dialog_choose_footprint.cpp dialogs/dialog_cleanup_graphics.cpp dialogs/dialog_cleanup_graphics_base.cpp dialogs/dialog_cleanup_tracks_and_vias.cpp @@ -50,10 +49,11 @@ set( PCBNEW_DIALOGS dialogs/dialog_dimension_properties_base.cpp dialogs/dialog_drc.cpp dialogs/dialog_drc_base.cpp - dialogs/dialog_footprint_checker.cpp - dialogs/dialog_footprint_checker_base.cpp dialogs/dialog_footprint_associations.cpp dialogs/dialog_footprint_associations_base.cpp + dialogs/dialog_footprint_checker.cpp + dialogs/dialog_footprint_checker_base.cpp + dialogs/dialog_footprint_chooser.cpp dialogs/dialog_footprint_properties.cpp dialogs/dialog_footprint_properties_base.cpp dialogs/dialog_footprint_properties_fp_editor.cpp @@ -287,6 +287,7 @@ set( PCBNEW_CLASS_SRCS footprint_editor_utils.cpp footprint_editor_settings.cpp fp_tree_synchronizing_adapter.cpp + footprint_chooser_frame.cpp footprint_edit_frame.cpp footprint_libraries_utils.cpp footprint_viewer_frame.cpp @@ -356,6 +357,7 @@ set( PCBNEW_CLASS_SRCS widgets/appearance_controls.cpp widgets/appearance_controls_base.cpp + widgets/panel_footprint_chooser.cpp widgets/panel_selection_filter.cpp widgets/panel_selection_filter_base.cpp widgets/pcb_properties_panel.cpp diff --git a/pcbnew/dialogs/dialog_choose_footprint.cpp b/pcbnew/dialogs/dialog_choose_footprint.cpp deleted file mode 100644 index 60938c6201..0000000000 --- a/pcbnew/dialogs/dialog_choose_footprint.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2014 Henner Zeller - * Copyright (C) 2016-2021 KiCad Developers, see AUTHORS.txt for contributors. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you may find one here: - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * or you may search the http://www.gnu.org website for the version 2 license, - * or you may write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -DIALOG_CHOOSE_FOOTPRINT::DIALOG_CHOOSE_FOOTPRINT( PCB_BASE_FRAME* aParent, - const wxString& aTitle, - wxObjectDataPtr& aAdapter ) - : DIALOG_SHIM( aParent, wxID_ANY, aTitle, wxDefaultPosition, wxDefaultSize, - wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ), - m_browser_button( nullptr ), - m_hsplitter( nullptr ), - m_vsplitter( nullptr ), - m_parent( aParent ), - m_external_browser_requested( false ) -{ - auto sizer = new wxBoxSizer( wxVERTICAL ); - HTML_WINDOW* details = nullptr; - - m_vsplitter = new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, - wxSP_LIVE_UPDATE ); - - m_hsplitter = new wxSplitterWindow( m_vsplitter, wxID_ANY, wxDefaultPosition, wxDefaultSize, - wxSP_LIVE_UPDATE ); - - //Avoid the splitter window being assigned as the Parent to additional windows - m_hsplitter->SetExtraStyle( wxWS_EX_TRANSIENT ); - - auto detailsPanel = new wxPanel( m_vsplitter ); - auto detailsSizer = new wxBoxSizer( wxVERTICAL ); - detailsPanel->SetSizer( detailsSizer ); - - details = new HTML_WINDOW( detailsPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, - wxHW_SCROLLBAR_AUTO ); - detailsSizer->Add( details, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 5 ); - detailsPanel->Layout(); - detailsSizer->Fit( detailsPanel ); - - m_vsplitter->SetSashGravity( 0.5 ); - m_vsplitter->SetMinimumPaneSize( 20 ); - m_vsplitter->SplitHorizontally( m_hsplitter, detailsPanel ); - - sizer->Add( m_vsplitter, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 5 ); - - m_tree = new LIB_TREE( m_hsplitter, wxT( "footprints" ), Prj().PcbFootprintLibs(), aAdapter, - LIB_TREE::FLAGS::ALL_WIDGETS, details ); - - m_hsplitter->SetSashGravity( 0.8 ); - m_hsplitter->SetMinimumPaneSize( 20 ); - m_hsplitter->SplitVertically( m_tree, ConstructRightPanel( m_hsplitter ) ); - - m_dbl_click_timer = new wxTimer( this ); - - auto buttonsSizer = new wxBoxSizer( wxHORIZONTAL ); - - m_browser_button = new wxButton( this, wxID_ANY, _( "Select with Browser" ) ); - buttonsSizer->Add( m_browser_button, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5 ); - - auto sdbSizer = new wxStdDialogButtonSizer(); - auto okButton = new wxButton( this, wxID_OK ); - auto cancelButton = new wxButton( this, wxID_CANCEL ); - sdbSizer->AddButton( okButton ); - sdbSizer->AddButton( cancelButton ); - sdbSizer->Realize(); - - buttonsSizer->Add( sdbSizer, 1, wxALL, 5 ); - - sizer->Add( buttonsSizer, 0, wxEXPAND | wxLEFT, 5 ); - SetSizer( sizer ); - - aAdapter->FinishTreeInitialization(); - - SetupStandardButtons(); - - Bind( wxEVT_TIMER, &DIALOG_CHOOSE_FOOTPRINT::OnCloseTimer, this, m_dbl_click_timer->GetId() ); - Bind( SYMBOL_PRESELECTED, &DIALOG_CHOOSE_FOOTPRINT::OnComponentPreselected, this ); - Bind( SYMBOL_SELECTED, &DIALOG_CHOOSE_FOOTPRINT::OnComponentSelected, this ); - m_browser_button->Bind( wxEVT_COMMAND_BUTTON_CLICKED, &DIALOG_CHOOSE_FOOTPRINT::OnUseBrowser, - this ); - - Layout(); - - if( PCBNEW_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings() ) - { - // We specify the width of the right window (m_symbol_view_panel), because specify - // the width of the left window does not work as expected when SetSashGravity() is called - if( cfg->m_FootprintChooser.sash_h < 0 ) - cfg->m_FootprintChooser.sash_h = horizPixelsFromDU( 220 ); - - m_hsplitter->SetSashPosition( cfg->m_FootprintChooser.sash_h ); - - if( cfg->m_FootprintChooser.sash_v < 0 ) - cfg->m_FootprintChooser.sash_v = horizPixelsFromDU( 230 ); - - if( m_vsplitter ) - m_vsplitter->SetSashPosition( cfg->m_FootprintChooser.sash_v ); - - int w = cfg->m_FootprintChooser.width < 0 ? - horizPixelsFromDU( 440 ) : cfg->m_FootprintChooser.width; - int h = cfg->m_FootprintChooser.height < 0 ? - horizPixelsFromDU( 340 ) : cfg->m_FootprintChooser.height; - SetSize( wxSize( w, h ) ); - - aAdapter->SetSortMode( (LIB_TREE_MODEL_ADAPTER::SORT_MODE) cfg->m_FootprintChooser.sort_mode ); - } - - SetInitialFocus( m_tree->GetFocusTarget() ); -} - - -DIALOG_CHOOSE_FOOTPRINT::~DIALOG_CHOOSE_FOOTPRINT() -{ - Unbind( wxEVT_TIMER, &DIALOG_CHOOSE_FOOTPRINT::OnCloseTimer, this ); - Unbind( SYMBOL_PRESELECTED, &DIALOG_CHOOSE_FOOTPRINT::OnComponentPreselected, this ); - Unbind( SYMBOL_SELECTED, &DIALOG_CHOOSE_FOOTPRINT::OnComponentSelected, this ); - m_browser_button->Unbind( wxEVT_COMMAND_BUTTON_CLICKED, - &DIALOG_CHOOSE_FOOTPRINT::OnUseBrowser, this ); - - // I am not sure the following two lines are necessary, - // but they will not hurt anyone - m_dbl_click_timer->Stop(); - delete m_dbl_click_timer; - - if( PCBNEW_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings() ) - { - cfg->m_FootprintChooser.width = GetSize().x; - cfg->m_FootprintChooser.height = GetSize().y; - cfg->m_FootprintChooser.sash_h = m_hsplitter->GetSashPosition(); - - if( m_vsplitter ) - cfg->m_FootprintChooser.sash_v = m_vsplitter->GetSashPosition(); - - cfg->m_FootprintChooser.sort_mode = m_tree->GetSortMode(); - } -} - - -wxPanel* DIALOG_CHOOSE_FOOTPRINT::ConstructRightPanel( wxWindow* aParent ) -{ - auto panel = new wxPanel( aParent ); - auto sizer = new wxBoxSizer( wxVERTICAL ); - - m_preview_ctrl = new FOOTPRINT_PREVIEW_WIDGET( panel, Kiway() ); - m_preview_ctrl->SetUserUnits( GetUserUnits() ); - sizer->Add( m_preview_ctrl, 1, wxEXPAND | wxTOP | wxRIGHT, 5 ); - - panel->SetSizer( sizer ); - panel->Layout(); - sizer->Fit( panel ); - - return panel; -} - - -LIB_ID DIALOG_CHOOSE_FOOTPRINT::GetSelectedLibId() const -{ - return m_tree->GetSelectedLibId(); -} - - -void DIALOG_CHOOSE_FOOTPRINT::OnUseBrowser( wxCommandEvent& aEvent ) -{ - m_external_browser_requested = true; - EndQuasiModal( wxID_OK ); -} - - -void DIALOG_CHOOSE_FOOTPRINT::OnCloseTimer( wxTimerEvent& aEvent ) -{ - // Hack handler because of eaten MouseUp event. See - // DIALOG_CHOOSE_FOOTPRINT::OnComponentSelected for the beginning - // of this spaghetti noodle. - - auto state = wxGetMouseState(); - - if( state.LeftIsDown() ) - { - // Mouse hasn't been raised yet, so fire the timer again. Otherwise the - // purpose of this timer is defeated. - m_dbl_click_timer->StartOnce( DIALOG_CHOOSE_FOOTPRINT::DblClickDelay ); - } - else - { - EndQuasiModal( wxID_OK ); - } -} - - -void DIALOG_CHOOSE_FOOTPRINT::OnComponentPreselected( wxCommandEvent& aEvent ) -{ - if( !m_preview_ctrl || !m_preview_ctrl->IsInitialized() ) - return; - - LIB_ID lib_id = m_tree->GetSelectedLibId(); - - if( !lib_id.IsValid() ) - { - m_preview_ctrl->SetStatusText( _( "No footprint selected" ) ); - } - else - { - m_preview_ctrl->ClearStatus(); - m_preview_ctrl->DisplayFootprint( lib_id ); - } -} - - -void DIALOG_CHOOSE_FOOTPRINT::OnComponentSelected( wxCommandEvent& aEvent ) -{ - if( m_tree->GetSelectedLibId().IsValid() ) - { - // Got a selection. We can't just end the modal dialog here, because - // wx leaks some events back to the parent window (in particular, the - // MouseUp following a double click). - // - // NOW, here's where it gets really fun. wxTreeListCtrl eats MouseUp. - // This isn't really feasible to bypass without a fully custom - // wxDataViewCtrl implementation, and even then might not be fully - // possible (docs are vague). To get around this, we use a one-shot - // timer to schedule the dialog close. - // - // See DIALOG_CHOOSE_FOOTPRINT::OnCloseTimer for the other end of this - // spaghetti noodle. - m_dbl_click_timer->StartOnce( DIALOG_CHOOSE_FOOTPRINT::DblClickDelay ); - } -} diff --git a/pcbnew/dialogs/dialog_choose_footprint.h b/pcbnew/dialogs/dialog_choose_footprint.h deleted file mode 100644 index f8ed320c5e..0000000000 --- a/pcbnew/dialogs/dialog_choose_footprint.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2014 Henner Zeller - * Copyright (C) 2014-2018 KiCad Developers, see AUTHORS.txt for contributors. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you may find one here: - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * or you may search the http://www.gnu.org website for the version 2 license, - * or you may write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ -#ifndef DIALOG_CHOOSE_FOOTPRINT_H -#define DIALOG_CHOOSE_FOOTPRINT_H - -#include "dialog_shim.h" -#include -#include -#include - -class wxStaticBitmap; -class wxTextCtrl; -class wxStdDialogButtonSizer; -class wxDataViewCtrl; -class wxHtmlLinkEvent; -class wxPanel; -class wxChoice; -class wxButton; -class wxTimer; -class wxSplitterWindow; - -class PCB_BASE_FRAME; -class LIB_TREE; -class FOOTPRINT; - - -/** - * Dialog class to select a footprint from the libraries. This is the master - * View class in a Model-View-Adapter (mediated MVC) architecture. The other - * pieces are in: - * - * - Adapter: CMP_TREE_MODEL_ADAPTER in common/cmp_tree_model_adapter.h - * - Model: CMP_TREE_NODE and descendants in common/cmp_tree_model.h - * - * Because everything is tied together in the adapter class, see that file - * for thorough documentation. A simple example usage follows: - * - * // Create the adapter class - * auto adapter( FP_TREE_MODEL_ADAPTER::Create( Prj().PcbFootprintLibs() ) ); - * - * // Perform any configuration of adapter properties here - * adapter->SetPreselectNode( "LIB_NICKNAME", "FP_NAME", 2 ); - * - * // Initialize model from #FP_LIB_TABLE - * libNicknames = libs->GetLogicalLibs(); - * - * for( auto nickname : libNicknames ) - * { - * adapter->AddLibrary( nickname ); - * } - * - * // Create and display dialog - * DIALOG_CHOOSE_FOOTPRINT dlg( this, title, adapter, 1 ); - * bool selected = ( dlg.ShowModal() != wxID_CANCEL ); - * - * // Receive part - * if( selected ) - * { - * int unit; - * #LIB_ID id = dlg.GetSelectedAlias( &unit ); - * do_something( id, unit ); - * } - * - */ -class DIALOG_CHOOSE_FOOTPRINT : public DIALOG_SHIM -{ -public: - /** - * Create dialog to choose component. - * - * @param aParent a PCB_BASE_FRAME parent window. - * @param aAdapter FP_TREE_MODEL_ADAPTER::PTR. See CMP_TREE_MODEL_ADAPTER - * for documentation. - */ - DIALOG_CHOOSE_FOOTPRINT( PCB_BASE_FRAME* aParent, const wxString& aTitle, - wxObjectDataPtr& aAdapter ); - - ~DIALOG_CHOOSE_FOOTPRINT(); - - /** - * To be called after this dialog returns from ShowModal(). - * - * @return the #LIB_ID of the symbol that has been selected. - */ - LIB_ID GetSelectedLibId() const; - - /** Function IsExternalBrowserSelected - * - * @return true, iff the user pressed the thumbnail view of the component to - * launch the component browser. - */ - bool IsExternalBrowserSelected() const - { - return m_external_browser_requested; - } - -protected: - static constexpr int DblClickDelay = 100; // milliseconds - - wxPanel* ConstructRightPanel( wxWindow* aParent ); - - void OnCloseTimer( wxTimerEvent& aEvent ); - void OnUseBrowser( wxCommandEvent& aEvent ); - - void OnComponentPreselected( wxCommandEvent& 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. - * If the item selected is a category, it is expanded or collapsed; if it - * is a component, the component is picked. - */ - void OnComponentSelected( wxCommandEvent& aEvent ); - - wxTimer* m_dbl_click_timer; - wxButton* m_browser_button; - wxSplitterWindow* m_hsplitter; - wxSplitterWindow* m_vsplitter; - - FOOTPRINT_PREVIEW_WIDGET* m_preview_ctrl; - LIB_TREE* m_tree; - - PCB_BASE_FRAME* m_parent; - bool m_external_browser_requested; -}; - -#endif /* DIALOG_CHOOSE_FOOTPRINT_H */ diff --git a/pcbnew/dialogs/dialog_exchange_footprints.cpp b/pcbnew/dialogs/dialog_exchange_footprints.cpp index 400e2c0c33..000eb52cf0 100644 --- a/pcbnew/dialogs/dialog_exchange_footprints.cpp +++ b/pcbnew/dialogs/dialog_exchange_footprints.cpp @@ -394,8 +394,6 @@ void DIALOG_EXCHANGE_FOOTPRINTS::processFootprint( FOOTPRINT* aFootprint, const msg += _( ": OK" ); m_MessageWindow->Report( msg, RPT_SEVERITY_ACTION ); } - - return; } @@ -403,7 +401,7 @@ void DIALOG_EXCHANGE_FOOTPRINTS::ViewAndSelectFootprint( wxCommandEvent& event ) { wxString newname = m_newID->GetValue(); - KIWAY_PLAYER* frame = Kiway().Player( FRAME_FOOTPRINT_VIEWER_MODAL, true ); + KIWAY_PLAYER* frame = Kiway().Player( FRAME_FOOTPRINT_CHOOSER, true ); if( frame->ShowModal( &newname, this ) ) { diff --git a/pcbnew/dialogs/dialog_footprint_chooser.cpp b/pcbnew/dialogs/dialog_footprint_chooser.cpp new file mode 100644 index 0000000000..113229bffb --- /dev/null +++ b/pcbnew/dialogs/dialog_footprint_chooser.cpp @@ -0,0 +1,73 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include + + +DIALOG_FOOTPRINT_CHOOSER::DIALOG_FOOTPRINT_CHOOSER( PCB_BASE_FRAME* aParent, + const LIB_ID& aPreselect, + const wxArrayString& aFootprintHistoryList ) : + DIALOG_SHIM( aParent, wxID_ANY, _( "Choose Footprint" ), wxDefaultPosition, wxDefaultSize, + wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ) +{ + wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL ); + m_chooserPanel = new PANEL_FOOTPRINT_CHOOSER( aParent, this, aFootprintHistoryList, + [this]() + { + EndQuasiModal( wxID_OK ); + } ); + + sizer->Add( m_chooserPanel, 1, wxEXPAND, 5 ); + + if( aPreselect.IsValid() ) + m_chooserPanel->SetPreselect( aPreselect ); + + SetTitle( GetTitle() + wxString::Format( _( " (%d items loaded)" ), + m_chooserPanel->GetItemCount() ) ); + + wxStdDialogButtonSizer* sdbSizer = new wxStdDialogButtonSizer(); + wxButton* okButton = new wxButton( this, wxID_OK ); + wxButton* cancelButton = new wxButton( this, wxID_CANCEL ); + sdbSizer->AddButton( okButton ); + sdbSizer->AddButton( cancelButton ); + sdbSizer->Realize(); + + sizer->Add( sdbSizer, 0, wxEXPAND | wxALL, 5 ); + SetSizer( sizer ); + + SetInitialFocus( m_chooserPanel->GetFocusTarget() ); + SetupStandardButtons(); + + m_chooserPanel->FinishSetup(); + Layout(); +} + + +LIB_ID DIALOG_FOOTPRINT_CHOOSER::GetSelectedLibId() const +{ + return m_chooserPanel->GetSelectedLibId(); +} diff --git a/pcbnew/dialogs/dialog_footprint_chooser.h b/pcbnew/dialogs/dialog_footprint_chooser.h new file mode 100644 index 0000000000..d2f305c751 --- /dev/null +++ b/pcbnew/dialogs/dialog_footprint_chooser.h @@ -0,0 +1,53 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef DIALOG_FOOTPRINT_CHOOSER_H +#define DIALOG_FOOTPRINT_CHOOSER_H + +#include +#include "dialog_shim.h" + + +class PCB_BASE_FRAME; +class PANEL_FOOTPRINT_CHOOSER; + + +class DIALOG_FOOTPRINT_CHOOSER : public DIALOG_SHIM +{ +public: + DIALOG_FOOTPRINT_CHOOSER( PCB_BASE_FRAME* aParent, const LIB_ID& aPreselect, + const wxArrayString& aFootprintHistoryList ); + + ~DIALOG_FOOTPRINT_CHOOSER() {}; + + /** + * To be called after this dialog returns from ShowModal(). + * + * @return the #LIB_ID of the symbol that has been selected. + */ + LIB_ID GetSelectedLibId() const; + +protected: + PANEL_FOOTPRINT_CHOOSER* m_chooserPanel; +}; + +#endif /* DIALOG_FOOTPRINT_CHOOSER_H */ diff --git a/pcbnew/footprint.cpp b/pcbnew/footprint.cpp index e8e0f9403d..2989bb82cf 100644 --- a/pcbnew/footprint.cpp +++ b/pcbnew/footprint.cpp @@ -1244,7 +1244,7 @@ void FOOTPRINT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vectorIsType( FRAME_FOOTPRINT_VIEWER ) - || aFrame->IsType( FRAME_FOOTPRINT_VIEWER_MODAL ) + || aFrame->IsType( FRAME_FOOTPRINT_CHOOSER ) || aFrame->IsType( FRAME_FOOTPRINT_EDITOR ) ) { size_t padCount = GetPadCount( DO_NOT_INCLUDE_NPTH ); diff --git a/pcbnew/footprint_chooser_frame.cpp b/pcbnew/footprint_chooser_frame.cpp new file mode 100644 index 0000000000..a6c790174b --- /dev/null +++ b/pcbnew/footprint_chooser_frame.cpp @@ -0,0 +1,239 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static wxArrayString s_FootprintHistoryList; +static unsigned s_FootprintHistoryMaxCount = 8; + +static void AddFootprintToHistory( const wxString& aName ) +{ + // Remove duplicates + for( int ii = s_FootprintHistoryList.GetCount() - 1; ii >= 0; --ii ) + { + if( s_FootprintHistoryList[ ii ] == aName ) + s_FootprintHistoryList.RemoveAt((size_t) ii ); + } + + // Add the new name at the beginning of the history list + s_FootprintHistoryList.Insert( aName, 0 ); + + // Remove extra names + while( s_FootprintHistoryList.GetCount() >= s_FootprintHistoryMaxCount ) + s_FootprintHistoryList.RemoveAt( s_FootprintHistoryList.GetCount() - 1 ); +} + + +BEGIN_EVENT_TABLE( FOOTPRINT_CHOOSER_FRAME, PCB_BASE_FRAME ) + EVT_MENU( wxID_CLOSE, FOOTPRINT_CHOOSER_FRAME::CloseFootprintChooser ) + EVT_BUTTON( wxID_OK, FOOTPRINT_CHOOSER_FRAME::OnOK ) + EVT_BUTTON( wxID_CANCEL, FOOTPRINT_CHOOSER_FRAME::CloseFootprintChooser ) + EVT_PAINT( FOOTPRINT_CHOOSER_FRAME::OnPaint ) +END_EVENT_TABLE() + + +#define PARENT_STYLE ( wxRESIZE_BORDER | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX | wxCLIP_CHILDREN \ + | wxWANTS_CHARS | wxFRAME_NO_TASKBAR | wxFRAME_FLOAT_ON_PARENT ) +#define MODAL_STYLE ( wxRESIZE_BORDER | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX | wxCLIP_CHILDREN \ + | wxWANTS_CHARS | wxFRAME_NO_TASKBAR | wxSTAY_ON_TOP ) + + +FOOTPRINT_CHOOSER_FRAME::FOOTPRINT_CHOOSER_FRAME( KIWAY* aKiway, wxWindow* aParent ) : + PCB_BASE_FRAME( aKiway, aParent, FRAME_FOOTPRINT_CHOOSER, _( "Footprint Chooser" ), + wxDefaultPosition, wxDefaultSize, aParent ? PARENT_STYLE : MODAL_STYLE, + FOOTPRINT_CHOOSER_FRAME_NAME ), + m_comp( LIB_ID(), wxEmptyString, wxEmptyString, KIID_PATH(), {} ) +{ + SetModal( true ); + + wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL ); + m_chooserPanel = new PANEL_FOOTPRINT_CHOOSER( this, this, s_FootprintHistoryList, + [this]() + { + wxCommandEvent dummy; + OnOK( dummy ); + } ); + + sizer->Add( m_chooserPanel, 1, wxEXPAND, 5 ); + + wxStdDialogButtonSizer* sdbSizer = new wxStdDialogButtonSizer(); + wxButton* okButton = new wxButton( this, wxID_OK ); + wxButton* cancelButton = new wxButton( this, wxID_CANCEL ); + sdbSizer->AddButton( okButton ); + sdbSizer->AddButton( cancelButton ); + sdbSizer->Realize(); + + sizer->Add( sdbSizer, 0, wxEXPAND | wxALL, 5 ); + SetSizer( sizer ); + + SetTitle( GetTitle() + wxString::Format( _( " (%d items loaded)" ), + m_chooserPanel->GetItemCount() ) ); + + Layout(); + m_chooserPanel->FinishSetup(); +} + + +void FOOTPRINT_CHOOSER_FRAME::doCloseWindow() +{ + // Only dismiss a modal frame once, so that the return values set by + // the prior DismissModal() are not bashed for ShowModal(). + if( !IsDismissed() ) + DismissModal( false ); + + // window to be destroyed by the caller of KIWAY_PLAYER::ShowModal() +} + + +WINDOW_SETTINGS* FOOTPRINT_CHOOSER_FRAME::GetWindowSettings( APP_SETTINGS_BASE* aCfg ) +{ + PCBNEW_SETTINGS* cfg = dynamic_cast( aCfg ); + wxCHECK_MSG( cfg, nullptr, wxT( "config not existing" ) ); + + return &cfg->m_FootprintViewer; +} + + +COLOR_SETTINGS* FOOTPRINT_CHOOSER_FRAME::GetColorSettings( bool aForceRefresh ) const +{ + auto* settings = Pgm().GetSettingsManager().GetAppSettings(); + + if( settings ) + return Pgm().GetSettingsManager().GetColorSettings( settings->m_ColorTheme ); + else + return Pgm().GetSettingsManager().GetColorSettings(); +} + + +void FOOTPRINT_CHOOSER_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail ) +{ + // JEY TODO: don't delete this just yet. We can use it to pass in symbol info so that we + // can filter on footprint filters, symbol pin count, etc. + + const std::string& payload = mail.GetPayload(); + + switch( mail.Command() ) + { + case MAIL_SYMBOL_NETLIST: + { + /* + * Symbol netlist format: + * library:footprint + * reference + * value + * pinName,netName,pinFunction,pinType + * pinName,netName,pinFunction,pinType + * ... + */ + std::vector strings = split( payload, "\r" ); + LIB_ID libid; + + if( strings.size() >= 3 ) + { + libid.Parse( strings[0] ); + + m_comp.SetFPID( libid ); + m_comp.SetReference( strings[1] ); + m_comp.SetValue( strings[2] ); + + m_comp.ClearNets(); + + for( size_t ii = 3; ii < strings.size(); ++ii ) + { + std::vector pinData = split( strings[ii], "," ); + m_comp.AddNet( pinData[0], pinData[1], pinData[2], pinData[3] ); + } + } + + break; + } + + default: + break; + } +} + + +bool FOOTPRINT_CHOOSER_FRAME::ShowModal( wxString* aFootprint, wxWindow* aParent ) +{ + if( aFootprint && !aFootprint->IsEmpty() ) + { + LIB_ID fpid; + + fpid.Parse( *aFootprint, true ); + + if( fpid.IsValid() ) + m_chooserPanel->SetPreselect( fpid ); + } + + return KIWAY_PLAYER::ShowModal( aFootprint, aParent ); +} + + +void FOOTPRINT_CHOOSER_FRAME::OnPaint( wxPaintEvent& aEvent ) +{ + if( m_firstPaintEvent ) + { + KIPLATFORM::UI::FixupCancelButtonCmdKeyCollision( this ); + KIPLATFORM::UI::ForceFocus( m_chooserPanel->GetFocusTarget() ); + + m_firstPaintEvent = false; + } + + aEvent.Skip(); +} + + +void FOOTPRINT_CHOOSER_FRAME::OnOK( wxCommandEvent& aEvent ) +{ + LIB_ID fpID = m_chooserPanel->GetSelectedLibId(); + + if( fpID.IsValid() ) + { + wxString footprint = fpID.Format(); + + AddFootprintToHistory( footprint ); + DismissModal( true, footprint ); + } + else + { + DismissModal( false ); + } +} + + +void FOOTPRINT_CHOOSER_FRAME::CloseFootprintChooser( wxCommandEvent& aEvent ) +{ + Close( false ); +} + + diff --git a/pcbnew/footprint_chooser_frame.h b/pcbnew/footprint_chooser_frame.h new file mode 100644 index 0000000000..c6ad94d320 --- /dev/null +++ b/pcbnew/footprint_chooser_frame.h @@ -0,0 +1,90 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef FOOTPRINT_CHOOSER_FRAME_H +#define FOOTPRINT_CHOOSER_FRAME_H + + +#include +#include +#include +#include + +class PANEL_FOOTPRINT_CHOOSER; + +namespace PCB { struct IFACE; } + + +class FOOTPRINT_CHOOSER_FRAME : public PCB_BASE_FRAME +{ +public: + ~FOOTPRINT_CHOOSER_FRAME() {}; + + ///< @copydoc PCB_BASE_FRAME::GetModel() + BOARD_ITEM_CONTAINER* GetModel() const override { return nullptr; } + + /** + * @param aFootprint an optional FPID string to initialize the viewer with and to + * return a selected footprint through. + */ + bool ShowModal( wxString* aFootprint, wxWindow* aParent ) override; + + void KiwayMailIn( KIWAY_EXPRESS& mail ) override; + +protected: + FOOTPRINT_CHOOSER_FRAME( KIWAY* aKiway, wxWindow* aParent ); + + void doReCreateMenuBar() override {} + +private: + void OnPaint( wxPaintEvent& aEvent ); + void OnOK( wxCommandEvent& aEvent ); + + void doCloseWindow() override; + void CloseFootprintChooser( wxCommandEvent& aEvent ); + + WINDOW_SETTINGS* GetWindowSettings( APP_SETTINGS_BASE* aCfg ) override; + COLOR_SETTINGS* GetColorSettings( bool aForceRefresh ) const override; + + // Required pure-virtual methods + void ReCreateHToolbar() override {}; + void ReCreateVToolbar() override {}; + void SaveCopyInUndoList( EDA_ITEM*, UNDO_REDO ) override {} + void SaveCopyInUndoList( const PICKED_ITEMS_LIST&, UNDO_REDO ) override {} + void AppendCopyToUndoList( const PICKED_ITEMS_LIST&, UNDO_REDO ) override {} + + DECLARE_EVENT_TABLE() + + friend struct PCB::IFACE; // constructor called from here only + +private: + PANEL_FOOTPRINT_CHOOSER* m_chooserPanel; + COMPONENT m_comp; + + // On MacOS (at least) SetFocus() calls made in the constructor will fail because a + // window that isn't yet visible will return false to AcceptsFocus(). So we must delay + // the initial-focus SetFocus() call to the first paint event. + bool m_firstPaintEvent; +}; + +#endif // FOOTPRINT_CHOOSER_FRAME_H diff --git a/pcbnew/footprint_viewer_frame.cpp b/pcbnew/footprint_viewer_frame.cpp index 917320c83a..c5dfdf5468 100644 --- a/pcbnew/footprint_viewer_frame.cpp +++ b/pcbnew/footprint_viewer_frame.cpp @@ -106,29 +106,12 @@ BEGIN_EVENT_TABLE( FOOTPRINT_VIEWER_FRAME, PCB_BASE_FRAME ) END_EVENT_TABLE() -/* - * Note: FOOTPRINT_VIEWER_FRAME can be created in "modal mode", or as a usual frame. - */ -#define PARENT_STYLE ( KICAD_DEFAULT_DRAWFRAME_STYLE | wxFRAME_FLOAT_ON_PARENT ) -#define MODAL_STYLE ( KICAD_DEFAULT_DRAWFRAME_STYLE | wxSTAY_ON_TOP ) -#define NONMODAL_STYLE ( KICAD_DEFAULT_DRAWFRAME_STYLE ) - - -FOOTPRINT_VIEWER_FRAME::FOOTPRINT_VIEWER_FRAME( KIWAY* aKiway, wxWindow* aParent, - FRAME_T aFrameType ) : - PCB_BASE_FRAME( aKiway, aParent, aFrameType, _( "Footprint Library Browser" ), - wxDefaultPosition, wxDefaultSize, - aFrameType == FRAME_FOOTPRINT_VIEWER_MODAL ? ( aParent ? PARENT_STYLE : MODAL_STYLE ) - : NONMODAL_STYLE, - aFrameType == FRAME_FOOTPRINT_VIEWER_MODAL ? FOOTPRINT_VIEWER_FRAME_NAME_MODAL - : FOOTPRINT_VIEWER_FRAME_NAME ), +FOOTPRINT_VIEWER_FRAME::FOOTPRINT_VIEWER_FRAME( KIWAY* aKiway, wxWindow* aParent ) : + PCB_BASE_FRAME( aKiway, aParent, FRAME_FOOTPRINT_VIEWER, _( "Footprint Library Browser" ), + wxDefaultPosition, wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE, + FOOTPRINT_VIEWER_FRAME_NAME ), m_comp( LIB_ID(), wxEmptyString, wxEmptyString, KIID_PATH(), {} ) { - wxASSERT( aFrameType == FRAME_FOOTPRINT_VIEWER_MODAL || aFrameType == FRAME_FOOTPRINT_VIEWER ); - - if( aFrameType == FRAME_FOOTPRINT_VIEWER_MODAL ) - SetModal( true ); - m_aboutTitle = _HKI( "KiCad Footprint Library Viewer" ); // Force the items to always snap @@ -1067,13 +1050,13 @@ bool FOOTPRINT_VIEWER_FRAME::ShowModal( wxString* aFootprint, wxWindow* aParent if( WX_INFOBAR* infobar = GetInfoBar() ) { button = new wxHyperlinkCtrl( infobar, wxID_ANY, - _( "Manage symbol libraries" ), - wxEmptyString ); - button->Bind( wxEVT_COMMAND_HYPERLINK, std::function( - [=]( wxHyperlinkEvent& aEvent ) - { - InvokePcbLibTableEditor( &Kiway(), this ); - } ) ); + _( "Manage footprint libraries" ), + wxEmptyString ); + button->Bind( wxEVT_COMMAND_HYPERLINK, + [=]( wxHyperlinkEvent& aEvent ) + { + InvokePcbLibTableEditor( &Kiway(), this ); + } ); } } diff --git a/pcbnew/footprint_viewer_frame.h b/pcbnew/footprint_viewer_frame.h index 1c44402265..e0fced8875 100644 --- a/pcbnew/footprint_viewer_frame.h +++ b/pcbnew/footprint_viewer_frame.h @@ -94,7 +94,7 @@ public: void KiwayMailIn( KIWAY_EXPRESS& mail ) override; protected: - FOOTPRINT_VIEWER_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aFrameType ); + FOOTPRINT_VIEWER_FRAME( KIWAY* aKiway, wxWindow* aParent ); MAGNETIC_SETTINGS m_magneticItems; diff --git a/pcbnew/load_select_footprint.cpp b/pcbnew/load_select_footprint.cpp index eee1bfeaae..1dbdc71273 100644 --- a/pcbnew/load_select_footprint.cpp +++ b/pcbnew/load_select_footprint.cpp @@ -30,15 +30,13 @@ using namespace std::placeholders; #include #include #include -#include +#include #include #include #include -#include #include #include #include -#include #include #include #include @@ -52,8 +50,6 @@ using namespace std::placeholders; #include #include -#include "fp_tree_model_adapter.h" - static wxArrayString s_FootprintHistoryList; static unsigned s_FootprintHistoryMaxCount = 8; @@ -181,120 +177,25 @@ bool FOOTPRINT_EDIT_FRAME::LoadFootprintFromBoard( FOOTPRINT* aFootprint ) } -wxString PCB_BASE_FRAME::SelectFootprintFromLibBrowser() +FOOTPRINT* PCB_BASE_FRAME::SelectFootprintFromLibrary( LIB_ID aPreselect ) { - // Close the current non-modal Lib browser if opened, and open a new one, in "modal" mode: - FOOTPRINT_VIEWER_FRAME* viewer; - viewer = (FOOTPRINT_VIEWER_FRAME*) Kiway().Player( FRAME_FOOTPRINT_VIEWER, false ); - - if( viewer ) - { - viewer->Destroy(); - // Destroy() does not immediately delete the viewer, if some events are pending. - // (for this reason delete operator cannot be used blindly with "top level" windows) - // so gives a slice of time to delete the viewer frame. - // This is especially important in OpenGL mode to avoid recreating context before - // the old one is deleted. - wxSafeYield(); - } - - SetFocus(); - - // Creates the modal Lib browser: - viewer = (FOOTPRINT_VIEWER_FRAME*) Kiway().Player( FRAME_FOOTPRINT_VIEWER_MODAL, true, this ); - - wxString fpid; - ignore_unused( viewer->ShowModal( &fpid, this ) ); - - viewer->Destroy(); - - return fpid; -} - - -FOOTPRINT* PCB_BASE_FRAME::SelectFootprintFromLibTree( LIB_ID aPreselect ) -{ - FP_LIB_TABLE* fpTable = Prj().PcbFootprintLibs(); wxString footprintName; LIB_ID fpid; FOOTPRINT* footprint = nullptr; static wxString lastComponentName; - // Load footprint files: - WX_PROGRESS_REPORTER* progressReporter = new WX_PROGRESS_REPORTER( this, - _( "Loading Footprint Libraries" ), 3 ); - GFootprintList.ReadFootprintFiles( fpTable, nullptr, progressReporter ); - bool cancel = progressReporter->WasCancelled(); - - // Force immediate deletion of the WX_PROGRESS_REPORTER. Do not use Destroy(), or use - // Destroy() followed by wxSafeYield() because on Windows, APP_PROGRESS_DIALOG and - // WX_PROGRESS_REPORTER have some side effects on the event loop manager. For instance, a - // subsequent call to ShowModal() or ShowQuasiModal() for a dialog following the use of a - // WX_PROGRESS_REPORTER results in incorrect modal or quasi modal behavior. - delete progressReporter; - - if( cancel ) - return nullptr; - - if( GFootprintList.GetErrorCount() ) - GFootprintList.DisplayErrors( this ); - - wxObjectDataPtr ptr = FP_TREE_MODEL_ADAPTER::Create( this, fpTable ); - FP_TREE_MODEL_ADAPTER* adapter = static_cast( ptr.get() ); - - std::vector historyInfos; - - for( const wxString& item : s_FootprintHistoryList ) - { - LIB_TREE_ITEM* fp_info = GFootprintList.GetFootprintInfo( item ); - - // this can be null, for example, if the footprint has been deleted from a library. - if( fp_info != nullptr ) - historyInfos.push_back( fp_info ); - } - - adapter->DoAddLibrary( wxT( "-- " ) + _( "Recently Used" ) + wxT( " --" ), wxEmptyString, - historyInfos, false, true ); - - if( aPreselect.IsValid() ) - adapter->SetPreselectNode( aPreselect, 0 ); - else if( historyInfos.size() ) - adapter->SetPreselectNode( historyInfos[0]->GetLibId(), 0 ); - - adapter->AddLibraries( this ); - - wxString title; - title.Printf( _( "Choose Footprint (%d items loaded)" ), adapter->GetItemCount() ); - - DIALOG_CHOOSE_FOOTPRINT dialog( this, title, ptr ); + DIALOG_FOOTPRINT_CHOOSER dialog( this, aPreselect, s_FootprintHistoryList ); if( dialog.ShowQuasiModal() == wxID_CANCEL ) return nullptr; - // Save any changes to column widths, etc. - adapter->SaveSettings(); + fpid = dialog.GetSelectedLibId(); - if( dialog.IsExternalBrowserSelected() ) - { - // SelectFootprintFromLibBrowser() returns the "full" footprint name, i.e. - // / or LIB_ID format "lib_name:fp_name:rev#" - footprintName = SelectFootprintFromLibBrowser(); - - if( footprintName.IsEmpty() ) // Cancel command - return nullptr; - else - fpid.Parse( footprintName ); - } + if( !fpid.IsValid() ) + return nullptr; else - { - fpid = dialog.GetSelectedLibId(); - - if( !fpid.IsValid() ) - return nullptr; - else - footprintName = fpid.Format().wx_str(); - } + footprintName = fpid.Format().wx_str(); try { diff --git a/pcbnew/pcb_base_frame.cpp b/pcbnew/pcb_base_frame.cpp index 65d1a927c7..5e0e239164 100644 --- a/pcbnew/pcb_base_frame.cpp +++ b/pcbnew/pcb_base_frame.cpp @@ -92,7 +92,8 @@ PCB_BASE_FRAME::~PCB_BASE_FRAME() m_spaceMouse = nullptr; // Ensure m_canvasType is up to date, to save it in config - m_canvasType = GetCanvas()->GetBackend(); + if( GetCanvas() ) + m_canvasType = GetCanvas()->GetBackend(); delete m_pcb; m_pcb = nullptr; @@ -992,7 +993,7 @@ PCB_VIEWERS_SETTINGS_BASE* PCB_BASE_FRAME::GetViewerSettingsBase() const return Pgm().GetSettingsManager().GetAppSettings(); case FRAME_FOOTPRINT_VIEWER: - case FRAME_FOOTPRINT_VIEWER_MODAL: + case FRAME_FOOTPRINT_CHOOSER: case FRAME_FOOTPRINT_PREVIEW: case FRAME_CVPCB: case FRAME_CVPCB_DISPLAY: diff --git a/pcbnew/pcb_edit_frame.cpp b/pcbnew/pcb_edit_frame.cpp index 7a40aa0e4b..3b4aa46ba9 100644 --- a/pcbnew/pcb_edit_frame.cpp +++ b/pcbnew/pcb_edit_frame.cpp @@ -1054,7 +1054,7 @@ bool PCB_EDIT_FRAME::canCloseWindow( wxCloseEvent& aEvent ) if( fpViewer && !fpViewer->Close() ) // Can close footprint viewer? return false; - fpViewer = (FOOTPRINT_VIEWER_FRAME*) Kiway().Player( FRAME_FOOTPRINT_VIEWER_MODAL, false ); + fpViewer = (FOOTPRINT_VIEWER_FRAME*) Kiway().Player( FRAME_FOOTPRINT_CHOOSER, false ); if( fpViewer && !fpViewer->Close() ) // Can close modal footprint viewer? return false; diff --git a/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp index 2c568ed0e6..d0eb960210 100644 --- a/pcbnew/pcb_painter.cpp +++ b/pcbnew/pcb_painter.cpp @@ -88,7 +88,7 @@ PCB_VIEWERS_SETTINGS_BASE* PCB_PAINTER::viewer_settings() return Pgm().GetSettingsManager().GetAppSettings(); case FRAME_FOOTPRINT_VIEWER: - case FRAME_FOOTPRINT_VIEWER_MODAL: + case FRAME_FOOTPRINT_CHOOSER: case FRAME_FOOTPRINT_PREVIEW: case FRAME_CVPCB: case FRAME_CVPCB_DISPLAY: diff --git a/pcbnew/pcbnew.cpp b/pcbnew/pcbnew.cpp index d91cacfaf3..29dd43daaf 100644 --- a/pcbnew/pcbnew.cpp +++ b/pcbnew/pcbnew.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -112,8 +113,10 @@ static struct IFACE : public KIFACE_BASE, public UNITS_PROVIDER return new FOOTPRINT_EDIT_FRAME( aKiway, aParent ); case FRAME_FOOTPRINT_VIEWER: - case FRAME_FOOTPRINT_VIEWER_MODAL: - return new FOOTPRINT_VIEWER_FRAME( aKiway, aParent, FRAME_T( aClassId ) ); + return new FOOTPRINT_VIEWER_FRAME( aKiway, aParent ); + + case FRAME_FOOTPRINT_CHOOSER: + return new FOOTPRINT_CHOOSER_FRAME( aKiway, aParent ); case FRAME_FOOTPRINT_WIZARD: return new FOOTPRINT_WIZARD_FRAME( aKiway, aParent, FRAME_T( aClassId ) ); diff --git a/pcbnew/tools/board_editor_control.cpp b/pcbnew/tools/board_editor_control.cpp index 9f92227569..46b623b762 100644 --- a/pcbnew/tools/board_editor_control.cpp +++ b/pcbnew/tools/board_editor_control.cpp @@ -1086,7 +1086,7 @@ int BOARD_EDITOR_CONTROL::PlaceFootprint( const TOOL_EVENT& aEvent ) if( !fp ) { // Pick the footprint to be placed - fp = m_frame->SelectFootprintFromLibTree(); + fp = m_frame->SelectFootprintFromLibrary(); if( fp == nullptr ) continue; diff --git a/pcbnew/tools/pcb_selection_tool.cpp b/pcbnew/tools/pcb_selection_tool.cpp index fd60d825a5..01dc1bb657 100644 --- a/pcbnew/tools/pcb_selection_tool.cpp +++ b/pcbnew/tools/pcb_selection_tool.cpp @@ -150,8 +150,7 @@ bool PCB_SELECTION_TOOL::Init() { PCB_BASE_FRAME* frame = getEditFrame(); - if( frame && ( frame->IsType( FRAME_FOOTPRINT_VIEWER ) - || frame->IsType( FRAME_FOOTPRINT_VIEWER_MODAL ) ) ) + if( frame && frame->IsType( FRAME_FOOTPRINT_VIEWER ) ) { frame->AddStandardSubMenus( m_menu ); return true; diff --git a/pcbnew/tools/pcb_viewer_tools.cpp b/pcbnew/tools/pcb_viewer_tools.cpp index a879784e83..b8adb44bfa 100644 --- a/pcbnew/tools/pcb_viewer_tools.cpp +++ b/pcbnew/tools/pcb_viewer_tools.cpp @@ -67,7 +67,6 @@ int PCB_VIEWER_TOOLS::Show3DViewer( const TOOL_EVENT& aEvent ) EDA_3D_VIEWER_FRAME* draw3DFrame = frame()->CreateAndShow3D_Frame(); if( frame()->IsType( FRAME_FOOTPRINT_VIEWER ) - || frame()->IsType( FRAME_FOOTPRINT_VIEWER_MODAL ) || frame()->IsType( FRAME_FOOTPRINT_WIZARD ) ) { // A stronger version of Raise() which promotes the window to its parent's level. diff --git a/pcbnew/widgets/panel_footprint_chooser.cpp b/pcbnew/widgets/panel_footprint_chooser.cpp new file mode 100644 index 0000000000..0166653cac --- /dev/null +++ b/pcbnew/widgets/panel_footprint_chooser.cpp @@ -0,0 +1,282 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 Henner Zeller + * Copyright (C) 2016-2023 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +PANEL_FOOTPRINT_CHOOSER::PANEL_FOOTPRINT_CHOOSER( PCB_BASE_FRAME* aFrame, wxTopLevelWindow* aParent, + const wxArrayString& aFootprintHistoryList, + std::function aCloseHandler ) : + wxPanel( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize ), + m_hsplitter( nullptr ), + m_vsplitter( nullptr ), + m_frame( aFrame ), + m_closeHandler( std::move( aCloseHandler ) ) +{ + FP_LIB_TABLE* fpTable = aFrame->Prj().PcbFootprintLibs(); + + // Load footprint files: + WX_PROGRESS_REPORTER* progressReporter = new WX_PROGRESS_REPORTER( aParent, + _( "Loading Footprint Libraries" ), 3 ); + GFootprintList.ReadFootprintFiles( fpTable, nullptr, progressReporter ); + + // Force immediate deletion of the WX_PROGRESS_REPORTER. Do not use Destroy(), or use + // Destroy() followed by wxSafeYield() because on Windows, APP_PROGRESS_DIALOG and + // WX_PROGRESS_REPORTER have some side effects on the event loop manager. For instance, a + // subsequent call to ShowModal() or ShowQuasiModal() for a dialog following the use of a + // WX_PROGRESS_REPORTER results in incorrect modal or quasi modal behavior. + delete progressReporter; + + if( GFootprintList.GetErrorCount() ) + GFootprintList.DisplayErrors( aParent ); + + m_adapter = FP_TREE_MODEL_ADAPTER::Create( aFrame, fpTable ); + FP_TREE_MODEL_ADAPTER* adapter = static_cast( m_adapter.get() ); + + std::vector historyInfos; + + for( const wxString& item : aFootprintHistoryList ) + { + LIB_TREE_ITEM* fp_info = GFootprintList.GetFootprintInfo( item ); + + // this can be null, for example, if the footprint has been deleted from a library. + if( fp_info != nullptr ) + historyInfos.push_back( fp_info ); + } + + adapter->DoAddLibrary( wxT( "-- " ) + _( "Recently Used" ) + wxT( " --" ), wxEmptyString, + historyInfos, false, true ); + + if( historyInfos.size() ) + adapter->SetPreselectNode( historyInfos[0]->GetLibId(), 0 ); + + adapter->AddLibraries( aFrame ); + + wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL ); + HTML_WINDOW* details = nullptr; + + m_vsplitter = new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, + wxSP_LIVE_UPDATE | wxSP_3DSASH ); + + m_hsplitter = new wxSplitterWindow( m_vsplitter, wxID_ANY, wxDefaultPosition, wxDefaultSize, + wxSP_LIVE_UPDATE | wxSP_3DSASH ); + + //Avoid the splitter window being assigned as the Parent to additional windows + m_hsplitter->SetExtraStyle( wxWS_EX_TRANSIENT ); + + auto detailsPanel = new wxPanel( m_vsplitter ); + auto detailsSizer = new wxBoxSizer( wxVERTICAL ); + detailsPanel->SetSizer( detailsSizer ); + + details = new HTML_WINDOW( detailsPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, + wxHW_SCROLLBAR_AUTO ); + detailsSizer->Add( details, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 5 ); + detailsPanel->Layout(); + detailsSizer->Fit( detailsPanel ); + + m_vsplitter->SetSashGravity( 0.5 ); + m_vsplitter->SetMinimumPaneSize( 20 ); + m_vsplitter->SplitHorizontally( m_hsplitter, detailsPanel ); + + sizer->Add( m_vsplitter, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 5 ); + + m_tree = new LIB_TREE( m_hsplitter, wxT( "footprints" ), fpTable, m_adapter, + LIB_TREE::FLAGS::ALL_WIDGETS, details ); + + m_hsplitter->SetSashGravity( 0.8 ); + m_hsplitter->SetMinimumPaneSize( 20 ); + + wxPanel* rightPanel = new wxPanel( m_hsplitter ); + wxBoxSizer* rightPanelSizer = new wxBoxSizer( wxVERTICAL ); + + m_preview_ctrl = new FOOTPRINT_PREVIEW_WIDGET( rightPanel, m_frame->Kiway() ); + m_preview_ctrl->SetUserUnits( m_frame->GetUserUnits() ); + rightPanelSizer->Add( m_preview_ctrl, 1, wxEXPAND | wxTOP | wxRIGHT, 5 ); + + rightPanel->SetSizer( rightPanelSizer ); + rightPanel->Layout(); + rightPanelSizer->Fit( rightPanel ); + + m_hsplitter->SplitVertically( m_tree, rightPanel ); + + m_dbl_click_timer = new wxTimer( this ); + + SetSizer( sizer ); + + m_adapter->FinishTreeInitialization(); + + Bind( wxEVT_TIMER, &PANEL_FOOTPRINT_CHOOSER::onCloseTimer, this, m_dbl_click_timer->GetId() ); + Bind( SYMBOL_PRESELECTED, &PANEL_FOOTPRINT_CHOOSER::onComponentPreselected, this ); + Bind( SYMBOL_SELECTED, &PANEL_FOOTPRINT_CHOOSER::onComponentSelected, this ); + + Layout(); +} + + +PANEL_FOOTPRINT_CHOOSER::~PANEL_FOOTPRINT_CHOOSER() +{ + Unbind( wxEVT_TIMER, &PANEL_FOOTPRINT_CHOOSER::onCloseTimer, this ); + Unbind( SYMBOL_PRESELECTED, &PANEL_FOOTPRINT_CHOOSER::onComponentPreselected, this ); + Unbind( SYMBOL_SELECTED, &PANEL_FOOTPRINT_CHOOSER::onComponentSelected, this ); + + // I am not sure the following two lines are necessary, but they will not hurt anyone + m_dbl_click_timer->Stop(); + delete m_dbl_click_timer; + + if( PCBNEW_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings() ) + { + // Save any changes to column widths, etc. + m_adapter->SaveSettings(); + + cfg->m_FootprintChooser.width = GetParent()->GetSize().x; + cfg->m_FootprintChooser.height = GetParent()->GetSize().y; + cfg->m_FootprintChooser.sash_h = m_hsplitter->GetSashPosition(); + + if( m_vsplitter ) + cfg->m_FootprintChooser.sash_v = m_vsplitter->GetSashPosition(); + + cfg->m_FootprintChooser.sort_mode = m_tree->GetSortMode(); + } +} + + +void PANEL_FOOTPRINT_CHOOSER::FinishSetup() +{ + if( PCBNEW_SETTINGS* settings = Pgm().GetSettingsManager().GetAppSettings() ) + { + auto horizPixelsFromDU = + [&]( int x ) -> int + { + wxSize sz( x, 0 ); + return GetParent()->ConvertDialogToPixels( sz ).x; + }; + + PCBNEW_SETTINGS::FOOTPRINT_CHOOSER& cfg = settings->m_FootprintChooser; + + int w = cfg.width < 0 ? horizPixelsFromDU( 440 ) : cfg.width; + int h = cfg.height < 0 ? horizPixelsFromDU( 340 ) : cfg.height; + + GetParent()->SetSize( wxSize( w, h ) ); + GetParent()->Layout(); + + // We specify the width of the right window (m_symbol_view_panel), because specify + // the width of the left window does not work as expected when SetSashGravity() is called + if( cfg.sash_h < 0 ) + cfg.sash_h = horizPixelsFromDU( 220 ); + + m_hsplitter->SetSashPosition( cfg.sash_h ); + + if( cfg.sash_v < 0 ) + cfg.sash_v = horizPixelsFromDU( 230 ); + + if( m_vsplitter ) + m_vsplitter->SetSashPosition( cfg.sash_v ); + + m_adapter->SetSortMode( (LIB_TREE_MODEL_ADAPTER::SORT_MODE) cfg.sort_mode ); + } +} + + +void PANEL_FOOTPRINT_CHOOSER::SetPreselect( const LIB_ID& aPreselect ) +{ + m_adapter->SetPreselectNode( aPreselect, 0 ); +} + + +LIB_ID PANEL_FOOTPRINT_CHOOSER::GetSelectedLibId() const +{ + return m_tree->GetSelectedLibId(); +} + + +void PANEL_FOOTPRINT_CHOOSER::onCloseTimer( wxTimerEvent& aEvent ) +{ + // Hack because of eaten MouseUp event. See PANEL_FOOTPRINT_CHOOSER::onComponentSelected + // for the beginning of this spaghetti noodle. + + auto state = wxGetMouseState(); + + if( state.LeftIsDown() ) + { + // Mouse hasn't been raised yet, so fire the timer again. Otherwise the + // purpose of this timer is defeated. + m_dbl_click_timer->StartOnce( PANEL_FOOTPRINT_CHOOSER::DblClickDelay ); + } + else + { + m_closeHandler(); + } +} + + +void PANEL_FOOTPRINT_CHOOSER::onComponentPreselected( wxCommandEvent& aEvent ) +{ + if( !m_preview_ctrl || !m_preview_ctrl->IsInitialized() ) + return; + + LIB_ID lib_id = m_tree->GetSelectedLibId(); + + if( !lib_id.IsValid() ) + { + m_preview_ctrl->SetStatusText( _( "No footprint selected" ) ); + } + else + { + m_preview_ctrl->ClearStatus(); + m_preview_ctrl->DisplayFootprint( lib_id ); + } +} + + +void PANEL_FOOTPRINT_CHOOSER::onComponentSelected( wxCommandEvent& aEvent ) +{ + if( m_tree->GetSelectedLibId().IsValid() ) + { + // Got a selection. We can't just end the modal dialog here, because wx leaks some + // events back to the parent window (in particular, the MouseUp following a double click). + // + // NOW, here's where it gets really fun. wxTreeListCtrl eats MouseUp. This isn't really + // feasible to bypass without a fully custom wxDataViewCtrl implementation, and even then + // might not be fully possible (docs are vague). To get around this, we use a one-shot + // timer to schedule the dialog close. + // + // See PANEL_FOOTPRINT_CHOOSER::onCloseTimer for the other end of this spaghetti noodle. + m_dbl_click_timer->StartOnce( PANEL_FOOTPRINT_CHOOSER::DblClickDelay ); + } +} diff --git a/pcbnew/widgets/panel_footprint_chooser.h b/pcbnew/widgets/panel_footprint_chooser.h new file mode 100644 index 0000000000..ff8fa4b3df --- /dev/null +++ b/pcbnew/widgets/panel_footprint_chooser.h @@ -0,0 +1,99 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014-2023 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef PANEL_FOOTPRINT_CHOOSER_H +#define PANEL_FOOTPRINT_CHOOSER_H + +#include "dialog_shim.h" +#include +#include +#include +#include + +class wxTimer; +class wxSplitterWindow; + +class PCB_BASE_FRAME; + + +class PANEL_FOOTPRINT_CHOOSER : public wxPanel +{ +public: + /** + * Create dialog to choose component. + * + * @param aFrame the parent frame (FRAME_PCB_EDIT_FRAME or FOOTPRINT_CHOOSER_FRAME) + * @param aParent the parent window (DIALOG_SHIM or FOOTPRINT_CHOOSER_FRAME) + * @param aCloseHandler a handler to be called on double-click of a footprint + */ + PANEL_FOOTPRINT_CHOOSER( PCB_BASE_FRAME* aFrame, wxTopLevelWindow* aParent, + const wxArrayString& aFootprintHistoryList, + std::function aCloseHandler ); + + ~PANEL_FOOTPRINT_CHOOSER(); + + void FinishSetup(); + + void SetPreselect( const LIB_ID& aPreselect ); + + /** + * To be called after this dialog returns from ShowModal(). + * + * @return the #LIB_ID of the symbol that has been selected. + */ + LIB_ID GetSelectedLibId() const; + + int GetItemCount() const { return m_adapter->GetItemCount(); } + + wxWindow* GetFocusTarget() const { return m_tree->GetFocusTarget(); } + + +protected: + static constexpr int DblClickDelay = 100; // milliseconds + + void onCloseTimer( wxTimerEvent& aEvent ); + + void onComponentPreselected( wxCommandEvent& 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. + * If the item selected is a category, it is expanded or collapsed; if it + * is a component, the component is picked. + */ + void onComponentSelected( wxCommandEvent& aEvent ); + +protected: + wxTimer* m_dbl_click_timer; + wxSplitterWindow* m_hsplitter; + wxSplitterWindow* m_vsplitter; + + wxObjectDataPtr m_adapter; + + FOOTPRINT_PREVIEW_WIDGET* m_preview_ctrl; + LIB_TREE* m_tree; + + PCB_BASE_FRAME* m_frame; + std::function m_closeHandler; +}; + +#endif /* PANEL_FOOTPRINT_CHOOSER_H */