KiCad PCB EDA Suite
dialog_choose_footprint.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
5  * Copyright (C) 2016-2019 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
26 #include <algorithm>
27 #include <wx/utils.h>
28 #include <wx/button.h>
29 #include <wx/panel.h>
30 #include <wx/sizer.h>
31 #include <wx/splitter.h>
32 #include <wx/timer.h>
33 #include <pcb_base_frame.h>
34 #include <pcbnew_settings.h>
35 #include <pgm_base.h>
36 #include <fp_lib_table.h>
38 #include <widgets/lib_tree.h>
41 #include <kiface_i.h>
42 
43 
45  const wxString& aTitle,
46  wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER>& aAdapter )
47  : DIALOG_SHIM( aParent, wxID_ANY, aTitle, wxDefaultPosition, wxDefaultSize,
48  wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
49  m_browser_button( nullptr ),
50  m_hsplitter( nullptr ),
51  m_vsplitter( nullptr ),
52  m_parent( aParent ),
53  m_external_browser_requested( false )
54 {
55  auto sizer = new wxBoxSizer( wxVERTICAL );
56  wxHtmlWindow* details = nullptr;
57 
58  m_vsplitter = new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
59  wxSP_LIVE_UPDATE );
60 
61  m_hsplitter = new wxSplitterWindow( m_vsplitter, wxID_ANY, wxDefaultPosition, wxDefaultSize,
62  wxSP_LIVE_UPDATE );
63 
64  //Avoid the splitter window being assigned as the Parent to additional windows
65  m_hsplitter->SetExtraStyle( wxWS_EX_TRANSIENT );
66 
67  auto detailsPanel = new wxPanel( m_vsplitter );
68  auto detailsSizer = new wxBoxSizer( wxVERTICAL );
69  detailsPanel->SetSizer( detailsSizer );
70 
71  details = new wxHtmlWindow( detailsPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize,
72  wxHW_SCROLLBAR_AUTO );
73  detailsSizer->Add( details, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 5 );
74  detailsPanel->Layout();
75  detailsSizer->Fit( detailsPanel );
76 
77  m_vsplitter->SetSashGravity( 0.5 );
78  m_vsplitter->SetMinimumPaneSize( 20 );
79  m_vsplitter->SplitHorizontally( m_hsplitter, detailsPanel );
80 
81  sizer->Add( m_vsplitter, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 5 );
82 
83  m_tree = new LIB_TREE( m_hsplitter, Prj().PcbFootprintLibs(), aAdapter,
84  LIB_TREE::WIDGETS::ALL, details );
85 
86  m_hsplitter->SetSashGravity( 0.8 );
87  m_hsplitter->SetMinimumPaneSize( 20 );
88  m_hsplitter->SplitVertically( m_tree, ConstructRightPanel( m_hsplitter ) );
89 
90  m_dbl_click_timer = new wxTimer( this );
91 
92  auto buttonsSizer = new wxBoxSizer( wxHORIZONTAL );
93 
94  m_browser_button = new wxButton( this, wxID_ANY, _( "Select with Browser" ) );
95  buttonsSizer->Add( m_browser_button, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5 );
96 
97  auto sdbSizer = new wxStdDialogButtonSizer();
98  auto okButton = new wxButton( this, wxID_OK );
99  auto cancelButton = new wxButton( this, wxID_CANCEL );
100  sdbSizer->AddButton( okButton );
101  sdbSizer->AddButton( cancelButton );
102  sdbSizer->Realize();
103 
104  buttonsSizer->Add( sdbSizer, 1, wxALL, 5 );
105 
106  sizer->Add( buttonsSizer, 0, wxEXPAND | wxLEFT, 5 );
107  SetSizer( sizer );
108 
109  Bind( wxEVT_TIMER, &DIALOG_CHOOSE_FOOTPRINT::OnCloseTimer, this, m_dbl_click_timer->GetId() );
110  Bind( COMPONENT_PRESELECTED, &DIALOG_CHOOSE_FOOTPRINT::OnComponentPreselected, this );
111  Bind( COMPONENT_SELECTED, &DIALOG_CHOOSE_FOOTPRINT::OnComponentSelected, this );
112  m_browser_button->Bind( wxEVT_COMMAND_BUTTON_CLICKED, &DIALOG_CHOOSE_FOOTPRINT::OnUseBrowser, this );
113 
114  Layout();
115 
116  auto cfg = Pgm().GetSettingsManager().GetAppSettings<PCBNEW_SETTINGS>();
117 
118  // We specify the width of the right window (m_symbol_view_panel), because specify
119  // the width of the left window does not work as expected when SetSashGravity() is called
120  if( cfg->m_FootprintChooser.sash_h < 0 )
122 
123  m_hsplitter->SetSashPosition( cfg->m_FootprintChooser.sash_h );
124 
125  if( cfg->m_FootprintChooser.sash_v < 0 )
126  cfg->m_FootprintChooser.sash_v = horizPixelsFromDU( 230 );
127 
128  if( m_vsplitter )
129  m_vsplitter->SetSashPosition( cfg->m_FootprintChooser.sash_v );
130 
131  int w = cfg->m_FootprintChooser.width < 0 ?
132  horizPixelsFromDU( 440 ) : cfg->m_FootprintChooser.width;
133  int h = cfg->m_FootprintChooser.height < 0 ?
134  horizPixelsFromDU( 340 ) : cfg->m_FootprintChooser.height;
135  SetSize( wxSize( w, h ) );
136 
138  okButton->SetDefault();
139 }
140 
141 
143 {
144  Unbind( wxEVT_TIMER, &DIALOG_CHOOSE_FOOTPRINT::OnCloseTimer, this );
145  Unbind( COMPONENT_PRESELECTED, &DIALOG_CHOOSE_FOOTPRINT::OnComponentPreselected, this );
146  Unbind( COMPONENT_SELECTED, &DIALOG_CHOOSE_FOOTPRINT::OnComponentSelected, this );
147  m_browser_button->Unbind( wxEVT_COMMAND_BUTTON_CLICKED, &DIALOG_CHOOSE_FOOTPRINT::OnUseBrowser, this );
148 
149  // I am not sure the following two lines are necessary,
150  // but they will not hurt anyone
151  m_dbl_click_timer->Stop();
152  delete m_dbl_click_timer;
153 
154  auto cfg = Pgm().GetSettingsManager().GetAppSettings<PCBNEW_SETTINGS>();
155 
156  cfg->m_FootprintChooser.width = GetSize().x;
157  cfg->m_FootprintChooser.height = GetSize().y;
158  cfg->m_FootprintChooser.sash_h = m_hsplitter->GetSashPosition();
159 
160  if( m_vsplitter )
161  cfg->m_FootprintChooser.sash_v = m_vsplitter->GetSashPosition();
162 }
163 
164 
165 wxPanel* DIALOG_CHOOSE_FOOTPRINT::ConstructRightPanel( wxWindow* aParent )
166 {
167  auto panel = new wxPanel( aParent );
168  auto sizer = new wxBoxSizer( wxVERTICAL );
169 
171  sizer->Add( m_preview_ctrl, 1, wxEXPAND | wxTOP | wxRIGHT, 5 );
172 
173  panel->SetSizer( sizer );
174  panel->Layout();
175  sizer->Fit( panel );
176 
177  return panel;
178 }
179 
180 
182 {
183  return m_tree->GetSelectedLibId();
184 }
185 
186 
187 void DIALOG_CHOOSE_FOOTPRINT::OnUseBrowser( wxCommandEvent& aEvent )
188 {
190  EndQuasiModal( wxID_OK );
191 }
192 
193 
194 void DIALOG_CHOOSE_FOOTPRINT::OnCloseTimer( wxTimerEvent& aEvent )
195 {
196  // Hack handler because of eaten MouseUp event. See
197  // DIALOG_CHOOSE_FOOTPRINT::OnComponentSelected for the beginning
198  // of this spaghetti noodle.
199 
200  auto state = wxGetMouseState();
201 
202  if( state.LeftIsDown() )
203  {
204  // Mouse hasn't been raised yet, so fire the timer again. Otherwise the
205  // purpose of this timer is defeated.
207  }
208  else
209  {
210  EndQuasiModal( wxID_OK );
211  }
212 }
213 
214 
216 {
218  return;
219 
220  LIB_ID lib_id = m_tree->GetSelectedLibId();
221 
222  if( !lib_id.IsValid() )
223  {
224  m_preview_ctrl->SetStatusText( _( "No footprint selected" ) );
225  }
226  else
227  {
229  m_preview_ctrl->DisplayFootprint( lib_id );
230  }
231 }
232 
233 
234 void DIALOG_CHOOSE_FOOTPRINT::OnComponentSelected( wxCommandEvent& aEvent )
235 {
236  if( m_tree->GetSelectedLibId().IsValid() )
237  {
238  // Got a selection. We can't just end the modal dialog here, because
239  // wx leaks some events back to the parent window (in particular, the
240  // MouseUp following a double click).
241  //
242  // NOW, here's where it gets really fun. wxTreeListCtrl eats MouseUp.
243  // This isn't really feasible to bypass without a fully custom
244  // wxDataViewCtrl implementation, and even then might not be fully
245  // possible (docs are vague). To get around this, we use a one-shot
246  // timer to schedule the dialog close.
247  //
248  // See DIALOG_CHOOSE_FOOTPRINT::OnCloseTimer for the other end of this
249  // spaghetti noodle.
251  }
252 }
static constexpr int DblClickDelay
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
Definition: kiway_holder.h:56
void OnCloseTimer(wxTimerEvent &aEvent)
wxWindow * GetFocusTarget()
Definition: lib_tree.cpp:224
int horizPixelsFromDU(int x) const
Convert an integer number of dialog units to pixels, horizontally.
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition: dialog_shim.h:83
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
All except INITIAL_ADD.
Definition: view_item.h:58
bool IsValid() const
Check if this LID_ID is valid.
Definition: lib_id.h:168
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:106
FOOTPRINT_PREVIEW_WIDGET * m_preview_ctrl
FOOTPRINT_CHOOSER m_FootprintChooser
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:98
Classes used in Pcbnew, CvPcb and GerbView.
void ClearStatus()
Clear the contents of the status label and hide it.
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
LIB_ID GetSelectedLibId(int *aUnit=nullptr) const
For multi-unit components, if the user selects the component itself rather than picking an individual...
Definition: lib_tree.cpp:148
LIB_ID GetSelectedLibId() const
To be called after this dialog returns from ShowModal().
void OnUseBrowser(wxCommandEvent &aEvent)
void SetStatusText(wxString const &aText)
Set the contents of the status label and display it.
void OnComponentPreselected(wxCommandEvent &aEvent)
DIALOG_CHOOSE_FOOTPRINT(PCB_BASE_FRAME *aParent, const wxString &aTitle, wxObjectDataPtr< LIB_TREE_MODEL_ADAPTER > &aAdapter)
Create dialog to choose component.
void EndQuasiModal(int retCode)
wxPanel * ConstructRightPanel(wxWindow *aParent)
see class PGM_BASE
#define _(s)
Definition: 3d_actions.cpp:33
void DisplayFootprint(const LIB_ID &aFPID)
Set the currently displayed footprint.
bool IsInitialized() const
Return whether the widget initialized properly.
void OnComponentSelected(wxCommandEvent &aEvent)
Handle the selection of an item.
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
Widget displaying a tree of components with optional search text control and description panel....
Definition: lib_tree.h:42