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  FP_TREE_MODEL_ADAPTER::PTR& 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->CacheFootprint( lib_id );
230  m_preview_ctrl->DisplayFootprint( lib_id );
231  }
232 }
233 
234 
235 void DIALOG_CHOOSE_FOOTPRINT::OnComponentSelected( wxCommandEvent& aEvent )
236 {
237  if( m_tree->GetSelectedLibId().IsValid() )
238  {
239  // Got a selection. We can't just end the modal dialog here, because
240  // wx leaks some events back to the parent window (in particular, the
241  // MouseUp following a double click).
242  //
243  // NOW, here's where it gets really fun. wxTreeListCtrl eats MouseUp.
244  // This isn't really feasible to bypass without a fully custom
245  // wxDataViewCtrl implementation, and even then might not be fully
246  // possible (docs are vague). To get around this, we use a one-shot
247  // timer to schedule the dialog close.
248  //
249  // See DIALOG_CHOOSE_FOOTPRINT::OnCloseTimer for the other end of this
250  // spaghetti noodle.
252  }
253 }
static constexpr int DblClickDelay
KIWAY & Kiway() const
Function Kiway returns a reference to the KIWAY that this object has an opportunity to participate in...
Definition: kiway_holder.h:56
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:104
void OnCloseTimer(wxTimerEvent &aEvent)
DIALOG_CHOOSE_FOOTPRINT(PCB_BASE_FRAME *aParent, const wxString &aTitle, FP_TREE_MODEL_ADAPTER::PTR &aAdapter)
Create dialog to choose component.
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
bool IsValid() const
Definition: lib_id.h:171
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:114
Classes used in Pcbnew, CvPcb and GerbView.
void ClearStatus()
Clear the contents of the status label and hide it.
PROJECT & Prj() const
Function Prj returns 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)
Definition: hash_eda.h:46
void SetStatusText(wxString const &aText)
Set the contents of the status label and display it.
void OnComponentPreselected(wxCommandEvent &aEvent)
void EndQuasiModal(int retCode)
wxPanel * ConstructRightPanel(wxWindow *aParent)
void CacheFootprint(const LIB_ID &aFPID)
Preload a footprint into the cache.
see class PGM_BASE
#define _(s)
Definition: 3d_actions.cpp:33
void DisplayFootprint(const LIB_ID &aFPID)
Set the currently displayed footprint.
int HorizPixelsFromDU(int x)
Convert an integer number of dialog units to pixels, horizontally.
wxObjectDataPtr< LIB_TREE_MODEL_ADAPTER > PTR
Reference-counting container for a pointer to CMP_TREE_MODEL_ADAPTER_BASE.
bool IsInitialized() const
Return whether the widget initialized properly.
void OnComponentSelected(wxCommandEvent &aEvent)
Handle the selection of an item.
PCB_BASE_FRAME basic 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