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-2018 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 
27 #include <algorithm>
28 #include <set>
29 #include <wx/utils.h>
30 
31 #include <wx/button.h>
32 #include <wx/dataview.h>
33 #include <wx/panel.h>
34 #include <wx/sizer.h>
35 #include <wx/splitter.h>
36 #include <wx/timer.h>
37 #include <wx/utils.h>
38 
39 #include <pcb_base_frame.h>
40 #include <fp_lib_table.h>
41 #include <widgets/lib_tree.h>
44 
45 
49 
50 
52  const wxString& aTitle,
54  bool aAllowBrowser )
55  : DIALOG_SHIM( aParent, wxID_ANY, aTitle, wxDefaultPosition, wxDefaultSize,
56  wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
57  m_browser_button( nullptr ),
58  m_hsplitter( nullptr ),
59  m_vsplitter( nullptr ),
60  m_parent( aParent ),
61  m_external_browser_requested( false )
62 {
63  auto sizer = new wxBoxSizer( wxVERTICAL );
64  wxHtmlWindow* details = nullptr;
65 
66  m_vsplitter = new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
67  wxSP_LIVE_UPDATE );
68 
69  m_hsplitter = new wxSplitterWindow( m_vsplitter, wxID_ANY, wxDefaultPosition, wxDefaultSize,
70  wxSP_LIVE_UPDATE );
71 
72  //Avoid the splitter window being assigned as the Parent to additional windows
73  m_hsplitter->SetExtraStyle( wxWS_EX_TRANSIENT );
74 
75  auto detailsPanel = new wxPanel( m_vsplitter );
76  auto detailsSizer = new wxBoxSizer( wxVERTICAL );
77  detailsPanel->SetSizer( detailsSizer );
78 
79  details = new wxHtmlWindow( detailsPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize,
80  wxHW_SCROLLBAR_AUTO );
81  detailsSizer->Add( details, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 5 );
82  detailsPanel->Layout();
83  detailsSizer->Fit( detailsPanel );
84 
85  m_vsplitter->SetSashGravity( 0.5 );
86  m_vsplitter->SetMinimumPaneSize( 20 );
87  m_vsplitter->SplitHorizontally( m_hsplitter, detailsPanel );
88 
89  sizer->Add( m_vsplitter, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 5 );
90 
91  m_tree = new LIB_TREE( m_hsplitter, Prj().PcbFootprintLibs(), aAdapter,
92  LIB_TREE::WIDGETS::ALL, details );
93 
94  m_hsplitter->SetSashGravity( 0.8 );
95  m_hsplitter->SetMinimumPaneSize( 20 );
96  m_hsplitter->SplitVertically( m_tree, ConstructRightPanel( m_hsplitter ) );
97 
98  m_dbl_click_timer = new wxTimer( this );
99 
100  auto buttonsSizer = new wxBoxSizer( wxHORIZONTAL );
101 
102  if( aAllowBrowser )
103  {
104  m_browser_button = new wxButton( this, wxID_ANY, _( "Select with Browser" ) );
105  buttonsSizer->Add( m_browser_button, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5 );
106  }
107 
108  auto sdbSizer = new wxStdDialogButtonSizer();
109  auto okButton = new wxButton( this, wxID_OK );
110  auto cancelButton = new wxButton( this, wxID_CANCEL );
111  sdbSizer->AddButton( okButton );
112  sdbSizer->AddButton( cancelButton );
113  sdbSizer->Realize();
114 
115  buttonsSizer->Add( sdbSizer, 1, wxALL, 5 );
116 
117  sizer->Add( buttonsSizer, 0, wxEXPAND | wxLEFT, 5 );
118  SetSizer( sizer );
119 
120  Bind( wxEVT_TIMER, &DIALOG_CHOOSE_FOOTPRINT::OnCloseTimer, this, m_dbl_click_timer->GetId() );
121  Bind( COMPONENT_PRESELECTED, &DIALOG_CHOOSE_FOOTPRINT::OnComponentPreselected, this );
122  Bind( COMPONENT_SELECTED, &DIALOG_CHOOSE_FOOTPRINT::OnComponentSelected, this );
123 
124  if( m_browser_button )
125  m_browser_button->Bind( wxEVT_COMMAND_BUTTON_CLICKED, &DIALOG_CHOOSE_FOOTPRINT::OnUseBrowser, this );
126 
127  Layout();
128 
129  // We specify the width of the right window (m_symbol_view_panel), because specify
130  // the width of the left window does not work as expected when SetSashGravity() is called
131  m_hsplitter->SetSashPosition( m_h_sash_pos ? m_h_sash_pos : HorizPixelsFromDU( 220 ) );
132 
133  if( m_vsplitter )
134  m_vsplitter->SetSashPosition( m_v_sash_pos ? m_v_sash_pos : VertPixelsFromDU( 230 ) );
135 
136  if( m_last_dlg_size == wxSize( -1, -1 ) )
137  SetSizeInDU( 440, 340 );
138  else
139  SetSize( m_last_dlg_size );
140 
142  okButton->SetDefault();
143 }
144 
145 
147 {
148  Unbind( wxEVT_TIMER, &DIALOG_CHOOSE_FOOTPRINT::OnCloseTimer, this );
149  Unbind( COMPONENT_PRESELECTED, &DIALOG_CHOOSE_FOOTPRINT::OnComponentPreselected, this );
150  Unbind( COMPONENT_SELECTED, &DIALOG_CHOOSE_FOOTPRINT::OnComponentSelected, this );
151 
152  if( m_browser_button )
153  m_browser_button->Unbind( wxEVT_COMMAND_BUTTON_CLICKED, &DIALOG_CHOOSE_FOOTPRINT::OnUseBrowser, this );
154 
155  // I am not sure the following two lines are necessary,
156  // but they will not hurt anyone
157  m_dbl_click_timer->Stop();
158  delete m_dbl_click_timer;
159 
160  m_last_dlg_size = GetSize();
161  m_h_sash_pos = m_hsplitter->GetSashPosition();
162 
163  if( m_vsplitter )
164  m_v_sash_pos = m_vsplitter->GetSashPosition();
165 }
166 
167 
168 wxPanel* DIALOG_CHOOSE_FOOTPRINT::ConstructRightPanel( wxWindow* aParent )
169 {
170  auto panel = new wxPanel( aParent );
171  auto sizer = new wxBoxSizer( wxVERTICAL );
172 
174  sizer->Add( m_preview_ctrl, 1, wxEXPAND | wxTOP | wxRIGHT, 5 );
175 
176  panel->SetSizer( sizer );
177  panel->Layout();
178  sizer->Fit( panel );
179 
180  return panel;
181 }
182 
183 
185 {
186  return m_tree->GetSelectedLibId();
187 }
188 
189 
190 void DIALOG_CHOOSE_FOOTPRINT::OnUseBrowser( wxCommandEvent& aEvent )
191 {
193  EndQuasiModal( wxID_OK );
194 }
195 
196 
197 void DIALOG_CHOOSE_FOOTPRINT::OnCloseTimer( wxTimerEvent& aEvent )
198 {
199  // Hack handler because of eaten MouseUp event. See
200  // DIALOG_CHOOSE_FOOTPRINT::OnComponentSelected for the beginning
201  // of this spaghetti noodle.
202 
203  auto state = wxGetMouseState();
204 
205  if( state.LeftIsDown() )
206  {
207  // Mouse hasn't been raised yet, so fire the timer again. Otherwise the
208  // purpose of this timer is defeated.
210  }
211  else
212  {
213  EndQuasiModal( wxID_OK );
214  }
215 }
216 
217 
219 {
221  return;
222 
223  LIB_ID lib_id = m_tree->GetSelectedLibId();
224 
225  if( !lib_id.IsValid() )
226  {
227  m_preview_ctrl->SetStatusText( _( "No footprint selected" ) );
228  }
229  else
230  {
232  m_preview_ctrl->CacheFootprint( lib_id );
233  m_preview_ctrl->DisplayFootprint( lib_id );
234  }
235 }
236 
237 
238 void DIALOG_CHOOSE_FOOTPRINT::OnComponentSelected( wxCommandEvent& aEvent )
239 {
240  if( m_tree->GetSelectedLibId().IsValid() )
241  {
242  // Got a selection. We can't just end the modal dialog here, because
243  // wx leaks some events back to the parent window (in particular, the
244  // MouseUp following a double click).
245  //
246  // NOW, here's where it gets really fun. wxTreeListCtrl eats MouseUp.
247  // This isn't really feasible to bypass without a fully custom
248  // wxDataViewCtrl implementation, and even then might not be fully
249  // possible (docs are vague). To get around this, we use a one-shot
250  // timer to schedule the dialog close.
251  //
252  // See DIALOG_CHOOSE_FOOTPRINT::OnCloseTimer for the other end of this
253  // spaghetti noodle.
255  }
256 }
bool IsValid() const
Definition: lib_id.h:171
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_player.h:60
void OnCloseTimer(wxTimerEvent &aEvent)
Class DIALOG_SHIM may sit in the inheritance tree between wxDialog and any class written by wxFormBui...
Definition: dialog_shim.h:82
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
FOOTPRINT_PREVIEW_WIDGET * m_preview_ctrl
DIALOG_CHOOSE_FOOTPRINT(PCB_BASE_FRAME *aParent, const wxString &aTitle, FP_TREE_MODEL_ADAPTER::PTR &aAdapter, bool aAllowBrowser)
Create dialog to choose component.
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:115
Classes used in Pcbnew, CvPcb and GerbView.
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
void ClearStatus()
Clear the contents of the status label and hide it.
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:144
void SetSizeInDU(int x, int y)
Set the dialog to the given dimensions in "dialog units".
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)
int VertPixelsFromDU(int y)
Convert an integer number of dialog units to pixels, vertically.
void EndQuasiModal(int retCode)
wxPanel * ConstructRightPanel(wxWindow *aParent)
void CacheFootprint(const LIB_ID &aFPID)
Preload a footprint into the cache.
bool IsInitialized() const
Return whether the widget initialized properly.
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.
void OnComponentSelected(wxCommandEvent &aEvent)
Handle the selection of an item.
class PCB_BASE_FRAME basic PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer...
LIB_ID GetSelectedLibId() const
To be called after this dialog returns from ShowModal().
Widget displaying a tree of components with optional search text control and description panel...
Definition: lib_tree.h:42