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 <fp_lib_table.h>
35 #include <widgets/lib_tree.h>
38 #include <kiface_i.h>
39 
40 #define FP_CHOOSER_HSASH wxT( "FootprintChooserHSashPosition" )
41 #define FP_CHOOSER_VSASH wxT( "FootprintChooserVSashPosition" )
42 #define FP_CHOOSER_WIDTH_KEY wxT( "FootprintChooserWidth" )
43 #define FP_CHOOSER_HEIGHT_KEY wxT( "FootprintChooserHeight" )
44 
45 
47  const wxString& aTitle,
48  FP_TREE_MODEL_ADAPTER::PTR& aAdapter )
49  : DIALOG_SHIM( aParent, wxID_ANY, aTitle, wxDefaultPosition, wxDefaultSize,
50  wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
51  m_browser_button( nullptr ),
52  m_hsplitter( nullptr ),
53  m_vsplitter( nullptr ),
54  m_parent( aParent ),
55  m_external_browser_requested( false )
56 {
58 
59  auto sizer = new wxBoxSizer( wxVERTICAL );
60  wxHtmlWindow* details = nullptr;
61 
62  m_vsplitter = new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
63  wxSP_LIVE_UPDATE );
64 
65  m_hsplitter = new wxSplitterWindow( m_vsplitter, wxID_ANY, wxDefaultPosition, wxDefaultSize,
66  wxSP_LIVE_UPDATE );
67 
68  //Avoid the splitter window being assigned as the Parent to additional windows
69  m_hsplitter->SetExtraStyle( wxWS_EX_TRANSIENT );
70 
71  auto detailsPanel = new wxPanel( m_vsplitter );
72  auto detailsSizer = new wxBoxSizer( wxVERTICAL );
73  detailsPanel->SetSizer( detailsSizer );
74 
75  details = new wxHtmlWindow( detailsPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize,
76  wxHW_SCROLLBAR_AUTO );
77  detailsSizer->Add( details, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 5 );
78  detailsPanel->Layout();
79  detailsSizer->Fit( detailsPanel );
80 
81  m_vsplitter->SetSashGravity( 0.5 );
82  m_vsplitter->SetMinimumPaneSize( 20 );
83  m_vsplitter->SplitHorizontally( m_hsplitter, detailsPanel );
84 
85  sizer->Add( m_vsplitter, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 5 );
86 
87  m_tree = new LIB_TREE( m_hsplitter, Prj().PcbFootprintLibs(), aAdapter,
88  LIB_TREE::WIDGETS::ALL, details );
89 
90  m_hsplitter->SetSashGravity( 0.8 );
91  m_hsplitter->SetMinimumPaneSize( 20 );
92  m_hsplitter->SplitVertically( m_tree, ConstructRightPanel( m_hsplitter ) );
93 
94  m_dbl_click_timer = new wxTimer( this );
95 
96  auto buttonsSizer = new wxBoxSizer( wxHORIZONTAL );
97 
98  m_browser_button = new wxButton( this, wxID_ANY, _( "Select with Browser" ) );
99  buttonsSizer->Add( m_browser_button, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5 );
100 
101  auto sdbSizer = new wxStdDialogButtonSizer();
102  auto okButton = new wxButton( this, wxID_OK );
103  auto cancelButton = new wxButton( this, wxID_CANCEL );
104  sdbSizer->AddButton( okButton );
105  sdbSizer->AddButton( cancelButton );
106  sdbSizer->Realize();
107 
108  buttonsSizer->Add( sdbSizer, 1, wxALL, 5 );
109 
110  sizer->Add( buttonsSizer, 0, wxEXPAND | wxLEFT, 5 );
111  SetSizer( sizer );
112 
113  Bind( wxEVT_TIMER, &DIALOG_CHOOSE_FOOTPRINT::OnCloseTimer, this, m_dbl_click_timer->GetId() );
114  Bind( COMPONENT_PRESELECTED, &DIALOG_CHOOSE_FOOTPRINT::OnComponentPreselected, this );
115  Bind( COMPONENT_SELECTED, &DIALOG_CHOOSE_FOOTPRINT::OnComponentSelected, this );
116  m_browser_button->Bind( wxEVT_COMMAND_BUTTON_CLICKED, &DIALOG_CHOOSE_FOOTPRINT::OnUseBrowser, this );
117 
118  Layout();
119 
120  // We specify the width of the right window (m_symbol_view_panel), because specify
121  // the width of the left window does not work as expected when SetSashGravity() is called
122  m_hsplitter->SetSashPosition( m_config->Read( FP_CHOOSER_HSASH, HorizPixelsFromDU( 220 ) ) );
123 
124  if( m_vsplitter )
125  m_vsplitter->SetSashPosition( m_config->Read( FP_CHOOSER_VSASH, VertPixelsFromDU( 230 ) ) );
126 
127  wxSize dlgSize( m_config->Read( FP_CHOOSER_WIDTH_KEY, HorizPixelsFromDU( 440 ) ),
129  SetSize( dlgSize );
130 
132  okButton->SetDefault();
133 }
134 
135 
137 {
138  Unbind( wxEVT_TIMER, &DIALOG_CHOOSE_FOOTPRINT::OnCloseTimer, this );
139  Unbind( COMPONENT_PRESELECTED, &DIALOG_CHOOSE_FOOTPRINT::OnComponentPreselected, this );
140  Unbind( COMPONENT_SELECTED, &DIALOG_CHOOSE_FOOTPRINT::OnComponentSelected, this );
141  m_browser_button->Unbind( wxEVT_COMMAND_BUTTON_CLICKED, &DIALOG_CHOOSE_FOOTPRINT::OnUseBrowser, this );
142 
143  // I am not sure the following two lines are necessary,
144  // but they will not hurt anyone
145  m_dbl_click_timer->Stop();
146  delete m_dbl_click_timer;
147 
148  m_config->Write( FP_CHOOSER_WIDTH_KEY, GetSize().x );
149  m_config->Write( FP_CHOOSER_HEIGHT_KEY, GetSize().y );
150 
151  m_config->Write( FP_CHOOSER_HSASH, m_hsplitter->GetSashPosition() );
152 
153  if( m_vsplitter )
154  m_config->Write( FP_CHOOSER_VSASH, m_vsplitter->GetSashPosition() );
155 }
156 
157 
158 wxPanel* DIALOG_CHOOSE_FOOTPRINT::ConstructRightPanel( wxWindow* aParent )
159 {
160  auto panel = new wxPanel( aParent );
161  auto sizer = new wxBoxSizer( wxVERTICAL );
162 
164  sizer->Add( m_preview_ctrl, 1, wxEXPAND | wxTOP | wxRIGHT, 5 );
165 
166  panel->SetSizer( sizer );
167  panel->Layout();
168  sizer->Fit( panel );
169 
170  return panel;
171 }
172 
173 
175 {
176  return m_tree->GetSelectedLibId();
177 }
178 
179 
180 void DIALOG_CHOOSE_FOOTPRINT::OnUseBrowser( wxCommandEvent& aEvent )
181 {
183  EndQuasiModal( wxID_OK );
184 }
185 
186 
187 void DIALOG_CHOOSE_FOOTPRINT::OnCloseTimer( wxTimerEvent& aEvent )
188 {
189  // Hack handler because of eaten MouseUp event. See
190  // DIALOG_CHOOSE_FOOTPRINT::OnComponentSelected for the beginning
191  // of this spaghetti noodle.
192 
193  auto state = wxGetMouseState();
194 
195  if( state.LeftIsDown() )
196  {
197  // Mouse hasn't been raised yet, so fire the timer again. Otherwise the
198  // purpose of this timer is defeated.
200  }
201  else
202  {
203  EndQuasiModal( wxID_OK );
204  }
205 }
206 
207 
209 {
211  return;
212 
213  LIB_ID lib_id = m_tree->GetSelectedLibId();
214 
215  if( !lib_id.IsValid() )
216  {
217  m_preview_ctrl->SetStatusText( _( "No footprint selected" ) );
218  }
219  else
220  {
222  m_preview_ctrl->CacheFootprint( lib_id );
223  m_preview_ctrl->DisplayFootprint( lib_id );
224  }
225 }
226 
227 
228 void DIALOG_CHOOSE_FOOTPRINT::OnComponentSelected( wxCommandEvent& aEvent )
229 {
230  if( m_tree->GetSelectedLibId().IsValid() )
231  {
232  // Got a selection. We can't just end the modal dialog here, because
233  // wx leaks some events back to the parent window (in particular, the
234  // MouseUp following a double click).
235  //
236  // NOW, here's where it gets really fun. wxTreeListCtrl eats MouseUp.
237  // This isn't really feasible to bypass without a fully custom
238  // wxDataViewCtrl implementation, and even then might not be fully
239  // possible (docs are vague). To get around this, we use a one-shot
240  // timer to schedule the dialog close.
241  //
242  // See DIALOG_CHOOSE_FOOTPRINT::OnCloseTimer for the other end of this
243  // spaghetti noodle.
245  }
246 }
#define FP_CHOOSER_VSASH
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
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.
wxConfigBase * KifaceSettings() const
Definition: kiface_i.h:103
Class DIALOG_SHIM may sit in the inheritance tree between wxDialog and any class written by wxFormBui...
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
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:118
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Definition: kicad.cpp:51
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:145
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)
#define _(s)
#define FP_CHOOSER_HEIGHT_KEY
int VertPixelsFromDU(int y)
Convert an integer number of dialog units to pixels, vertically.
#define FP_CHOOSER_WIDTH_KEY
void EndQuasiModal(int retCode)
#define FP_CHOOSER_HSASH
wxPanel * ConstructRightPanel(wxWindow *aParent)
void CacheFootprint(const LIB_ID &aFPID)
Preload a footprint into the cache.
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.
class 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