KiCad PCB EDA Suite
Loading...
Searching...
No Matches
panel_toolbar_customization.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
25
26#include <bitmaps.h>
28#include <tool/actions.h>
33
34#include <magic_enum.hpp>
35#include <wx/listctrl.h>
36#include <wx/menu.h>
37#include <widgets/ui_common.h>
38
39// Simple IDs for the split button menu
40enum
41{
42 ID_SEPARATOR_MENU = ( wxID_HIGHEST + 5 ),
45};
46
47
48static std::map<TOOLBAR_LOC, wxString> s_toolbarNameMap = {
49 { TOOLBAR_LOC::LEFT, _( "Left" ) },
50 { TOOLBAR_LOC::RIGHT, _( "Right" ) },
51 { TOOLBAR_LOC::TOP_MAIN, _( "Top main" ) },
52 { TOOLBAR_LOC::TOP_AUX, _( "Top auxiliary" ) }
53};
54
55
56class TOOLBAR_TREE_ITEM_DATA : public wxTreeItemData
57{
58public:
60 m_type( TOOLBAR_ITEM_TYPE::SEPARATOR ), // Init m_type to something
61 m_action( nullptr ),
62 m_control( nullptr ),
63 m_size( 0 )
64 { }
65
67 m_type( aType ),
68 m_action( nullptr ),
69 m_control( nullptr ),
70 m_size( 0 )
71 { }
72
74 m_type( aType ),
75 m_action( nullptr ),
76 m_control( nullptr ),
77 m_size( aSize )
78 {
79 wxASSERT( aType == TOOLBAR_ITEM_TYPE::SPACER );
80 }
81
82 TOOLBAR_TREE_ITEM_DATA( TOOLBAR_ITEM_TYPE aType, wxString aName ) :
83 m_type( aType ),
84 m_action( nullptr ),
85 m_control( nullptr ),
86 m_size( 0 ),
87 m_name( aName )
88 {
89 wxASSERT( aType == TOOLBAR_ITEM_TYPE::CONTROL
90 || aType == TOOLBAR_ITEM_TYPE::TB_GROUP );
91 }
92
93 void SetAction( TOOL_ACTION* aAction ) { m_action = aAction; }
95 {
96 wxASSERT( m_type == TOOLBAR_ITEM_TYPE::TOOL );
97 return m_action;
98 }
99
100 void SetControl( ACTION_TOOLBAR_CONTROL* aControl ) { m_control = aControl; }
102 {
103 wxASSERT( m_type == TOOLBAR_ITEM_TYPE::CONTROL );
104 return m_control;
105 }
106
107 void SetName( const wxString& aName ) { m_name = aName; }
108 const wxString& GetName() const { return m_name; }
109
110 void SetSize( int aSize ) { m_size = aSize; }
111 int GetSize() const { return m_size; }
112
113 TOOLBAR_ITEM_TYPE GetType() const { return m_type; }
114
115private:
116 // Item type
118
119 // Tool properties (can be one or the other, but never both)
122
123 // Spacer properties
125
126 // Group/control properties
127 wxString m_name;
128};
129
130
132 TOOLBAR_SETTINGS* aTbSettings, FRAME_T aActionContext,
133 const std::vector<TOOL_ACTION*>& aTools,
134 const std::vector<ACTION_TOOLBAR_CONTROL*>& aControls ) :
136 m_appSettings( aCfg ),
137 m_appTbSettings( aTbSettings ),
139 m_actionContext( aActionContext )
140{
141 // Copy the tools and controls into the internal maps
142 for( auto& tool : aTools )
143 m_availableTools.emplace( tool->GetName(), tool );
144
145 for( auto& control : aControls )
146 m_availableControls.emplace( control->GetName(), control );
147
148 // Configure the Ui elements
153
154 m_insertButton->SetLabel( _( "Insert Separator" ) );
155 //m_insertButton->SetWidthPadding( 4 );
156
157 // Populate the browse library options
158 wxMenu* insertMenu = m_insertButton->GetSplitButtonMenu();
159
160 insertMenu->Append( ID_SPACER_MENU, _( "Insert Spacer" ) );
161 insertMenu->Append( ID_GROUP_MENU, _( "Insert Group" ) );
162
163 insertMenu->Bind( wxEVT_COMMAND_MENU_SELECTED, &PANEL_TOOLBAR_CUSTOMIZATION::onSpacerPress,
164 this, ID_SPACER_MENU );
165 insertMenu->Bind( wxEVT_COMMAND_MENU_SELECTED, &PANEL_TOOLBAR_CUSTOMIZATION::onGroupPress,
166 this, ID_GROUP_MENU );
167
168 // This is the button only press for the browse button instead of the menu
170
171 m_actionFilter->ShowSearchButton( false );
172 m_actionFilter->ShowCancelButton( true );
173 m_actionFilter->SetDescriptiveText( _( "Filter actions" ) );
174
175#ifdef __WXGTK__
176 m_actionFilter->SetMinSize( wxSize( -1, GetTextExtent( wxT( "qb" ) ).y + 10 ) );
177#endif
178
180 m_actionFilter->Bind( wxEVT_SEARCHCTRL_CANCEL_BTN,
183 m_actionsList->Bind( wxEVT_LEAVE_WINDOW, &PANEL_TOOLBAR_CUSTOMIZATION::onActionListMouseMove, this );
184
185 // TODO (ISM): Enable draging
186 m_btnToolMoveDown->Enable( false );
187 m_btnToolMoveUp->Enable( false );
188}
189
190
199
200
202{
203 const std::string& name = aAction.GetName();
204
205 auto hasPrefix = [&]( const char* aPrefix ) -> bool
206 {
207 return name.rfind( aPrefix, 0 ) == 0;
208 };
209
211 {
212 if( hasPrefix( "3DViewer." ) )
213 return true;
214
215 return name == ACTIONS::zoomRedraw.GetName() || name == ACTIONS::zoomInCenter.GetName()
216 || name == ACTIONS::zoomOutCenter.GetName() || name == ACTIONS::zoomFitScreen.GetName();
217 }
218
219 if( hasPrefix( "common." ) )
220 return true;
221
222 switch( m_actionContext )
223 {
224 case FRAME_PCB_EDITOR:
226 case FRAME_FOOTPRINT_VIEWER: return hasPrefix( "pcbnew." );
227
228 case FRAME_SCH:
230 case FRAME_SCH_VIEWER:
231 case FRAME_SIMULATOR: return hasPrefix( "eeschema." );
232
233 case FRAME_GERBER: return hasPrefix( "gerbview." );
234
235 case FRAME_PL_EDITOR: return hasPrefix( "plEditor." );
236
237 default: return false;
238 }
239}
240
241
243{
244 m_toolbars.clear();
245 m_toolbarChoices.clear();
246
247 // Go over every toolbar and initialize things
248 for( auto& tb : magic_enum::enum_values<TOOLBAR_LOC>() )
249 {
250 // Create a shadow toolbar
251 auto tbConfig = m_appTbSettings->DefaultToolbarConfig( tb );
252
253 if( !tbConfig.has_value() )
254 continue;
255
256 m_toolbars[tb] = tbConfig.value();
257 m_toolbarChoices.push_back( tb );
258 }
259
260 if( !m_toolbarChoices.empty() )
261 {
262 m_tbChoice->SetSelection( 0 );
264 }
265
267}
268
269
271{
272 wxArrayString tbChoices;
273
274 m_toolbars.clear();
275 m_toolbarChoices.clear();
276
277 // Go over every toolbar and initialize things
278 for( auto& tb : magic_enum::enum_values<TOOLBAR_LOC>() )
279 {
280 // Create a shadow toolbar
281 auto tbConfig = m_appTbSettings->GetToolbarConfig( tb );
282
283 if( !tbConfig.has_value() )
284 continue;
285
286 m_toolbars.emplace( tb, tbConfig.value() );
287 m_toolbarChoices.push_back( tb );
288
289 // Setup the UI name
290 const auto& tbName = s_toolbarNameMap.find( tb );
291
292 wxASSERT_MSG( tbName != s_toolbarNameMap.end(),
293 wxString::Format( "Unknown toolbar: %s", magic_enum::enum_name( tb ) ) );
294
295 tbChoices.Add( tbName->second );
296 }
297
298 m_tbChoice->Set( tbChoices );
299
300 // Always populate the actions before the toolbars, that way the icons are available
302
303 if( !m_toolbarChoices.empty() )
304 {
305 m_tbChoice->SetSelection( 0 );
307 }
308
310
311 // Sync the enable/disable control
312 enableCustomControls( m_appSettings->m_CustomToolbars );
313 m_customToolbars->SetValue( m_appSettings->m_CustomToolbars );
314
315 return true;
316}
317
318
320{
321 m_appSettings->m_CustomToolbars = m_customToolbars->GetValue();
322
323 // Store the current toolbar
324 std::optional<TOOLBAR_CONFIGURATION> currentTb = parseToolbarTree();
325
326 if( currentTb.has_value() )
327 m_toolbars[m_currentToolbar] = currentTb.value();
328
329 // Write the shadow toolbars with changes back to the app toolbar settings
330 for( const auto& [loc, config] : m_toolbars )
331 m_appTbSettings->SetStoredToolbarConfig( loc, config );
332
333 return true;
334}
335
336
337std::optional<TOOLBAR_CONFIGURATION> PANEL_TOOLBAR_CUSTOMIZATION::parseToolbarTree()
338{
340
341 wxTreeItemId mainId;
342 wxTreeItemId rootId = m_toolbarTree->GetRootItem();
343 wxTreeItemIdValue mainCookie;
344
345 if( !rootId.IsOk() )
346 return std::nullopt;
347
348 mainId = m_toolbarTree->GetFirstChild( rootId, mainCookie );
349
350 while( mainId.IsOk() )
351 {
352 wxTreeItemData* treeData = m_toolbarTree->GetItemData( mainId );
353
354 TOOLBAR_TREE_ITEM_DATA* tbData = dynamic_cast<TOOLBAR_TREE_ITEM_DATA*>( treeData );
355
356 wxCHECK2( tbData, continue );
357
358 switch( tbData->GetType() )
359 {
361 config.AppendSpacer( tbData->GetSize() );
362 break;
363
365 config.AppendSeparator();
366 break;
367
369 config.AppendControl( tbData->GetControl()->GetName() );
370 break;
371
373 config.AppendAction( *( tbData->GetAction() ) );
374 break;
375
377 TOOLBAR_GROUP_CONFIG grpConfig( tbData->GetName() );
378
379 if( m_toolbarTree->ItemHasChildren( mainId ) )
380 {
381 wxTreeItemIdValue childCookie;
382 wxTreeItemId childId = m_toolbarTree->GetFirstChild( mainId, childCookie );
383
384 while( childId.IsOk() )
385 {
386 wxTreeItemData* childTreeData = m_toolbarTree->GetItemData( childId );
387
388 TOOLBAR_TREE_ITEM_DATA* childTbData = dynamic_cast<TOOLBAR_TREE_ITEM_DATA*>( childTreeData );
389
390 wxCHECK2( childTbData, break );
391
392 switch( childTbData->GetType() )
393 {
398 wxASSERT_MSG( false, "Invalid entry in a group" );
399 break;
400
402 grpConfig.AddAction( *( childTbData->GetAction() ) );
403 break;
404 }
405
406 childId = m_toolbarTree->GetNextChild( mainId, childCookie );
407 }
408 }
409
410 config.AppendGroup( grpConfig );
411 }
412
413 mainId = m_toolbarTree->GetNextChild( rootId, mainCookie );
414 }
415
416 return config;
417}
418
419
421{
422 m_toolbarTree->DeleteAllItems();
424
425 const auto& it = m_toolbars.find( m_currentToolbar );
426
427 if( it == m_toolbars.end() )
428 {
429 // Disable the controls and bail out - no toolbar here
430 enableToolbarControls( false );
431 return;
432 }
433
434 // Ensure the controls are enabled
435 enableToolbarControls( true );
436
437 TOOLBAR_CONFIGURATION toolbar = it->second;
438
439 wxTreeItemId root = m_toolbarTree->AddRoot( "Toolbar" );
440
441 for( const TOOLBAR_ITEM& item : toolbar.GetToolbarItems() )
442 {
443 switch( item.m_Type )
444 {
446 {
447 // Add a separator
449 m_toolbarTree->AppendItem( root, _( "Separator" ), -1, -1, sepTreeItem );
450 break;
451 }
452
454 {
455 // Add a spacer
457 spacerTreeItem->SetSize( item.m_Size );
458 m_toolbarTree->AppendItem( root, wxString::Format( _( "Spacer: %i" ), item.m_Size ), -1, -1,
459 spacerTreeItem );
460 break;
461 }
462
464 {
465 auto controlIter = m_availableControls.find( item.m_ControlName );
466
467 if( controlIter == m_availableControls.end() )
468 {
469 wxASSERT_MSG( false, wxString::Format( "Unable to find control %s", item.m_ControlName ) );
470 continue;
471 }
472
473 // Add a control
475 controlTreeItem->SetControl( controlIter->second );
476 m_toolbarTree->AppendItem( root, controlIter->second->GetUiName(), -1, -1, controlTreeItem );
477 break;
478 }
479
481 {
482 // Add a tool
483 auto toolIter = m_availableTools.find( item.m_ActionName );
484
485 if( toolIter == m_availableTools.end() )
486 {
487 wxASSERT_MSG( false, wxString::Format( "Unable to find tool %s", item.m_ActionName ) );
488 continue;
489 }
490
491 if( !isActionSupported( *toolIter->second ) )
492 continue;
493
495 toolTreeItem->SetAction( toolIter->second );
496
497 int imgIdx = -1;
498 auto imgMap = m_actionImageListMap.find( item.m_ActionName );
499
500 if( imgMap != m_actionImageListMap.end() )
501 imgIdx = imgMap->second;
502
503 m_toolbarTree->AppendItem( root, toolIter->second->GetFriendlyName(), imgIdx, -1, toolTreeItem );
504 break;
505 }
506
508 {
509 // Add a group of items to the toolbar
511 groupTreeItem->SetName( item.m_GroupName );
512
513 wxTreeItemId groupId = m_toolbarTree->AppendItem( root, item.m_GroupName, -1, -1, groupTreeItem );
514 bool haveVisibleGroupItems = false;
515
516 // Add the elements below the group
517 for( const TOOLBAR_ITEM& groupItem : item.m_GroupItems )
518 {
519 auto toolMap = m_availableTools.find( groupItem.m_ActionName );
520
521 if( toolMap == m_availableTools.end() )
522 {
523 wxASSERT_MSG( false, wxString::Format( "Unable to find group tool %s", groupItem.m_ActionName ) );
524 continue;
525 }
526
527 if( !isActionSupported( *toolMap->second ) )
528 continue;
529
531 toolTreeItem->SetAction( toolMap->second );
532
533 int imgIdx = -1;
534 auto imgMap = m_actionImageListMap.find( groupItem.m_ActionName );
535
536 if( imgMap != m_actionImageListMap.end() )
537 imgIdx = imgMap->second;
538
539 m_toolbarTree->AppendItem( groupId, toolMap->second->GetFriendlyName(), imgIdx, -1, toolTreeItem );
540
541 haveVisibleGroupItems = true;
542 }
543
544 if( !haveVisibleGroupItems )
545 m_toolbarTree->Delete( groupId );
546
547 break;
548 }
549 }
550 }
551
552 m_toolbarTree->ExpandAll();
553
554 wxTreeItemIdValue temp;
555 wxTreeItemId firstItem = m_toolbarTree->GetFirstChild( root, temp );
556
557 if( firstItem.IsOk() )
558 {
559 m_toolbarTree->SelectItem( firstItem );
560 m_toolbarTree->EnsureVisible( firstItem );
561 }
562}
563
564
566{
567 const int c_defSize = 24; // Default icon size for toolbar actions
568
569 // Clear all existing information for the actions
570 m_actionImageListMap.clear();
572 m_actionEntries.clear();
573
574 // Prep the control
575 m_actionsList->DeleteAllItems();
576 m_actionsList->DeleteAllColumns();
577 m_actionsList->InsertColumn( 0, "", wxLIST_FORMAT_LEFT, wxLIST_AUTOSIZE );
578
579 for( const auto& [k, tool] : m_availableTools )
580 {
581 if( !isActionSupported( *tool ) )
582 continue;
583
584 if( tool->CheckToolbarState( TOOLBAR_STATE::HIDDEN ) )
585 continue;
586
587 ACTION_LIST_ENTRY entry;
588 entry.label = tool->GetFriendlyName();
589 entry.tooltip = tool->GetDescription(); // falls back to tooltip if no description provided
590 entry.action = tool;
591 entry.search_text = entry.label.Upper() + wxS( " " ) + entry.tooltip.Upper();
592
593 if( tool->GetIcon() != BITMAPS::INVALID_BITMAP )
594 {
595 int imgIdx = m_actionImageBundleVector.size();
596 m_actionImageBundleVector.push_back( KiBitmapBundleDef( tool->GetIcon(), c_defSize ) );
597 m_actionImageListMap.emplace( tool->GetName(), imgIdx );
598 entry.image_index = imgIdx;
599 }
600
601 m_actionEntries.push_back( std::move( entry ) );
602 }
603
604 for( const auto& [k, control] : m_availableControls )
605 {
606 ACTION_LIST_ENTRY entry;
607 entry.label = control->GetUiName();
608 entry.tooltip = control->GetDescription();
609 entry.control = control;
610 entry.search_text = entry.label.Upper() + wxS( " " ) + control->GetDescription().Upper();
611 m_actionEntries.push_back( std::move( entry ) );
612 }
613
614 std::sort( m_actionEntries.begin(), m_actionEntries.end(),
615 []( const ACTION_LIST_ENTRY& a, const ACTION_LIST_ENTRY& b )
616 {
617 return a.label.CmpNoCase( b.label ) < 0;
618 } );
619
620 m_actionsList->SetSmallImages( m_actionImageBundleVector );
622}
623
624
626 const wxString& aFilter ) const
627{
628 if( aFilter.IsEmpty() )
629 return true;
630
631 return aEntry.search_text.Contains( aFilter.Upper() );
632}
633
634
636{
637 wxFont listFont = KIUI::GetInfoFont( this );
638 wxString filter = m_actionFilter->GetValue();
639
641 m_actionsList->UnsetToolTip();
642
643 m_actionsList->DeleteAllItems();
644
645 for( size_t idx = 0; idx < m_actionEntries.size(); ++idx )
646 {
647 const ACTION_LIST_ENTRY& entry = m_actionEntries[idx];
648
649 if( !actionMatchesFilter( entry, filter ) )
650 continue;
651
652 wxListItem item;
653 item.SetId( m_actionsList->GetItemCount() );
654 item.SetText( entry.label );
655 item.SetFont( listFont );
656 item.SetData( static_cast<long>( idx ) );
657 item.SetImage( entry.image_index );
658
659 m_actionsList->InsertItem( item );
660 }
661
662 if( m_actionsList->GetItemCount() > 0 )
663 m_actionsList->SetItemState( 0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
664
665 m_actionsList->SetColumnWidth( 0, wxLIST_AUTOSIZE );
666}
667
668
669void PANEL_TOOLBAR_CUSTOMIZATION::onGroupPress( wxCommandEvent& aEvent )
670{
672
673 wxTreeItemId newItem;
674 wxTreeItemId selItem = m_toolbarTree->GetSelection();
675
676 if( selItem.IsOk() )
677 {
678 // Can't add a group onto a group
679 wxTreeItemId parent = m_toolbarTree->GetItemParent( selItem );
680
681 if( parent.IsOk() )
682 {
683 wxTreeItemId secondParent = m_toolbarTree->GetItemParent( parent );
684
685 if( secondParent.IsOk() )
686 {
687 delete treeItem;
688 return;
689 }
690 }
691
692 newItem = m_toolbarTree->InsertItem( m_toolbarTree->GetRootItem(), selItem, treeItem->GetName(),
693 -1, -1, treeItem );
694 }
695 else
696 {
697 newItem = m_toolbarTree->AppendItem( m_toolbarTree->GetRootItem(), treeItem->GetName(), -1, -1,
698 treeItem );
699 }
700
701 if( newItem.IsOk() )
702 {
703 m_toolbarTree->SelectItem( newItem );
704 m_toolbarTree->EnsureVisible( newItem );
705 }
706}
707
708
709void PANEL_TOOLBAR_CUSTOMIZATION::onSpacerPress( wxCommandEvent& aEvent )
710{
712
713 wxString label = wxString::Format( "Spacer: %i", treeItem->GetSize() );
714
715 wxTreeItemId newItem;
716 wxTreeItemId selItem = m_toolbarTree->GetSelection();
717
718 if( selItem.IsOk() )
719 {
720 // Insert after the current selection at the same level
721 wxTreeItemId parent = m_toolbarTree->GetItemParent( selItem );
722
723 // Can't insert a spacer in a group yet
724 if( parent.IsOk() )
725 {
726 wxTreeItemId secondParent = m_toolbarTree->GetItemParent( parent );
727
728 if( secondParent.IsOk() )
729 {
730 delete treeItem;
731 return;
732 }
733 }
734
735 newItem = m_toolbarTree->InsertItem( parent, selItem, label, -1, -1, treeItem );
736 }
737 else
738 {
739 newItem = m_toolbarTree->AppendItem( m_toolbarTree->GetRootItem(), label, -1, -1, treeItem );
740 }
741
742 if( newItem.IsOk() )
743 {
744 m_toolbarTree->SelectItem( newItem );
745 m_toolbarTree->EnsureVisible( newItem );
746 }
747}
748
749
751{
753
754 wxTreeItemId newItem;
755 wxTreeItemId selItem = m_toolbarTree->GetSelection();
756
757 if( selItem.IsOk() )
758 {
759 // Insert after the current selection at the same level
760 wxTreeItemId parent = m_toolbarTree->GetItemParent( selItem );
761
762 // Can't insert a separator in a group yet
763 if( parent.IsOk() )
764 {
765 wxTreeItemId secondParent = m_toolbarTree->GetItemParent( parent );
766
767 if( secondParent.IsOk() )
768 {
769 delete treeItem;
770 return;
771 }
772 }
773
774 newItem = m_toolbarTree->InsertItem( parent, selItem, _( "Separator" ), -1, -1, treeItem );
775 }
776 else
777 {
778 newItem = m_toolbarTree->AppendItem( m_toolbarTree->GetRootItem(), _( "Separator" ), -1, -1, treeItem );
779 }
780
781 if( newItem.IsOk() )
782 {
783 m_toolbarTree->SelectItem( newItem );
784 m_toolbarTree->EnsureVisible( newItem );
785 }
786}
787
788
790{
791 enableCustomControls( event.IsChecked() );
792}
793
794
796{
797 m_tbChoice->Enable( enable );
798 enableToolbarControls( enable );
799}
800
801
803{
804 m_toolbarTree->Enable( enable );
805 m_btnAddTool->Enable( enable );
806 m_btnToolDelete->Enable( enable );
807
808 m_btnToolMoveDown->Enable( enable );
809 m_btnToolMoveUp->Enable( enable );
810 m_actionsList->Enable( enable );
811 m_actionFilter->Enable( enable );
812 m_insertButton->Enable( enable );
813}
814
815
816void PANEL_TOOLBAR_CUSTOMIZATION::onToolDelete( wxCommandEvent& event )
817{
818 wxTreeItemId item = m_toolbarTree->GetSelection();
819
820 if( !item.IsOk() )
821 return;
822
823 // The tree control defaults to nothing selected if you delete the item
824 // at the last place, so we have to manually get the itme immediately before
825 // the one we will delete, and then select it if nothing is selected.
826 wxTreeItemId prev = m_toolbarTree->GetPrevSibling( item );
827
828 m_toolbarTree->Delete( item );
829
830 item = m_toolbarTree->GetSelection();
831
832 if( !item.IsOk() && prev.IsOk() )
833 {
834 m_toolbarTree->SelectItem( prev );
835 m_toolbarTree->EnsureVisible( prev );
836 }
837}
838
839
840void PANEL_TOOLBAR_CUSTOMIZATION::onToolMoveUp( wxCommandEvent& event )
841{
842 m_toolbarTree->MoveItemUp( m_toolbarTree->GetSelection() );
843}
844
845
847{
848 m_toolbarTree->MoveItemDown( m_toolbarTree->GetSelection() );
849}
850
851
853{
854 // Get the selected item
855 long actionIdx = m_actionsList->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
856
857 // Nothing is selected, bail out
858 if( actionIdx < 0 )
859 return;
860
861 size_t entryIdx = m_actionsList->GetItemData( actionIdx );
862
863 if( entryIdx >= m_actionEntries.size() )
864 return;
865
866 const ACTION_LIST_ENTRY& entry = m_actionEntries[entryIdx];
867 TOOL_ACTION* action = entry.action;
868 ACTION_TOOLBAR_CONTROL* control = entry.control;
869
870 // Build the item to add
873 toolTreeItem->SetAction( action );
874 toolTreeItem->SetControl( control );
875
876 int imgIdx = -1;
877
878 if( action )
879 {
880 auto imgMap = m_actionImageListMap.find( action->GetName() );
881
882 if( imgMap != m_actionImageListMap.end() )
883 imgIdx = imgMap->second;
884 }
885
886 // Actually add the item
887 wxTreeItemId selItem = m_toolbarTree->GetSelection();
888 wxTreeItemId newItem;
889
890 if( selItem.IsOk() )
891 {
893 dynamic_cast<TOOLBAR_TREE_ITEM_DATA*>( m_toolbarTree->GetItemData( selItem ) );
894
895 if( data && data->GetType() == TOOLBAR_ITEM_TYPE::TB_GROUP )
896 {
897 // Insert into the end of the group
898 newItem = m_toolbarTree->AppendItem( selItem, entry.label, imgIdx, -1, toolTreeItem );
899 }
900 else
901 {
902 // Insert after the current selection at the same level
903 wxTreeItemId parent = m_toolbarTree->GetItemParent( selItem );
904 newItem = m_toolbarTree->InsertItem( parent, selItem, entry.label, imgIdx, -1, toolTreeItem );
905 }
906 }
907 else
908 {
909 // Insert at the root level if there is no selection
910 newItem = m_toolbarTree->AppendItem( m_toolbarTree->GetRootItem(), entry.label, imgIdx, -1, toolTreeItem );
911 }
912
913 if( newItem.IsOk() )
914 {
915 m_toolbarTree->SelectItem( newItem );
916 m_toolbarTree->EnsureVisible( newItem );
917
918 // Move the action to the next available one, to be nice
919 if( ++actionIdx < m_actionsList->GetItemCount() )
920 m_actionsList->SetItemState( actionIdx, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
921 }
922}
923
924
926{
928 aEvent.Skip();
929}
930
931
933{
934 aEvent.Skip();
935
936 if( aEvent.Leaving() )
937 {
939 m_actionsList->UnsetToolTip();
940 return;
941 }
942
943 int flags = 0;
944 long item = m_actionsList->HitTest( aEvent.GetPosition(), flags );
945
946 if( item >= 0 )
947 {
948 long entryIdx = static_cast<long>( m_actionsList->GetItemData( item ) );
949
950 if( entryIdx >= 0 && entryIdx < static_cast<long>( m_actionEntries.size() ) )
951 {
952 if( m_hoveredActionEntry != entryIdx )
953 {
954 m_hoveredActionEntry = entryIdx;
955
956 if( const wxString& tooltip = m_actionEntries[entryIdx].tooltip; tooltip.IsEmpty() )
957 m_actionsList->UnsetToolTip();
958 else
959 m_actionsList->SetToolTip( tooltip );
960 }
961
962 return;
963 }
964 }
965
966 if( m_hoveredActionEntry != -1 )
967 {
969 m_actionsList->UnsetToolTip();
970 }
971}
972
973
975{
976 wxTreeItemId id = event.GetItem();
977
978 if( id.IsOk() )
979 {
980 wxTreeItemData* treeData = m_toolbarTree->GetItemData( id );
981
982 if( TOOLBAR_TREE_ITEM_DATA* tbData = dynamic_cast<TOOLBAR_TREE_ITEM_DATA*>( treeData ) )
983 {
984 switch( tbData->GetType() )
985 {
989 // Don't let these be edited
990 event.Veto();
991 break;
992
995 // Do nothing here
996 break;
997 }
998 }
999 }
1000}
1001
1002
1004{
1005
1006}
1007
1008
1010{
1011 // Store the current toolbar
1012 std::optional<TOOLBAR_CONFIGURATION> currentTb = parseToolbarTree();
1013
1014 if( currentTb.has_value() )
1015 m_toolbars[m_currentToolbar] = currentTb.value();
1016
1017 int idx = event.GetInt();
1018
1019 if( idx >= 0 && idx < static_cast<int>( m_toolbarChoices.size() ) )
1020 {
1023 }
1024}
1025
1026
1028{
1029 wxCommandEvent dummy;
1031}
const char * name
wxBitmapBundle KiBitmapBundleDef(BITMAPS aBitmap, int aDefHeight)
Constructs and returns a bitmap bundle for the given icon ID, with the default bitmap size being aDef...
Definition bitmap.cpp:116
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
@ INVALID_BITMAP
static TOOL_ACTION zoomRedraw
Definition actions.h:132
static TOOL_ACTION zoomOutCenter
Definition actions.h:136
static TOOL_ACTION zoomFitScreen
Definition actions.h:142
static TOOL_ACTION zoomInCenter
Definition actions.h:135
Class to hold basic information about controls that can be added to the toolbars.
const std::string & GetName() const
APP_SETTINGS_BASE is a settings class that should be derived for each standalone KiCad application.
PANEL_TOOLBAR_CUSTOMIZATION_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
bool actionMatchesFilter(const ACTION_LIST_ENTRY &aEntry, const wxString &aFilter) const
void onSpacerPress(wxCommandEvent &aEvent)
wxVector< wxBitmapBundle > m_actionImageBundleVector
void onActionListMouseMove(wxMouseEvent &event)
void onTbChoiceSelect(wxCommandEvent &event) override
bool isActionSupported(const TOOL_ACTION &aAction) const
void onTreeEndLabelEdit(wxTreeEvent &event) override
void onTreeBeginLabelEdit(wxTreeEvent &event) override
void onToolDelete(wxCommandEvent &event) override
std::map< TOOLBAR_LOC, TOOLBAR_CONFIGURATION > m_toolbars
void onGroupPress(wxCommandEvent &aEvent)
void onSeparatorPress(wxCommandEvent &aEvent)
void ResetPanel() override
Reset the contents of this panel.
std::vector< TOOLBAR_LOC > m_toolbarChoices
std::map< std::string, int > m_actionImageListMap
void onBtnAddAction(wxCommandEvent &event) override
std::map< std::string, TOOL_ACTION * > m_availableTools
std::map< std::string, ACTION_TOOLBAR_CONTROL * > m_availableControls
std::optional< TOOLBAR_CONFIGURATION > parseToolbarTree()
PANEL_TOOLBAR_CUSTOMIZATION(wxWindow *aParent, APP_SETTINGS_BASE *aCfg, TOOLBAR_SETTINGS *aTbSettings, FRAME_T aActionContext, const std::vector< TOOL_ACTION * > &aTools, const std::vector< ACTION_TOOLBAR_CONTROL * > &aControls)
void onCustomizeTbCb(wxCommandEvent &event) override
void onActionFilterText(wxCommandEvent &event)
void onToolMoveDown(wxCommandEvent &event) override
void onListItemActivated(wxListEvent &event) override
void onToolMoveUp(wxCommandEvent &event) override
std::vector< ACTION_LIST_ENTRY > m_actionEntries
std::vector< TOOLBAR_ITEM > GetToolbarItems() const
TOOLBAR_GROUP_CONFIG & AddAction(std::string aActionName)
std::vector< TOOLBAR_ITEM > m_GroupItems
std::string m_ActionName
void SetName(const wxString &aName)
void SetAction(TOOL_ACTION *aAction)
void SetControl(ACTION_TOOLBAR_CONTROL *aControl)
TOOLBAR_TREE_ITEM_DATA(TOOLBAR_ITEM_TYPE aType)
TOOLBAR_TREE_ITEM_DATA(TOOLBAR_ITEM_TYPE aType, int aSize)
TOOLBAR_TREE_ITEM_DATA(TOOLBAR_ITEM_TYPE aType, wxString aName)
TOOLBAR_ITEM_TYPE GetType() const
ACTION_TOOLBAR_CONTROL * GetControl() const
Represent a single user action.
const std::string & GetName() const
Return name of the action.
#define _(s)
FRAME_T
The set of EDA_BASE_FRAME derivatives, typically stored in EDA_BASE_FRAME::m_Ident.
Definition frame_type.h:33
@ FRAME_PCB_EDITOR
Definition frame_type.h:42
@ FRAME_SCH_SYMBOL_EDITOR
Definition frame_type.h:35
@ FRAME_FOOTPRINT_VIEWER
Definition frame_type.h:45
@ FRAME_SCH_VIEWER
Definition frame_type.h:36
@ FRAME_SCH
Definition frame_type.h:34
@ FRAME_SIMULATOR
Definition frame_type.h:38
@ FRAME_PL_EDITOR
Definition frame_type.h:59
@ FRAME_FOOTPRINT_EDITOR
Definition frame_type.h:43
@ FRAME_GERBER
Definition frame_type.h:57
@ FRAME_PCB_DISPLAY3D
Definition frame_type.h:47
KICOMMON_API wxFont GetInfoFont(wxWindow *aWindow)
static std::map< TOOLBAR_LOC, wxString > s_toolbarNameMap
std::vector< FAB_LAYER_COLOR > dummy
TOOL_ACTION * action
wxString label
ACTION_TOOLBAR_CONTROL * control
int image_index
wxString tooltip
wxString search_text
@ HIDDEN
Action is hidden from the toolbar.
Definition tool_action.h:63
@ RIGHT
Toolbar on the right side of the canvas.
@ LEFT
Toolbar on the left side of the canvas.
@ TOP_AUX
Toolbar on the top of the canvas.
@ TOP_MAIN
Toolbar on the top of the canvas.
Functions to provide common constants and other functions to assist in making a consistent UI.
#define SEPARATOR