KiCad PCB EDA Suite
Loading...
Searching...
No Matches
panel_symbol_chooser.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 <[email protected]>
5 * Copyright The 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, see <https://www.gnu.org/licenses/>.
19 */
20
22
23#include <pgm_base.h>
25#include <kiface_base.h>
26#include <sch_base_frame.h>
27#include <project_sch.h>
29#include <widgets/lib_tree.h>
35#include <eeschema_settings.h>
37#include <symbol_library_common.h> // For SYMBOL_LIBRARY_FILTER
38#include <algorithm>
39#include <wx/button.h>
40#include <wx/clipbrd.h>
41#include <wx/display.h>
42#include <wx/panel.h>
43#include <wx/sizer.h>
44#include <wx/splitter.h>
45#include <wx/timer.h>
46#include <wx/wxhtml.h>
47#include <wx/log.h>
48
49
53
55 const SYMBOL_LIBRARY_FILTER* aFilter,
56 std::vector<PICKED_SYMBOL>& aHistoryList,
57 std::vector<PICKED_SYMBOL>& aAlreadyPlaced,
58 bool aAllowFieldEdits, bool aShowFootprints, bool& aCancelled,
59 std::function<void()> aAcceptHandler,
60 std::function<void()> aEscapeHandler ) :
61 wxPanel( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize ),
62 m_symbol_preview( nullptr ),
63 m_hsplitter( nullptr ),
64 m_vsplitter( nullptr ),
65 m_fp_sel_ctrl( nullptr ),
66 m_fp_preview( nullptr ),
67 m_tree( nullptr ),
68 m_details( nullptr ),
69 m_acceptHandler( std::move( aAcceptHandler ) ),
70 m_escapeHandler( std::move( aEscapeHandler ) ),
71 m_showPower( false ),
72 m_allow_field_edits( aAllowFieldEdits ),
73 m_show_footprints( aShowFootprints )
74{
75 m_frame = aFrame;
76
79 PROJECT_FILE& project = m_frame->Prj().GetProjectFile();
80
81 // Make sure settings are loaded before we start running multi-threaded symbol loaders
84
86 SYMBOL_TREE_MODEL_ADAPTER* adapter = static_cast<SYMBOL_TREE_MODEL_ADAPTER*>( m_adapter.get() );
87
88 if( aFilter )
89 {
90 const wxArrayString& liblist = aFilter->GetAllowedLibList();
91
92 for( const wxString& nickname : liblist )
93 {
94 if( libmgr->HasLibrary( nickname, true ) )
95 {
96 bool pinned = alg::contains( session.pinned_symbol_libs, nickname )
97 || alg::contains( project.m_PinnedSymbolLibs, nickname );
98
99 std::optional<LIBRARY_TABLE_ROW*> row = libmgr->GetRow( nickname );
100
101 if( row.has_value() && !row.value()->Hidden() )
102 adapter->AddLibrary( nickname, pinned );
103 }
104 }
105
106 adapter->AssignIntrinsicRanks();
107
108 if( aFilter->GetFilterPowerSymbols() )
109 {
110 static std::function<bool( LIB_TREE_NODE& )> powerFilter =
111 []( LIB_TREE_NODE& aNode ) -> bool
112 {
113 return aNode.m_IsPower;
114 };
115
116 adapter->SetFilter( &powerFilter );
117
118 m_showPower = true;
119 m_show_footprints = false;
120 }
121 }
122
123 std::vector<LIB_SYMBOL> history_list_storage;
124 std::vector<LIB_TREE_ITEM*> history_list;
125 std::vector<LIB_SYMBOL> already_placed_storage;
126 std::vector<LIB_TREE_ITEM*> already_placed;
127
128 // Lambda to encapsulate the common logic
129 auto processList =
130 [&]( const std::vector<PICKED_SYMBOL>& inputList,
131 std::vector<LIB_SYMBOL>& storageList,
132 std::vector<LIB_TREE_ITEM*>& resultList )
133 {
134 storageList.reserve( inputList.size() );
135
136 for( const PICKED_SYMBOL& i : inputList )
137 {
138 LIB_SYMBOL* symbol = m_frame->GetLibSymbol( i.LibId );
139
140 if( symbol )
141 {
142 storageList.emplace_back( *symbol );
143
144 for( const auto& [fieldType, fieldValue] : i.Fields )
145 {
146 SCH_FIELD* field = storageList.back().GetField( fieldType );
147
148 if( field )
149 field->SetText( fieldValue );
150 }
151
152 resultList.push_back( &storageList.back() );
153 }
154 }
155 };
156
157 // Sort the already placed list since it is potentially from multiple sessions,
158 // but not the most recent list since we want this listed by most recent usage.
159 std::sort( aAlreadyPlaced.begin(), aAlreadyPlaced.end(),
160 []( PICKED_SYMBOL const& a, PICKED_SYMBOL const& b )
161 {
162 return a.LibId.GetLibItemName() < b.LibId.GetLibItemName();
163 } );
164
165 processList( aHistoryList, history_list_storage, history_list );
166 processList( aAlreadyPlaced, already_placed_storage, already_placed );
167
168 adapter->DoAddLibrary( wxT( "-- " ) + _( "Recently Used" ) + wxT( " --" ), wxEmptyString,
169 history_list, false, true )
170 .m_IsRecentlyUsedGroup = true;
171
172 if( !aHistoryList.empty() )
173 adapter->SetPreselectNode( aHistoryList[0].LibId, aHistoryList[0].Unit );
174
175 adapter->DoAddLibrary( wxT( "-- " ) + _( "Already Placed" ) + wxT( " --" ), wxEmptyString,
176 already_placed, false, true )
178
179 adapter->AddLibraries( m_frame );
180
181 // -------------------------------------------------------------------------------------
182 // Construct the actual panel
183 //
184
185 wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
186
187 // Use a slightly different layout, with a details pane spanning the entire window,
188 // if we're not showing footprints.
190 {
191 m_hsplitter = new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
192 wxSP_LIVE_UPDATE | wxSP_NOBORDER | wxSP_3DSASH );
193
194 //Avoid the splitter window being assigned as the Parent to additional windows
195 m_hsplitter->SetExtraStyle( wxWS_EX_TRANSIENT );
196
197 sizer->Add( m_hsplitter, 1, wxEXPAND, 5 );
198 }
199 else
200 {
201 m_vsplitter = new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
202 wxSP_LIVE_UPDATE | wxSP_NOBORDER | wxSP_3DSASH );
203
204 m_hsplitter = new wxSplitterWindow( m_vsplitter, wxID_ANY, wxDefaultPosition, wxDefaultSize,
205 wxSP_LIVE_UPDATE | wxSP_NOBORDER | wxSP_3DSASH );
206
207 // Avoid the splitter window being assigned as the parent to additional windows.
208 m_vsplitter->SetExtraStyle( wxWS_EX_TRANSIENT );
209 m_hsplitter->SetExtraStyle( wxWS_EX_TRANSIENT );
210
211 wxPanel* detailsPanel = new wxPanel( m_vsplitter );
212 wxBoxSizer* detailsSizer = new wxBoxSizer( wxVERTICAL );
213 detailsPanel->SetSizer( detailsSizer );
214
215 m_details = new HTML_WINDOW( detailsPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize );
216 detailsSizer->Add( m_details, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
217 detailsPanel->Layout();
218 detailsSizer->Fit( detailsPanel );
219
220 m_vsplitter->SetSashGravity( 0.5 );
221 m_vsplitter->SetMinimumPaneSize( 20 );
222 m_vsplitter->SplitHorizontally( m_hsplitter, detailsPanel );
223
224 sizer->Add( m_vsplitter, 1, wxEXPAND | wxBOTTOM, 5 );
225 }
226
227 wxPanel* treePanel = new wxPanel( m_hsplitter );
228 wxBoxSizer* treeSizer = new wxBoxSizer( wxVERTICAL );
229 treePanel->SetSizer( treeSizer );
230
231 m_tree = new LIB_TREE( treePanel, m_showPower ? wxT( "power" ) : wxT( "symbols" ), m_adapter,
233
234 treeSizer->Add( m_tree, 1, wxALL | wxEXPAND, 5 );
235 treePanel->Layout();
236 treeSizer->Fit( treePanel );
237
238 m_adapter->FinishTreeInitialization();
239
240 if( m_showPower )
241 m_tree->SetSearchString( g_powerSearchString );
242 else
243 m_tree->SetSearchString( g_symbolSearchString );
244
245 m_hsplitter->SetSashGravity( 0.8 );
246 m_hsplitter->SetMinimumPaneSize( 20 );
247 m_hsplitter->SplitVertically( treePanel, constructRightPanel( m_hsplitter ) );
248
249 m_dbl_click_timer = new wxTimer( this );
250 m_open_libs_timer = new wxTimer( this );
251
252 SetSizer( sizer );
253
254 Layout();
255
256 Bind( wxEVT_TIMER, &PANEL_SYMBOL_CHOOSER::onCloseTimer, this, m_dbl_click_timer->GetId() );
257 Bind( wxEVT_TIMER, &PANEL_SYMBOL_CHOOSER::onOpenLibsTimer, this, m_open_libs_timer->GetId() );
258 Bind( EVT_LIBITEM_SELECTED, &PANEL_SYMBOL_CHOOSER::onSymbolSelected, this );
259 Bind( EVT_LIBITEM_CHOSEN, &PANEL_SYMBOL_CHOOSER::onSymbolChosen, this );
260 aFrame->Bind( wxEVT_MENU_OPEN, &PANEL_SYMBOL_CHOOSER::onMenuOpen, this );
261 aFrame->Bind( wxEVT_MENU_CLOSE, &PANEL_SYMBOL_CHOOSER::onMenuClose, this );
262
263 if( m_fp_sel_ctrl )
264 m_fp_sel_ctrl->Bind( EVT_FOOTPRINT_SELECTED, &PANEL_SYMBOL_CHOOSER::onFootprintSelected, this );
265
266 if( m_details )
267 m_details->Bind( wxEVT_CHAR_HOOK, &PANEL_SYMBOL_CHOOSER::OnDetailsCharHook, this );
268
269 // Open the user's previously opened libraries on timer expiration.
270 // This is done on a timer because we need a gross hack to keep GTK from garbling the
271 // display. Must be longer than the search debounce timer.
272 m_open_libs_timer->StartOnce( 300 );
273}
274
275
277{
278 m_frame->Unbind( wxEVT_MENU_OPEN, &PANEL_SYMBOL_CHOOSER::onMenuOpen, this );
279 m_frame->Unbind( wxEVT_MENU_CLOSE, &PANEL_SYMBOL_CHOOSER::onMenuClose, this );
280 Unbind( wxEVT_TIMER, &PANEL_SYMBOL_CHOOSER::onCloseTimer, this );
281 Unbind( EVT_LIBITEM_SELECTED, &PANEL_SYMBOL_CHOOSER::onSymbolSelected, this );
282 Unbind( EVT_LIBITEM_CHOSEN, &PANEL_SYMBOL_CHOOSER::onSymbolChosen, this );
283
284 // Stop the timer during destruction early to avoid potential race conditions (that do happen)
285 m_dbl_click_timer->Stop();
286 m_open_libs_timer->Stop();
287 delete m_dbl_click_timer;
288 delete m_open_libs_timer;
289
290 if( m_showPower )
291 g_powerSearchString = m_tree->GetSearchString();
292 else
293 g_symbolSearchString = m_tree->GetSearchString();
294
295 if( m_fp_sel_ctrl )
296 m_fp_sel_ctrl->Unbind( EVT_FOOTPRINT_SELECTED, &PANEL_SYMBOL_CHOOSER::onFootprintSelected, this );
297
298 if( m_details )
299 m_details->Unbind( wxEVT_CHAR_HOOK, &PANEL_SYMBOL_CHOOSER::OnDetailsCharHook, this );
300
301 if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() ) )
302 {
303 // Save any changes to column widths, etc.
304 m_adapter->SaveSettings();
305
306 cfg->m_SymChooserPanel.width = GetParent()->ToDIP( GetParent()->GetSize().x );
307 cfg->m_SymChooserPanel.height = GetParent()->ToDIP( GetParent()->GetSize().y );
308
309 cfg->m_SymChooserPanel.sash_pos_h = m_hsplitter->GetSashPosition();
310
311 if( m_vsplitter )
312 cfg->m_SymChooserPanel.sash_pos_v = m_vsplitter->GetSashPosition();
313
314 cfg->m_SymChooserPanel.sort_mode = m_tree->GetSortMode();
315 }
316
317 m_frame = nullptr;
318}
319
320
321void PANEL_SYMBOL_CHOOSER::onMenuOpen( wxMenuEvent& aEvent )
322{
323 m_tree->BlockPreview( true );
324 aEvent.Skip();
325}
326
327
328void PANEL_SYMBOL_CHOOSER::onMenuClose( wxMenuEvent& aEvent )
329{
330 m_tree->BlockPreview( false );
331 aEvent.Skip();
332}
333
334
335void PANEL_SYMBOL_CHOOSER::OnChar( wxKeyEvent& aEvent )
336{
337 if( aEvent.GetKeyCode() == WXK_ESCAPE )
338 {
339 wxObject* eventSource = aEvent.GetEventObject();
340
341 if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( eventSource ) )
342 {
343 // First escape cancels search string value
344 if( textCtrl->GetValue() == m_tree->GetSearchString()
345 && !m_tree->GetSearchString().IsEmpty() )
346 {
347 m_tree->SetSearchString( wxEmptyString );
348 return;
349 }
350 }
351
353 }
354 else
355 {
356 aEvent.Skip();
357 }
358}
359
360
361wxPanel* PANEL_SYMBOL_CHOOSER::constructRightPanel( wxWindow* aParent )
362{
364
365 if( m_frame->GetCanvas() )
366 backend = m_frame->GetCanvas()->GetBackend();
367 else if( COMMON_SETTINGS* cfg = Pgm().GetCommonSettings() )
368 backend = static_cast<EDA_DRAW_PANEL_GAL::GAL_TYPE>( cfg->m_Graphics.canvas_type );
369
370 wxPanel* panel = new wxPanel( aParent );
371 wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
372
373 m_symbol_preview = new SYMBOL_PREVIEW_WIDGET( panel, &m_frame->Kiway(), true, backend );
374 m_symbol_preview->SetLayoutDirection( wxLayout_LeftToRight );
375
377 {
378 sizer->Add( m_symbol_preview, 11, wxEXPAND | wxALL, 5 );
379
381 sizer->Add( m_fp_sel_ctrl, 0, wxEXPAND | wxLEFT | wxRIGHT, 5 );
382
383 m_fp_preview = new FOOTPRINT_PREVIEW_WIDGET( panel, m_frame->Kiway() );
384 m_fp_preview->SetUserUnits( m_frame->GetUserUnits() );
385
386 if( m_fp_preview )
387 sizer->Add( m_fp_preview, 10, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
388 }
389 else
390 {
391 sizer->Add( m_symbol_preview, 1, wxEXPAND | wxALL, 5 );
392 }
393
394 panel->SetSizer( sizer );
395 panel->Layout();
396 sizer->Fit( panel );
397
398 return panel;
399}
400
401
403{
404 if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() ) )
405 {
406 auto horizPixelsFromDU =
407 [&]( int x ) -> int
408 {
409 wxSize sz( x, 0 );
410 return GetParent()->ConvertDialogToPixels( sz ).x;
411 };
412
413 EESCHEMA_SETTINGS::PANEL_SYM_CHOOSER& panelCfg = cfg->m_SymChooserPanel;
414
415 // The persisted size is stored in DIP so it is independent of the monitor it was saved
416 // on. Restoring raw pixels would scale the window by the DPI ratio when reopened on a
417 // different-scale display, producing a window that spills across monitors.
418 int w = panelCfg.width > 40 ? GetParent()->FromDIP( panelCfg.width ) : horizPixelsFromDU( 440 );
419 int h = panelCfg.height > 40 ? GetParent()->FromDIP( panelCfg.height ) : horizPixelsFromDU( 340 );
420
421 // Cap to the work area so a stale pre-DIP setting cannot reopen the window across monitors.
422 if( int display = wxDisplay::GetFromWindow( GetParent() ); display != wxNOT_FOUND )
423 {
424 wxRect workArea = wxDisplay( display ).GetClientArea();
425 w = std::min( w, workArea.GetWidth() );
426 h = std::min( h, workArea.GetHeight() );
427 }
428
429 GetParent()->SetSize( wxSize( w, h ) );
430 GetParent()->Layout();
431
432 // We specify the width of the right window (m_symbol_view_panel), because specify
433 // the width of the left window does not work as expected when SetSashGravity() is called
434
435 if( panelCfg.sash_pos_h < 0 )
436 panelCfg.sash_pos_h = horizPixelsFromDU( 220 );
437
438 if( panelCfg.sash_pos_v < 0 )
439 panelCfg.sash_pos_v = horizPixelsFromDU( 230 );
440
441 m_hsplitter->SetSashPosition( panelCfg.sash_pos_h );
442
443 if( m_vsplitter )
444 m_vsplitter->SetSashPosition( panelCfg.sash_pos_v );
445
446 m_adapter->SetSortMode( (LIB_TREE_MODEL_ADAPTER::SORT_MODE) panelCfg.sort_mode );
447 }
448
449 if( m_fp_preview && m_fp_preview->IsInitialized() )
450 {
451 // This hides the GAL panel and shows the status label
452 m_fp_preview->SetStatusText( wxEmptyString );
453 }
454
455 if( m_fp_sel_ctrl )
456 m_fp_sel_ctrl->Load( m_frame->Kiway(), m_frame->Prj() );
457}
458
459
461{
462 if( m_details && e.GetKeyCode() == 'C' && e.ControlDown() &&
463 !e.AltDown() && !e.ShiftDown() && !e.MetaDown() )
464 {
465 wxString txt = m_details->SelectionToText();
466 wxLogNull doNotLog; // disable logging of failed clipboard actions
467
468 if( wxTheClipboard->Open() )
469 {
470 wxTheClipboard->SetData( new wxTextDataObject( txt ) );
471 wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
472 wxTheClipboard->Close();
473 }
474 }
475 else
476 {
477 e.Skip();
478 }
479}
480
481
483{
484 m_adapter->SetPreselectNode( aPreselect, 0 );
485
486 if( m_tree && aPreselect.IsValid() )
487 m_tree->SelectLibId( aPreselect );
488}
489
490
492{
493 return m_tree->GetSelectedLibId( aUnit );
494}
495
496
498{
499 m_symbol_preview->GetCanvas()->SetEvtHandlerEnabled( false );
500 m_symbol_preview->GetCanvas()->StopDrawing();
501
502 if( m_fp_preview )
503 {
504 m_fp_preview->GetPreviewPanel()->GetCanvas()->SetEvtHandlerEnabled( false );
505 m_fp_preview->GetPreviewPanel()->GetCanvas()->StopDrawing();
506 }
507}
508
509
510void PANEL_SYMBOL_CHOOSER::onCloseTimer( wxTimerEvent& aEvent )
511{
512 // Hack because of eaten MouseUp event. See PANEL_SYMBOL_CHOOSER::onSymbolChosen
513 // for the beginning of this spaghetti noodle.
514
515 wxMouseState state = wxGetMouseState();
516
517 if( state.LeftIsDown() )
518 {
519 // Mouse hasn't been raised yet, so fire the timer again. Otherwise the
520 // purpose of this timer is defeated.
522 }
523 else
524 {
526 }
527}
528
529
530void PANEL_SYMBOL_CHOOSER::onOpenLibsTimer( wxTimerEvent& aEvent )
531{
532 if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() ) )
533 m_adapter->OpenLibs( cfg->m_LibTree.open_libs );
534}
535
536
538{
539 if( !m_fp_preview || !m_fp_preview->IsInitialized() )
540 return;
541
542 LIB_SYMBOL* symbol = nullptr;
543
544 try
545 {
546 symbol = PROJECT_SCH::SymbolLibAdapter( &m_frame->Prj() )->LoadSymbol( aLibId );
547 }
548 catch( const IO_ERROR& ioe )
549 {
550 wxLogError( _( "Error loading symbol %s from library '%s'." ) + wxS( "\n%s" ),
551 aLibId.GetLibItemName().wx_str(),
552 aLibId.GetLibNickname().wx_str(),
553 ioe.What() );
554 }
555
556 if( !symbol )
557 return;
558
559 SCH_FIELD* fp_field = symbol->GetField( FIELD_T::FOOTPRINT );
560 wxString fp_name = fp_field ? fp_field->GetFullText() : wxString( "" );
561
562 showFootprint( fp_name );
563}
564
565
566void PANEL_SYMBOL_CHOOSER::showFootprint( wxString const& aFootprint )
567{
568 if( !m_fp_preview || !m_fp_preview->IsInitialized() )
569 return;
570
571 if( aFootprint == wxEmptyString )
572 {
573 m_fp_preview->SetStatusText( _( "No footprint specified" ) );
574 }
575 else
576 {
577 LIB_ID lib_id;
578
579 if( lib_id.Parse( aFootprint ) == -1 && lib_id.IsValid() )
580 {
581 m_fp_preview->ClearStatus();
582 m_fp_preview->DisplayFootprint( lib_id );
583 }
584 else
585 {
586 m_fp_preview->SetStatusText( _( "Invalid footprint specified" ) );
587 }
588 }
589}
590
591
593{
594 if( !m_fp_sel_ctrl )
595 return;
596
597 m_fp_sel_ctrl->ClearFilters();
598
599 LIB_SYMBOL* symbol = nullptr;
600
601 if( aLibId.IsValid() )
602 {
603 try
604 {
605 symbol = PROJECT_SCH::SymbolLibAdapter( &m_frame->Prj() )->LoadSymbol( aLibId );
606 }
607 catch( const IO_ERROR& ioe )
608 {
609 wxLogError( _( "Error loading symbol %s from library '%s'." ) + wxS( "\n%s" ),
610 aLibId.GetLibItemName().wx_str(),
611 aLibId.GetLibNickname().wx_str(),
612 ioe.What() );
613 }
614 }
615
616 if( symbol != nullptr )
617 {
618 int pinCount = symbol->GetGraphicalPins( 0 /* all units */, 1 /* single bodyStyle */ ).size();
619 SCH_FIELD* fp_field = symbol->GetField( FIELD_T::FOOTPRINT );
620 wxString fp_name = fp_field ? fp_field->GetFullText() : wxString( "" );
621
622 // Explicitly associated footprints (issue #2282) are listed ahead of the glob matches in
623 // written order and bypass the pin-count filter; a mapped EP/NC footprint legally has more
624 // pads than the symbol has pins.
625 for( const ASSOCIATED_FOOTPRINT& assoc : symbol->GetEffectiveAssociatedFootprints() )
626 m_fp_sel_ctrl->AddAlwaysIncludedFootprint( assoc.m_FootprintLibId );
627
628 m_fp_sel_ctrl->FilterByPinCount( pinCount );
629 m_fp_sel_ctrl->FilterByFootprintFilters( symbol->GetFPFilters(), true );
630 m_fp_sel_ctrl->SetDefaultFootprint( fp_name );
631 m_fp_sel_ctrl->UpdateList();
632 m_fp_sel_ctrl->Enable();
633 }
634 else
635 {
636 m_fp_sel_ctrl->UpdateList();
637 m_fp_sel_ctrl->Disable();
638 }
639}
640
641
642void PANEL_SYMBOL_CHOOSER::onFootprintSelected( wxCommandEvent& aEvent )
643{
644 m_fp_override = aEvent.GetString();
645
646 std::erase_if( m_field_edits, []( std::pair<FIELD_T, wxString> const& i )
647 {
648 return i.first == FIELD_T::FOOTPRINT;
649 } );
650
651 m_field_edits.emplace_back( std::make_pair( FIELD_T::FOOTPRINT, m_fp_override ) );
652
654}
655
656
657void PANEL_SYMBOL_CHOOSER::onSymbolSelected( wxCommandEvent& aEvent )
658{
659 LIB_TREE_NODE* node = m_tree->GetCurrentTreeNode();
660
661 if( node && node->m_LibId.IsValid() )
662 {
663 m_symbol_preview->DisplaySymbol( node->m_LibId, node->m_Unit );
664
665 if( !node->m_Footprint.IsEmpty() )
666 showFootprint( node->m_Footprint );
667 else
668 showFootprintFor( node->m_LibId );
669
671 }
672 else
673 {
674 m_symbol_preview->SetStatusText( _( "No symbol selected" ) );
675
676 if( m_fp_preview && m_fp_preview->IsInitialized() )
677 m_fp_preview->SetStatusText( wxEmptyString );
678
680 }
681}
682
683
684void PANEL_SYMBOL_CHOOSER::onSymbolChosen( wxCommandEvent& aEvent )
685{
686 if( m_tree->GetSelectedLibId().IsValid() )
687 {
688 // Got a selection. We can't just end the modal dialog here, because wx leaks some events
689 // back to the parent window (in particular, the MouseUp following a double click).
690 //
691 // NOW, here's where it gets really fun. wxTreeListCtrl eats MouseUp. This isn't really
692 // feasible to bypass without a fully custom wxDataViewCtrl implementation, and even then
693 // might not be fully possible (docs are vague). To get around this, we use a one-shot
694 // timer to schedule the dialog close.
695 //
696 // See PANEL_SYMBOL_CHOOSER::onCloseTimer for the other end of this spaghetti noodle.
698 }
699}
700
701
703{
704 LIB_ID savedSelection = m_tree->GetSelectedLibId();
705 m_tree->Regenerate( true );
706
707 if( savedSelection.IsValid() )
708 m_tree->CenterLibId( savedSelection );
709}
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
@ GAL_TYPE_OPENGL
OpenGL implementation.
Add dark theme support to wxHtmlWindow.
Definition html_window.h:31
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library tables.
std::optional< LIBRARY_TABLE_ROW * > GetRow(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
Like LIBRARY_MANAGER::GetRow but filtered to the LIBRARY_TABLE_TYPE of this adapter.
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition lib_id.cpp:65
bool IsValid() const
Check if this LID_ID is valid.
Definition lib_id.h:168
const UTF8 & GetLibItemName() const
Definition lib_id.h:98
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:83
Define a library symbol object.
Definition lib_symbol.h:80
std::vector< const SCH_PIN * > GetGraphicalPins(int aUnit=0, int aBodyStyle=0) const
Graphical pins: Return schematic pin objects as drawn (unexpanded), filtered by unit/body.
const std::vector< ASSOCIATED_FOOTPRINT > & GetEffectiveAssociatedFootprints() const
Definition lib_symbol.h:256
SCH_FIELD * GetField(const wxString &aFieldName)
Find a field within this symbol matching aFieldName; return nullptr if not found.
wxArrayString GetFPFilters() const
Definition lib_symbol.h:208
void SetPreselectNode(const LIB_ID &aLibId, int aUnit)
Set the symbol name to be selected if there are no search results.
void AssignIntrinsicRanks()
Sort the tree and assign ranks after adding libraries.
LIB_TREE_NODE_LIBRARY & DoAddLibrary(const wxString &aNodeName, const wxString &aDesc, const std::vector< LIB_TREE_ITEM * > &aItemList, bool pinned, bool presorted)
Add the given list of symbols by alias.
void SetFilter(std::function< bool(LIB_TREE_NODE &aNode)> *aFilter)
Set the filter.
Model class in the component selector Model-View-Adapter (mediated MVC) architecture.
bool m_IsAlreadyPlacedGroup
wxString m_Footprint
Widget displaying a tree of symbols with optional search text control and description panel.
Definition lib_tree.h:46
@ ALL_WIDGETS
Definition lib_tree.h:55
SYMBOL_PREVIEW_WIDGET * m_symbol_preview
PANEL_SYMBOL_CHOOSER(SCH_BASE_FRAME *aFrame, wxWindow *aParent, const SYMBOL_LIBRARY_FILTER *aFilter, std::vector< PICKED_SYMBOL > &aHistoryList, std::vector< PICKED_SYMBOL > &aAlreadyPlaced, bool aAllowFieldEdits, bool aShowFootprints, bool &aCancelled, std::function< void()> aAcceptHandler, std::function< void()> aEscapeHandler)
Create dialog to choose symbol.
void onSymbolSelected(wxCommandEvent &aEvent)
void showFootprintFor(const LIB_ID &aLibId)
Look up the footprint for a given symbol specified in the LIB_ID and display it.
void onMenuClose(wxMenuEvent &aEvent)
wxSplitterWindow * m_hsplitter
FOOTPRINT_SELECT_WIDGET * m_fp_sel_ctrl
std::function< void()> m_escapeHandler
void OnDetailsCharHook(wxKeyEvent &aEvt)
static wxString g_symbolSearchString
void onMenuOpen(wxMenuEvent &aEvent)
Handle parent frame menu events to block tree preview.
std::vector< std::pair< FIELD_T, wxString > > m_field_edits
void onCloseTimer(wxTimerEvent &aEvent)
wxSplitterWindow * m_vsplitter
static SCH_BASE_FRAME * m_frame
void showFootprint(const wxString &aFootprint)
Display the given footprint by name.
void populateFootprintSelector(const LIB_ID &aLibId)
Populate the footprint selector for a given alias.
void onOpenLibsTimer(wxTimerEvent &aEvent)
void onFootprintSelected(wxCommandEvent &aEvent)
static wxString g_powerSearchString
void OnChar(wxKeyEvent &aEvent)
void SetPreselect(const LIB_ID &aPreselect)
std::function< void()> m_acceptHandler
static constexpr int DBLCLICK_DELAY
FOOTPRINT_PREVIEW_WIDGET * m_fp_preview
wxObjectDataPtr< LIB_TREE_MODEL_ADAPTER > m_adapter
LIB_ID GetSelectedLibId(int *aUnit=nullptr) const
To be called after this dialog returns from ShowModal().
void onSymbolChosen(wxCommandEvent &aEvent)
Handle the selection of an item.
wxPanel * constructRightPanel(wxWindow *aParent)
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition pgm_base.cpp:553
The backing store for a PROJECT, in JSON format.
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
A shim class between EDA_DRAW_FRAME and several derived classes: SYMBOL_EDIT_FRAME,...
wxString GetFullText(int unit=1) const
Return the text of a field.
void SetText(const wxString &aText) override
An interface to the global shared library manager that is schematic-specific and linked to one projec...
LIB_SYMBOL * LoadSymbol(const wxString &aNickname, const wxString &aName)
Load a LIB_SYMBOL having aName from the library given by aNickname.
Helper object to filter a list of libraries.
const wxArrayString & GetAllowedLibList() const
void AddLibraries(SCH_BASE_FRAME *aFrame)
Add all the libraries in a SYMBOL_LIB_TABLE to the model.
static wxObjectDataPtr< LIB_TREE_MODEL_ADAPTER > Create(SCH_BASE_FRAME *aParent, SYMBOL_LIBRARY_ADAPTER *aLibs)
Factory function: create a model adapter in a reference-counting container.
void AddLibrary(wxString const &aLibNickname, bool pinned)
wxString wx_str() const
Definition utf8.cpp:41
#define _(s)
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:96
STL namespace.
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
T * GetAppSettings(const char *aFilename)
A first-class footprint choice on a LIB_SYMBOL, tied to a named pin map.
Definition pin_map.h:158
std::vector< wxString > pinned_symbol_libs
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".