KiCad PCB EDA Suite
Loading...
Searching...
No Matches
action_toolbar.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) 2019 CERN
5 * Copyright The KiCad Developers, see CHANGELOG.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
21#include <algorithm>
22#include <advanced_config.h>
23#include <bitmaps.h>
24#include <bitmap_store.h>
25#include <eda_draw_frame.h>
26#include <functional>
27#include <kiplatform/ui.h>
28#include <math/util.h>
29#include <memory>
30#include <pgm_base.h>
32#include <trace_helpers.h>
33#include <tool/action_toolbar.h>
34#include <tool/tool_action.h>
35#include <tool/tool_event.h>
37#include <tool/tool_manager.h>
42
43#include <wx/log.h>
44#include <wx/popupwin.h>
45#include <wx/renderer.h>
46#include <wx/sizer.h>
47#include <wx/dcclient.h>
48#include <wx/settings.h>
49
50#ifdef __WXMSW__
51#include <windows.h>
52#endif
53
54// Needed to handle adding the plugins to the toolbar
55// TODO (ISM): This should be better abstracted away from the toolbars
57
58
59ACTION_GROUP::ACTION_GROUP( const std::string_view& aName )
60{
61 m_name = aName;
63 m_defaultAction = nullptr;
64}
65
66
67ACTION_GROUP::ACTION_GROUP( const std::string_view& aName,
68 const std::vector<const TOOL_ACTION*>& aActions )
69{
70 m_name = aName;
72
73 SetActions( aActions );
74}
75
76
77void ACTION_GROUP::SetActions( const std::vector<const TOOL_ACTION*>& aActions )
78{
79 wxASSERT_MSG( aActions.size() > 0, wxS( "Action groups must have at least one action" ) );
80
81 // The default action is just the first action in the vector
82 m_actions = aActions;
84}
85
87{
89}
90
91
93{
94 bool valid = std::any_of( m_actions.begin(), m_actions.end(),
95 [&]( const TOOL_ACTION* aAction ) -> bool
96 {
97 // For some reason, we can't compare the actions directly
98 return aAction->GetId() == aDefault.GetId();
99 } );
100
101 wxASSERT_MSG( valid, wxS( "Action must be present in a group to be the default" ) );
102
103 m_defaultAction = &aDefault;
104}
105
106
107#define PALETTE_BORDER FromDIP( 4 ) // The border around the palette buttons on all sides
108#define BUTTON_BORDER FromDIP( 1 ) // The border on the sides of the buttons that touch other buttons
109
110
111ACTION_TOOLBAR_PALETTE::ACTION_TOOLBAR_PALETTE( wxWindow* aParent, bool aVertical ) :
112 wxPopupTransientWindow( aParent, wxBORDER_NONE ),
113 m_group( nullptr ),
114 m_isVertical( aVertical ),
115 m_panel( nullptr ),
116 m_mainSizer( nullptr ),
117 m_buttonSizer( nullptr )
118{
119 m_panel = new wxPanel( this, wxID_ANY );
120 m_panel->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
121
122 // This sizer holds the buttons for the actions
123 m_buttonSizer = new wxBoxSizer( aVertical ? wxVERTICAL : wxHORIZONTAL );
124
125 // This sizer holds the other sizer, so that a consistent border is present on all sides
126 m_mainSizer = new wxBoxSizer( aVertical ? wxVERTICAL : wxHORIZONTAL );
127 m_mainSizer->Add( m_buttonSizer, wxSizerFlags().Border( wxALL, PALETTE_BORDER ) );
128
129 m_panel->SetSizer( m_mainSizer );
130
131 Connect( wxEVT_CHAR_HOOK, wxCharEventHandler( ACTION_TOOLBAR_PALETTE::onCharHook ), nullptr, this );
132}
133
134
136{
138 wxBitmapBundle normalBmp = KiBitmapBundleDef( aAction.GetIcon(), iconSize );
139 int paddingDip = ( ToDIP( m_buttonSize.GetWidth() ) - iconSize ) / 2;
140
141 BITMAP_BUTTON* button = new BITMAP_BUTTON( m_panel, aAction.GetUIId() );
142
143 button->SetIsToolbarButton();
144 button->SetBitmap( normalBmp );
145 button->SetDisabledBitmap( KiDisabledBitmapBundleDef( aAction.GetIcon(), iconSize ) );
146 button->SetPadding( paddingDip );
147 button->SetToolTip( aAction.GetButtonTooltip() );
148 button->AcceptDragInAsClick();
149 button->SetBitmapCentered();
150
151 m_buttons[aAction.GetUIId()] = button;
152
153 if( m_isVertical )
154 m_buttonSizer->Add( button, wxSizerFlags().Border( wxTOP | wxBOTTOM, BUTTON_BORDER ) );
155 else
156 m_buttonSizer->Add( button, wxSizerFlags().Border( wxLEFT | wxRIGHT, BUTTON_BORDER ) );
157
158 m_buttonSizer->Layout();
159}
160
161
162void ACTION_TOOLBAR_PALETTE::EnableAction( const TOOL_ACTION& aAction, bool aEnable )
163{
164 auto it = m_buttons.find( aAction.GetUIId() );
165
166 if( it != m_buttons.end() )
167 it->second->Enable( aEnable );
168}
169
170
171void ACTION_TOOLBAR_PALETTE::CheckAction( const TOOL_ACTION& aAction, bool aCheck )
172{
173 auto it = m_buttons.find( aAction.GetUIId() );
174
175 if( it != m_buttons.end() )
176 it->second->Check( aCheck );
177}
178
179
181{
182 m_mainSizer->Fit( m_panel );
183 SetClientSize( m_panel->GetSize() );
184
185 return m_panel->GetSize();
186}
187
188
189void ACTION_TOOLBAR_PALETTE::Popup( wxWindow* aFocus )
190{
192
193 wxPopupTransientWindow::Popup( aFocus );
194}
195
196
197void ACTION_TOOLBAR_PALETTE::onCharHook( wxKeyEvent& aEvent )
198{
199 // Allow the escape key to dismiss this popup
200 if( aEvent.GetKeyCode() == WXK_ESCAPE )
201 Dismiss();
202 else
203 aEvent.Skip();
204}
205
206
207#ifdef __WXMSW__
208bool ACTION_TOOLBAR_PALETTE::MSWHandleMessage( WXLRESULT* aResult, WXUINT aMessage,
209 WXWPARAM aWParam, WXLPARAM aLParam )
210{
211 // The Windows "Activate on hover" option (active window tracking) activates whatever
212 // top-level window the pointer is over. As the pointer travels from the toolbar button
213 // toward this palette it crosses the owner frame, which then steals activation and would
214 // normally deactivate and dismiss this transient popup before the user can reach it.
215 // Ignore that specific deactivation so the palette survives the trip. Dismissal by Escape,
216 // by pressing a palette button, or by switching to any other window is unaffected because
217 // those do not hand activation back to the owner frame.
218 if( aMessage == WM_ACTIVATE && LOWORD( aWParam ) == WA_INACTIVE )
219 {
220 BOOL tracking = FALSE;
221
222 if( ::SystemParametersInfo( SPI_GETACTIVEWINDOWTRACKING, 0, &tracking, 0 ) && tracking )
223 {
224 HWND activated = reinterpret_cast<HWND>( aLParam );
225 wxWindow* owner = MSWGetOwner();
226
227 if( activated && owner && ::GetAncestor( activated, GA_ROOT ) == owner->GetHWND() )
228 return wxPopupTransientWindowBase::MSWHandleMessage( aResult, aMessage, aWParam,
229 aLParam );
230 }
231 }
232
233 return wxPopupTransientWindow::MSWHandleMessage( aResult, aMessage, aWParam, aLParam );
234}
235#endif
236
237
238ACTION_TOOLBAR::ACTION_TOOLBAR( EDA_BASE_FRAME* parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
239 long style ) :
240 wxAuiToolBar( parent, id, pos, size, style ),
241 m_parent( parent ),
242 m_paletteTimer( nullptr ),
243 m_auiManager( nullptr ),
244 m_toolManager( parent->GetToolManager() ),
245 m_palette( nullptr )
246{
247 m_paletteTimer = new wxTimer( this );
248
249 SetArtProvider( new WX_AUI_TOOLBAR_ART );
250
251 Connect( wxEVT_COMMAND_TOOL_CLICKED, wxAuiToolBarEventHandler( ACTION_TOOLBAR::onToolEvent ), nullptr, this );
252 Connect( wxEVT_AUITOOLBAR_RIGHT_CLICK, wxAuiToolBarEventHandler( ACTION_TOOLBAR::onRightClick ), nullptr, this );
253 Connect( wxEVT_RIGHT_UP, wxMouseEventHandler( ACTION_TOOLBAR::onRightUp ), nullptr, this );
254 Connect( wxEVT_AUITOOLBAR_BEGIN_DRAG, wxAuiToolBarEventHandler( ACTION_TOOLBAR::onItemDrag ), nullptr, this );
255 Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( ACTION_TOOLBAR::onMouseClick ), nullptr, this );
256 Connect( wxEVT_LEFT_UP, wxMouseEventHandler( ACTION_TOOLBAR::onMouseClick ), nullptr, this );
257 Connect( m_paletteTimer->GetId(), wxEVT_TIMER, wxTimerEventHandler( ACTION_TOOLBAR::onTimerDone ), nullptr, this );
258
259 Bind( wxEVT_SIZE,
260 [&]( wxSizeEvent& aEvent )
261 {
262 CallAfter(
263 [&]()
264 {
265 SetOverflowVisible( !GetToolBarFits() );
266 } );
267
268 aEvent.Skip();
269 } );
270
271 Bind( wxEVT_SYS_COLOUR_CHANGED, wxSysColourChangedEventHandler( ACTION_TOOLBAR::onThemeChanged ), this );
272
273 Bind( wxEVT_DPI_CHANGED,
274 [&]( wxDPIChangedEvent& aEvent )
275 {
276#ifdef __WXMSW__
277 // Update values which are normally only initialized in wxAuiToolBar::Create.
278 // FromDIP is no-op on backends other than wxMSW.
279 SetToolPacking( FromDIP( 2 ) );
280 SetToolBorderPadding( FromDIP( 3 ) );
281
282 wxSize margin_lt = FromDIP( wxSize( 5, 5 ) );
283 wxSize margin_rb = FromDIP( wxSize( 2, 2 ) );
284 SetMargins( margin_lt.x, margin_lt.y, margin_rb.x, margin_rb.y );
285
286 // Re-realize the toolbar to recalculate all item sizes with the new DPI.
287 // This fixes excessive button padding when moving windows between displays
288 // with different DPI scaling factors.
289 if( GetToolCount() > 0 )
290 {
292 InvalidateBestSize();
293 KiRealize();
294 }
295#endif
296
297 aEvent.Skip();
298 } );
299}
300
301
303{
304 Disconnect( wxEVT_COMMAND_TOOL_CLICKED, wxAuiToolBarEventHandler( ACTION_TOOLBAR::onToolEvent ), nullptr, this );
305 Disconnect( wxEVT_AUITOOLBAR_RIGHT_CLICK, wxAuiToolBarEventHandler( ACTION_TOOLBAR::onRightClick ), nullptr, this );
306 Disconnect( wxEVT_RIGHT_UP, wxMouseEventHandler( ACTION_TOOLBAR::onRightUp ), nullptr, this );
307 Disconnect( wxEVT_AUITOOLBAR_BEGIN_DRAG, wxAuiToolBarEventHandler( ACTION_TOOLBAR::onItemDrag ), nullptr, this );
308 Disconnect( wxEVT_LEFT_DOWN, wxMouseEventHandler( ACTION_TOOLBAR::onMouseClick ), nullptr, this );
309 Disconnect( wxEVT_LEFT_UP, wxMouseEventHandler( ACTION_TOOLBAR::onMouseClick ), nullptr, this );
310 Disconnect( m_paletteTimer->GetId(), wxEVT_TIMER, wxTimerEventHandler( ACTION_TOOLBAR::onTimerDone ), nullptr,
311 this );
312
313 Unbind( wxEVT_SYS_COLOUR_CHANGED, wxSysColourChangedEventHandler( ACTION_TOOLBAR::onThemeChanged ), this );
314
315 delete m_paletteTimer;
316
317 // Clear all the maps keeping track of our items on the toolbar
318 m_toolMenus.clear();
319 m_actionGroups.clear();
320 m_toolCancellable.clear();
321 m_toolKinds.clear();
322 m_toolActions.clear();
323}
324
325
326std::list<ACTION_TOOLBAR_CONTROL*> ACTION_TOOLBAR::GetCustomControlList( FRAME_T aContext )
327{
328 std::list<ACTION_TOOLBAR_CONTROL*> controls;
329
331 {
332 if( control->SupportedFor( aContext ) )
333 controls.push_back( control );
334 }
335
336 return controls;
337}
338
339
341{
342 wxASSERT( GetParent() );
343
344 // Keep each group's selection across the rebuild.
345 std::map<std::string, std::string> currentGroupItems = m_groupSelections;
346
347 // Remove existing tools
348 ClearToolbar();
349
350 std::vector<TOOLBAR_ITEM> items = aConfig.GetToolbarItems();
351
352 // Add all the items to the toolbar
353 for( auto& item : items )
354 {
355 switch( item.m_Type )
356 {
358 AddScaledSeparator( GetParent() );
359 break;
360
362 AddSpacer( item.m_Size );
363 break;
364
366 {
367 // Add a group of items to the toolbar
368 std::string groupName = item.m_GroupName.ToStdString();
369 std::vector<const TOOL_ACTION*> tools;
370 const TOOL_ACTION* defaultTool = nullptr;
371
372 for( TOOLBAR_ITEM& groupItem : item.m_GroupItems )
373 {
374 switch( groupItem.m_Type )
375 {
380 wxFAIL_MSG( wxT( "Unsupported group item type" ) );
381 continue;
382
384 TOOL_ACTION* grpAction = m_toolManager->GetActionManager()->FindAction( groupItem.m_ActionName );
385
386 if( !grpAction )
387 {
388 wxFAIL_MSG( wxString::Format( wxT( "Unable to find group tool %s" ), groupItem.m_ActionName ) );
389 continue;
390 }
391
392 tools.push_back( grpAction );
393
394 if( currentGroupItems[groupName] == groupItem.m_ActionName )
395 defaultTool = grpAction;
396 }
397 }
398
399 // A group needs at least one action
400 if( tools.empty() )
401 continue;
402
403 std::unique_ptr<ACTION_GROUP> group = std::make_unique<ACTION_GROUP>( groupName, tools );
404
405 if( defaultTool )
406 group->SetDefaultAction( *defaultTool );
407
408 AddGroup( std::move( group ) );
409
410 // Look up and attach context menu if one is registered for this group
411 auto menuFactory = TOOLBAR_CONTEXT_MENU_REGISTRY::GetGroupMenuFactory( groupName );
412
413 if( menuFactory && m_toolManager )
414 {
415 // Register the menu for each action in the group
416 for( const TOOL_ACTION* grpAction : tools )
417 AddToolContextMenu( *grpAction, menuFactory( m_toolManager ) );
418 }
419
420 break;
421 }
422
424 {
425 // Add a custom control to the toolbar
426 EDA_BASE_FRAME* frame = static_cast<EDA_BASE_FRAME*>( GetParent() );
427 ACTION_TOOLBAR_CONTROL_FACTORY* factory = frame->GetCustomToolbarControlFactory( item.m_ControlName );
428
429 if( !factory )
430 {
431 wxFAIL_MSG( wxString::Format( wxT( "Unable to find control factory for %s" ), item.m_ControlName ) );
432 continue;
433 }
434
435 // The factory functions are responsible for adding the controls to the toolbar themselves
436 (*factory)( this );
437 break;
438 }
439
441 {
442 TOOL_ACTION* action = m_toolManager->GetActionManager()->FindAction( item.m_ActionName );
443
444 if( !action )
445 {
446 wxFAIL_MSG( wxString::Format( wxT( "Unable to find toolbar tool %s" ), item.m_ActionName ) );
447 continue;
448 }
449
450 Add( *action );
451
452 // Look up and attach context menu if one is registered for this action
453 auto factory = TOOLBAR_CONTEXT_MENU_REGISTRY::GetMenuFactory( item.m_ActionName );
454
455 if( factory && m_toolManager )
456 AddToolContextMenu( *action, factory( m_toolManager ) );
457
458 break;
459 }
460 }
461 }
462
463 // Apply the configuration
464 KiRealize();
465}
466
467
468void ACTION_TOOLBAR::DoSetToolTipText( const wxString& aTip )
469{
470 // We use \t in short description to align accelerators in wxMenuItem
471 // But they should be converted when displaying tooltips
472 wxString tip = aTip;
473 tip.Replace( "\t", " " );
474
475 wxAuiToolBar::DoSetToolTipText( tip );
476}
477
478
479void ACTION_TOOLBAR::Add( const TOOL_ACTION& aAction )
480{
481 wxASSERT_MSG( !aAction.CheckToolbarState( TOOLBAR_STATE::HIDDEN ),
482 wxString::Format( "Attempting to add hidden action %s to the toolbar", aAction.GetName() ) );
483
484 bool isToggleEntry = aAction.CheckToolbarState( TOOLBAR_STATE::TOGGLE );
485 bool isCancellable = aAction.CheckToolbarState( TOOLBAR_STATE::CANCEL );
486
487 Add( aAction, isToggleEntry, isCancellable );
488}
489
490
491void ACTION_TOOLBAR::Add( const TOOL_ACTION& aAction, bool aIsToggleEntry, bool aIsCancellable )
492{
493 wxASSERT( GetParent() );
494 wxASSERT_MSG( !( aIsCancellable && !aIsToggleEntry ),
495 wxS( "aIsCancellable requires aIsToggleEntry" ) );
496
497 int toolId = aAction.GetUIId();
499
500 AddTool( toolId, wxEmptyString,
501 KiBitmapBundleDef( aAction.GetIcon(), iconSize ),
502 KiDisabledBitmapBundleDef( aAction.GetIcon(), iconSize ),
503 aIsToggleEntry ? wxITEM_CHECK : wxITEM_NORMAL,
504 aAction.GetButtonTooltip(), wxEmptyString, nullptr );
505
506 m_toolKinds[ toolId ] = aIsToggleEntry;
507 m_toolActions[ toolId ] = &aAction;
508 m_toolCancellable[ toolId ] = aIsCancellable;
509}
510
511
513{
514 int toolId = aAction.GetUIId();
516
517 AddTool( toolId, wxEmptyString,
518 KiBitmapBundleDef( aAction.GetIcon(), iconSize ),
519 KiDisabledBitmapBundleDef( aAction.GetIcon(), iconSize ),
520 wxITEM_NORMAL, aAction.GetButtonTooltip(), wxEmptyString, nullptr );
521
522 m_toolKinds[ toolId ] = false;
523 m_toolActions[ toolId ] = &aAction;
524}
525
526
527void ACTION_TOOLBAR::AddScaledSeparator( wxWindow* aWindow )
528{
529 int scale = KiIconScale( aWindow );
530
531 if( scale > 4 )
532 AddSpacer( 16 * ( scale - 4 ) / 4 );
533
534 AddSeparator();
535
536 if( scale > 4 )
537 AddSpacer( 16 * ( scale - 4 ) / 4 );
538}
539
540
541void ACTION_TOOLBAR::Add( wxControl* aControl, const wxString& aLabel )
542{
543 wxASSERT( aControl );
544 m_controlIDs.push_back( aControl->GetId() );
545 AddControl( aControl, aLabel );
546}
547
548
549void ACTION_TOOLBAR::AddToolContextMenu( const TOOL_ACTION& aAction, std::unique_ptr<ACTION_MENU> aMenu )
550{
551 int toolId = aAction.GetUIId();
552
553 m_toolMenus[toolId] = std::move( aMenu );
554}
555
556
557void ACTION_TOOLBAR::AddGroup( std::unique_ptr<ACTION_GROUP> aGroup )
558{
559 int groupId = aGroup->GetUIId();
560 const TOOL_ACTION* defaultAction = aGroup->GetDefaultAction();
562
563 wxASSERT( GetParent() );
564 wxASSERT( defaultAction );
565
566 // Turn this into a toggle entry if any one of the actions is a toggle entry
567 bool isToggleEntry = false;
568
569 for( const auto& act : aGroup->GetActions() )
570 isToggleEntry |= act->CheckToolbarState( TOOLBAR_STATE::TOGGLE );
571
572 m_toolKinds[ groupId ] = isToggleEntry;
573 m_toolActions[ groupId ] = defaultAction;
574 m_actionGroups[ groupId ] = std::move( aGroup );
575
576 // Add the main toolbar item representing the group
577 AddTool( groupId, wxEmptyString,
578 KiBitmapBundleDef( defaultAction->GetIcon(), iconSize ),
579 KiDisabledBitmapBundleDef( defaultAction->GetIcon(), iconSize ),
580 isToggleEntry ? wxITEM_CHECK : wxITEM_NORMAL, wxEmptyString, wxEmptyString, nullptr );
581
582 // Select the default action
583 doSelectAction( m_actionGroups[ groupId ].get(), *defaultAction );
584}
585
586
588{
589 bool valid = std::any_of( aGroup->m_actions.begin(), aGroup->m_actions.end(),
590 [&]( const TOOL_ACTION* action2 ) -> bool
591 {
592 // For some reason, we can't compare the actions directly
593 return aAction.GetId() == action2->GetId();
594 } );
595
596 if( valid )
597 doSelectAction( aGroup, aAction );
598}
599
600
602{
603 // Find the group that contains this action and select it
604 for( auto& [id, groupPtr] : m_actionGroups )
605 {
606 ACTION_GROUP* group = groupPtr.get();
607
608 bool inGroup = std::any_of( group->m_actions.begin(), group->m_actions.end(),
609 [&]( const TOOL_ACTION* action2 )
610 {
611 return aAction.GetId() == action2->GetId();
612 } );
613
614 if( inGroup )
615 {
616 doSelectAction( group, aAction );
617 break;
618 }
619 }
620}
621
622
624{
625 wxASSERT( GetParent() );
626
627 int groupId = aGroup->GetUIId();
628
629 wxAuiToolBarItem* item = FindTool( groupId );
630
631 if( !item )
632 return;
633
635
636 // Update the item information
637 item->SetShortHelp( aAction.GetButtonTooltip() );
638 item->SetBitmap( KiBitmapBundleDef( aAction.GetIcon(), iconSize ) );
639 item->SetDisabledBitmap( KiDisabledBitmapBundleDef( aAction.GetIcon(), iconSize ) );
640
641 // Register a new handler with the new UI conditions
642 if( m_toolManager )
643 {
644 m_toolManager->GetToolHolder()->UnregisterUIUpdateHandler( groupId );
645
646 const ACTION_CONDITIONS* cond = m_toolManager->GetActionManager()->GetCondition( aAction );
647
648 // Register the new UI condition to control this entry
649 if( cond )
650 {
651 m_toolManager->GetToolHolder()->RegisterUIUpdateHandler( groupId, *cond );
652 }
653 else
654 {
655 wxLogTrace( kicadTraceToolStack, wxString::Format( "No UI condition for action %s",
656 aAction.GetName() ) );
657 }
658 }
659
660 // Update the currently selected action
661 m_toolActions[ groupId ] = &aAction;
662 m_groupSelections[aGroup->GetName()] = aAction.GetName();
663
664 Refresh();
665}
666
667
669{
670 for( int id : m_controlIDs )
671 UpdateControlWidth( id );
672}
673
674
676{
677 wxAuiToolBarItem* item = FindTool( aID );
678 wxASSERT_MSG( item, wxString::Format( "No toolbar item found for ID %d", aID ) );
679
680 // The control on the toolbar is stored inside the window field of the item
681 wxControl* control = dynamic_cast<wxControl*>( item->GetWindow() );
682 wxASSERT_MSG( control, wxString::Format( "No control located in toolbar item with ID %d", aID ) );
683
684 // Update the size the item has stored using the best size of the control
685 control->InvalidateBestSize();
686 wxSize bestSize = control->GetBestSize();
687 item->SetMinSize( bestSize );
688
689 // Update the sizer item sizes
690 // This is a bit convoluted because there are actually 2 sizers that need to be updated:
691 // 1. The main sizer that is used for the entire toolbar (this sizer item can be found in the
692 // toolbar item)
693 if( wxSizerItem* szrItem = item->GetSizerItem() )
694 szrItem->SetMinSize( bestSize );
695
696 // 2. The controls have a second sizer that allows for padding above/below the control with
697 // stretch space, so we also need to update the sizer item for the control in that sizer with
698 // the new size. We let wx do the search for us, since SetItemMinSize is recursive and will
699 // locate the control on that sizer.
700 if( m_sizer )
701 {
702 m_sizer->SetItemMinSize( control, bestSize );
703
704 // Now actually update the toolbar with the new sizes
705 m_sizer->Layout();
706 }
707}
708
709
711{
712 // Clear all the maps keeping track of our items on the toolbar
713 m_toolMenus.clear();
714 m_actionGroups.clear();
715 m_toolCancellable.clear();
716 m_toolKinds.clear();
717 m_toolActions.clear();
718
719 for( int id : m_controlIDs )
720 {
721 m_parent->ClearToolbarControl( id );
722 DestroyTool( id );
723 }
724
725 m_controlIDs.clear();
726
727 // Remove the actual tools from the toolbar
728 Clear();
729}
730
731
732void ACTION_TOOLBAR::SetToolBitmap( const TOOL_ACTION& aAction, const wxBitmapBundle& aBitmap )
733{
734 int toolId = aAction.GetUIId();
735
736 // Set the disabled bitmap: we use the disabled bitmap version of aBitmap.
737 wxAuiToolBarItem* tb_item = wxAuiToolBar::FindTool( toolId );
738
739 if( !tb_item )
740 return;
741
742 wxBitmap bm = aBitmap.GetBitmapFor( this );
743
744 tb_item->SetBitmap( aBitmap );
745 tb_item->SetDisabledBitmap( bm.ConvertToDisabled( KIPLATFORM::UI::IsDarkTheme() ? 70 : 255 ) );
746}
747
748
749void ACTION_TOOLBAR::Toggle( const TOOL_ACTION& aAction, bool aState )
750{
751 int toolId = aAction.GetUIId();
752
753 if( m_toolKinds[ toolId ] )
754 ToggleTool( toolId, aState );
755 else
756 EnableTool( toolId, aState );
757}
758
759
760void ACTION_TOOLBAR::Toggle( const TOOL_ACTION& aAction, bool aEnabled, bool aChecked )
761{
762 int toolId = aAction.GetUIId();
763
764 EnableTool( toolId, aEnabled );
765 ToggleTool( toolId, aEnabled && aChecked );
766}
767
768
769void ACTION_TOOLBAR::onToolEvent( wxAuiToolBarEvent& aEvent )
770{
771 int id = aEvent.GetId();
772 wxEventType type = aEvent.GetEventType();
773 OPT_TOOL_EVENT evt;
774
775 bool handled = false;
776
777 if( m_toolManager && type == wxEVT_COMMAND_TOOL_CLICKED )
778 {
779 const auto actionIt = m_toolActions.find( id );
780 const auto cancelIt = m_toolCancellable.find( id );
781 const auto groupIt = m_actionGroups.find( id );
782
783 // Determine if the tool is actually cancellable
784 bool isCancellable = ( cancelIt != m_toolCancellable.end() ) ? cancelIt->second : false;
785
786 // The toolbar item is toggled before the event is sent, so we check for it not being
787 // toggled to see if it was toggled originally
788 if( isCancellable && !GetToolToggled( id ) )
789 {
790 // Send a cancel event
791 m_toolManager->CancelTool();
792 handled = true;
793 }
794 else if( groupIt != m_actionGroups.end()
795 && std::none_of( groupIt->second->GetActions().begin(),
796 groupIt->second->GetActions().end(),
797 []( const TOOL_ACTION* a )
798 {
799 return a->IsActivation();
800 } ) )
801 {
802 // For non-tool toggle groups (units, crosshair, line modes), cycle to the next
803 // action on click. Tool groups (route track, etc.) fall through and just dispatch
804 // the currently displayed action.
805 ACTION_GROUP* group = groupIt->second.get();
806 const std::vector<const TOOL_ACTION*>& actions = group->GetActions();
807 const TOOL_ACTION* current = actionIt->second;
808
809 const TOOL_ACTION* next = actions[0];
810
811 for( size_t i = 0; i < actions.size(); ++i )
812 {
813 if( actions[i]->GetId() == current->GetId() )
814 {
815 next = actions[( i + 1 ) % actions.size()];
816 break;
817 }
818 }
819
820 evt = next->MakeEvent();
821 evt->SetHasPosition( false );
822 m_toolManager->ProcessEvent( *evt );
823 m_toolManager->GetToolHolder()->RefreshCanvas();
824
826 handled = true;
827 }
828 else if( actionIt != m_toolActions.end() )
829 {
830 // Dispatch a tool event
831 evt = actionIt->second->MakeEvent();
832 evt->SetHasPosition( false );
833 m_toolManager->ProcessEvent( *evt );
834 m_toolManager->GetToolHolder()->RefreshCanvas();
835 handled = true;
836 }
837 }
838
839 // Skip the event if we don't handle it
840 if( !handled )
841 aEvent.Skip();
842}
843
844
845void ACTION_TOOLBAR::onRightClick( wxAuiToolBarEvent& aEvent )
846{
847 int toolId = aEvent.GetToolId();
848
849 // This means the event was not on a button
850 if( toolId == -1 )
851 return;
852
853 showContextMenu( toolId );
854}
855
856
857void ACTION_TOOLBAR::onRightUp( wxMouseEvent& aEvent )
858{
859 // wxAuiToolBar::OnRightDown() uses horizontal-only geometry to reserve its overflow
860 // dead-zone, which on a vertical toolbar kills right-clicks over part of every button.
861 // Hit-test the tool ourselves so the whole button works.
862 wxAuiToolBarItem* item = FindToolByPosition( aEvent.GetX(), aEvent.GetY() );
863
864 if( !item )
865 {
866 aEvent.Skip();
867 return;
868 }
869
870 // Don't Skip(): suppress wx's own OnRightUp() so the menu is shown exactly once.
871 showContextMenu( item->GetId() );
872}
873
874
876{
877 // Ensure that the ID maps to a proper tool ID. If right-clicked on a group item, this is needed
878 // to get the ID of the currently selected action, since the event's ID is that of the group.
879 const auto actionIt = m_toolActions.find( aToolId );
880
881 if( actionIt != m_toolActions.end() )
882 aToolId = actionIt->second->GetUIId();
883
884 // Find the menu for the action
885 const auto menuIt = m_toolMenus.find( aToolId );
886
887 if( menuIt == m_toolMenus.end() )
888 return;
889
890 // Update and show the menu
891 std::unique_ptr<ACTION_MENU>& owningMenu = menuIt->second;
892
893 // Get the actual menu pointer to show it
894 ACTION_MENU* menu = owningMenu.get();
895 SELECTION dummySel;
896
897 if( CONDITIONAL_MENU* condMenu = dynamic_cast<CONDITIONAL_MENU*>( menu ) )
898 condMenu->Evaluate( dummySel );
899
900 menu->UpdateAll();
901 PopupMenu( menu );
902
903 // Remove hovered item when the menu closes, otherwise it remains hovered even if the
904 // mouse is not on the toolbar
905 SetHoverItem( nullptr );
906}
907
908
909// The time (in milliseconds) between pressing the left mouse button and opening the palette
910#define PALETTE_OPEN_DELAY 500
911
912
913void ACTION_TOOLBAR::onMouseClick( wxMouseEvent& aEvent )
914{
915 wxAuiToolBarItem* item = FindToolByPosition( aEvent.GetX(), aEvent.GetY() );
916
917 if( item )
918 {
919 // Ensure there is no active palette
920 if( m_palette )
921 {
922 m_palette->Hide();
923 m_palette->Destroy();
924 m_palette = nullptr;
925 }
926
927 // Start the popup conditions if it is a left mouse click and the tool clicked is a group
928 if( aEvent.LeftDown() && ( m_actionGroups.find( item->GetId() ) != m_actionGroups.end() ) )
930
931 // Clear the popup conditions if it is a left up, because that implies a click happened
932 if( aEvent.LeftUp() )
933 m_paletteTimer->Stop();
934 }
935
936 // Skip the event so wx can continue processing the mouse event
937 aEvent.Skip();
938}
939
940
941void ACTION_TOOLBAR::onItemDrag( wxAuiToolBarEvent& aEvent )
942{
943 int toolId = aEvent.GetToolId();
944
945 if( m_actionGroups.find( toolId ) != m_actionGroups.end() )
946 {
947 wxAuiToolBarItem* item = FindTool( toolId );
948
949 // Use call after because opening the palette from a mouse handler
950 // creates a weird mouse state that causes problems on OSX.
951 CallAfter( &ACTION_TOOLBAR::popupPalette, item );
952
953 // Don't skip this event since we are handling it
954 return;
955 }
956
957 // Skip since we don't care about it
958 aEvent.Skip();
959}
960
961
962void ACTION_TOOLBAR::onTimerDone( wxTimerEvent& aEvent )
963{
964 // We need to search for the tool using the client coordinates
965 wxPoint mousePos = ScreenToClient( KIPLATFORM::UI::GetMousePosition() );
966
967 wxAuiToolBarItem* item = FindToolByPosition( mousePos.x, mousePos.y );
968
969 if( item )
970 popupPalette( item );
971}
972
973
974void ACTION_TOOLBAR::onPaletteEvent( wxCommandEvent& aEvent )
975{
976 if( !m_palette )
977 return;
978
979 // Clear m_palette up front so a re-entrant dispatch (modal dialog pumping events)
980 // hits the null guard above instead of double-destroying.
982 m_palette = nullptr;
983
984 OPT_TOOL_EVENT evt;
985 ACTION_GROUP* group = palette->GetGroup();
986
987 // Find the action corresponding to the button press
988 auto actionIt = std::find_if( group->GetActions().begin(), group->GetActions().end(),
989 [&]( const TOOL_ACTION* aAction )
990 {
991 return aAction->GetUIId() == aEvent.GetId();
992 } );
993
994 if( actionIt != group->GetActions().end() )
995 {
996 const TOOL_ACTION* action = *actionIt;
997
998 // Dispatch a tool event
999 evt = action->MakeEvent();
1000 evt->SetHasPosition( false );
1001 m_toolManager->ProcessEvent( *evt );
1002 m_toolManager->GetToolHolder()->RefreshCanvas();
1003
1004 // Update the main toolbar item with the selected action
1005 doSelectAction( group, *action );
1006 }
1007
1008 // Hide the palette
1009 palette->Hide();
1010 palette->Destroy();
1011}
1012
1013
1014void ACTION_TOOLBAR::popupPalette( wxAuiToolBarItem* aItem )
1015{
1016 // Clear all popup conditions
1017 m_paletteTimer->Stop();
1018
1019 wxWindow* toolParent = dynamic_cast<wxWindow*>( m_toolManager->GetToolHolder() );
1020
1021 wxCHECK( GetParent() && m_auiManager && toolParent, /* void */ );
1022
1023 // Ensure the item we are using for the palette has a group associated with it.
1024 const auto it = m_actionGroups.find( aItem->GetId() );
1025
1026 if( it == m_actionGroups.end() )
1027 return;
1028
1029 ACTION_GROUP* group = it->second.get();
1030
1031 wxAuiPaneInfo& pane = m_auiManager->GetPane( this );
1032
1033 // We use the size of the toolbar items for our palette buttons
1034 wxRect toolRect = GetToolRect( aItem->GetId() );
1035
1036 // The position for the palette window must be in screen coordinates
1037 wxPoint pos( ClientToScreen( toolRect.GetPosition() ) );
1038
1039 // True for vertical buttons, false for horizontal
1040 bool dir = pane.dock_direction != wxAUI_DOCK_LEFT && pane.dock_direction != wxAUI_DOCK_RIGHT;
1041
1042 m_palette = new ACTION_TOOLBAR_PALETTE( GetParent(), dir );
1043
1044 m_palette->SetGroup( group );
1045 m_palette->SetButtonSize( toolRect );
1046 m_palette->Connect( wxEVT_BUTTON, wxCommandEventHandler( ACTION_TOOLBAR::onPaletteEvent ), nullptr, this );
1047
1048
1049 for( const TOOL_ACTION* action : group->m_actions )
1050 {
1051 wxUpdateUIEvent evt( action->GetUIId() );
1052
1053 toolParent->ProcessWindowEvent( evt );
1054
1055 m_palette->AddAction( *action );
1056
1057 if( evt.GetSetEnabled() )
1058 m_palette->EnableAction( *action, evt.GetEnabled() );
1059 }
1060
1061 wxSize paletteSize = m_palette->GetFittedSize();
1062
1063 // Determine the position of the top left corner of the palette window
1064 switch( pane.dock_direction )
1065 {
1066 case wxAUI_DOCK_TOP:
1067 // Top toolbars need to shift the palette window down by the toolbar padding
1068 pos = ClientToScreen( toolRect.GetBottomLeft() );
1069 pos += wxPoint( -PALETTE_BORDER, // Shift left to align the button edges
1070 m_bottomPadding ); // Shift down to move away from the toolbar
1071 break;
1072
1073 case wxAUI_DOCK_BOTTOM:
1074 // Bottom toolbars need to shift the palette window up by its height (all buttons +
1075 // border + toolbar padding)
1076 pos = ClientToScreen( toolRect.GetTopLeft() );
1077 pos += wxPoint( -PALETTE_BORDER, // Shift left to align the button
1078 // Shift up by the entire length of the palette.
1079 -( paletteSize.GetHeight() + m_topPadding ) );
1080 break;
1081
1082 case wxAUI_DOCK_LEFT:
1083 // Left toolbars open the palette to the right, with a small extra nudge so it does not
1084 // paint over the toolbar icon that opened it.
1085 pos = ClientToScreen( toolRect.GetTopRight() );
1086 pos += wxPoint( m_rightPadding + PALETTE_BORDER, 0 );
1087 break;
1088
1089 case wxAUI_DOCK_RIGHT:
1090 // Right toolbars need to shift the palette window left by its width (all buttons +
1091 // border + toolbar padding)
1092 pos = ClientToScreen( toolRect.GetTopLeft() );
1093
1094 // Shift left by the palette length, with a small extra nudge so it does not paint over
1095 // the toolbar icon that opened it.
1096 pos += wxPoint( -( paletteSize.GetWidth() + m_leftPadding + PALETTE_BORDER ), 0 );
1097 break;
1098 }
1099
1100 // Release the mouse to ensure the first click will be recognized in the palette
1101 if( HasCapture() )
1102 ReleaseMouse();
1103
1104 m_palette->SetPosition( pos );
1105 m_palette->Popup();
1106
1107 // Clear the mouse state on the toolbar because otherwise wxWidgets gets confused
1108 // and won't properly display any highlighted items after the palette is closed.
1109 // (This is the equivalent of calling the DoResetMouseState() private function)
1110 RefreshOverflowState();
1111 SetHoverItem( nullptr );
1112 SetPressedItem( nullptr );
1113
1114 m_dragging = false;
1115 m_tipItem = nullptr;
1116 m_actionPos = wxPoint( -1, -1 );
1117 m_actionItem = nullptr;
1118}
1119
1120
1121void ACTION_TOOLBAR::OnCustomRender(wxDC& aDc, const wxAuiToolBarItem& aItem, const wxRect& aRect )
1122{
1123 auto it = m_actionGroups.find( aItem.GetId() );
1124
1125 if( it == m_actionGroups.end() )
1126 return;
1127
1128 // Choose the color to draw the triangle
1129 wxColour clr;
1130
1131 if( aItem.GetState() & wxAUI_BUTTON_STATE_DISABLED )
1132 clr = wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT );
1133 else
1134 clr = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNTEXT );
1135
1136 // Must set both the pen (for the outline) and the brush (for the polygon fill)
1137 aDc.SetPen( wxPen( clr ) );
1138 aDc.SetBrush( wxBrush( clr ) );
1139
1140 // Make the side length of the triangle approximately 1/5th of the bitmap
1141 int sideLength = KiROUND( aRect.height / 5.0 );
1142
1143 // This will create a triangle with its point at the bottom right corner,
1144 // and its other two corners along the right and bottom sides
1145 wxPoint btmRight = aRect.GetBottomRight();
1146 wxPoint topCorner( btmRight.x, btmRight.y - sideLength );
1147 wxPoint btmCorner( btmRight.x - sideLength, btmRight.y );
1148
1149 wxPointList points;
1150 points.Append( &btmRight );
1151 points.Append( &topCorner );
1152 points.Append( &btmCorner );
1153
1154 aDc.DrawPolygon( &points );
1155}
1156
1157
1159{
1160#if wxCHECK_VERSION( 3, 3, 0 )
1161 return Realize();
1162#else
1163 wxClientDC dc( this );
1164
1165 if( !dc.IsOk() )
1166 return false;
1167
1168 // calculate hint sizes for both horizontal and vertical
1169 // in the order that leaves toolbar in correct final state
1170
1171 // however, skip calculating alternate orientations if we don't need them due to window style
1172 bool retval = true;
1173
1174 if( m_orientation == wxHORIZONTAL )
1175 {
1176 if( !( GetWindowStyle() & wxAUI_TB_HORIZONTAL ) )
1177 {
1178 m_vertHintSize = GetSize();
1179 retval = RealizeHelper( dc, false );
1180 }
1181
1182 if( retval && RealizeHelper( dc, true ) )
1183 m_horzHintSize = GetSize();
1184 else
1185 retval = false;
1186 }
1187 else
1188 {
1189 if( !( GetWindowStyle() & wxAUI_TB_VERTICAL ) )
1190 {
1191 m_horzHintSize = GetSize();
1192 retval = RealizeHelper( dc, true );
1193 }
1194
1195 if( retval && RealizeHelper( dc, false ) )
1196 m_vertHintSize = GetSize();
1197 else
1198 retval = false;
1199 }
1200
1201 Refresh( false );
1202 return retval;
1203#endif
1204}
1205
1206
1207void ACTION_TOOLBAR::onThemeChanged( wxSysColourChangedEvent &aEvent )
1208{
1211
1212 aEvent.Skip();
1213}
1214
1215
1217{
1219
1220 for( const std::pair<int, const TOOL_ACTION*> pair : m_toolActions )
1221 {
1222 wxAuiToolBarItem* tool = FindTool( pair.first );
1223
1224 tool->SetBitmap( KiBitmapBundleDef( pair.second->GetIcon(), iconSize ) );
1225 tool->SetDisabledBitmap( KiDisabledBitmapBundleDef( pair.second->GetIcon(), iconSize ) );
1226 }
1227
1228 Refresh();
1229}
1230
1231/*
1232 * Common controls for the toolbar
1233 */
1235 _( "Grid selector" ),
1236 _( "Grid Selection box" ),
1237 { FRAME_SCH,
1244 FRAME_PL_EDITOR } );
1245
1246
1248 _( "Zoom selector" ),
1249 _( "Zoom Selection box" ),
1250 { FRAME_SCH,
1258 FRAME_PL_EDITOR } );
1259
1261 _( "IPC/Scripting plugins" ),
1262 _( "Region to hold the IPC/Scripting action buttons" ),
1263 { FRAME_SCH,
1264 FRAME_PCB_EDITOR } );
1265
1267 _( "Layer selector" ),
1268 _( "Control to select the layer" ),
1272 FRAME_GERBER } );
1273
1275 _( "Symbol unit selector" ),
1276 _( "Displays the current unit" ),
1278 FRAME_SCH_VIEWER } );
1279
1281 _( "Symbol body style selector" ),
1282 _( "Displays the current body style" ),
1284 FRAME_SCH_VIEWER } );
1285
1287 _( "Override locks" ),
1288 _( "Allow moving of locked items with the mouse" ),
#define PALETTE_BORDER
#define PALETTE_OPEN_DELAY
#define BUTTON_BORDER
std::function< void(ACTION_TOOLBAR *)> ACTION_TOOLBAR_CONTROL_FACTORY
Type for the function signature that is used to add custom controls to the toolbar.
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:112
int KiIconScale(wxWindow *aWindow)
Return the automatic scale factor that would be used for a given window by KiScaledBitmap and KiScale...
Definition bitmap.cpp:130
BITMAP_STORE * GetBitmapStore()
Definition bitmap.cpp:88
KICOMMON_API wxBitmapBundle KiDisabledBitmapBundleDef(BITMAPS aBitmap, int aDefHeight)
Definition bitmap.cpp:124
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:995
A group of actions that will be displayed together on a toolbar palette.
void SetDefaultAction(const TOOL_ACTION &aDefault)
Set the default action to use when first creating the toolbar palette icon.
ACTION_GROUP(const std::string_view &aName)
std::vector< const TOOL_ACTION * > m_actions
void SetActions(const std::vector< const TOOL_ACTION * > &aActions)
Set the actions contained in this group.
int GetUIId() const
Get the ID used in the UI to reference this group.
int m_id
< The action ID for this action group
const TOOL_ACTION * m_defaultAction
The actions that compose the group. Non-owning.
std::string m_name
The default action to display on the toolbar item.
std::string GetName() const
Get the name of the group.
static int MakeActionId(const std::string &aActionName)
Generate an unique ID from for an action with given name.
Define the structure of a menu based on ACTIONs.
Definition action_menu.h:43
void UpdateAll()
Run update handlers for the menu and its submenus.
static ACTION_TOOLBAR_CONTROL gridSelect
static ACTION_TOOLBAR_CONTROL overrideLocks
static ACTION_TOOLBAR_CONTROL layerSelector
static ACTION_TOOLBAR_CONTROL zoomSelect
static ACTION_TOOLBAR_CONTROL unitSelector
static ACTION_TOOLBAR_CONTROL ipcScripting
static ACTION_TOOLBAR_CONTROL bodyStyleSelector
Class to hold basic information about controls that can be added to the toolbars.
A popup window that contains a row of toolbar-like buttons for the user to choose from.
void CheckAction(const TOOL_ACTION &aAction, bool aCheck=true)
Check/Toggle the button for an action on the palette.
void onCharHook(wxKeyEvent &aEvent)
wxBoxSizer * m_buttonSizer
The buttons that act as the toolbar on the palette.
void AddAction(const TOOL_ACTION &aAction)
Add an action to the palette.
ACTION_TOOLBAR_PALETTE(wxWindow *aParent, bool aVertical)
Create the palette.
wxRect m_buttonSize
True if the palette uses vertical buttons, false for horizontal buttons.
void EnableAction(const TOOL_ACTION &aAction, bool aEnable=true)
Enable the button for an action on the palette.
ACTION_GROUP * m_group
The size each button on the toolbar should be.
std::map< int, BITMAP_BUTTON * > m_buttons
ACTION_GROUP * GetGroup()
void Popup(wxWindow *aFocus=nullptr) override
Popup this window.
void RefreshBitmaps()
Reload all the bitmaps for the tools (e.g.
void SetToolBitmap(const TOOL_ACTION &aAction, const wxBitmapBundle &aBitmap)
Updates the bitmap of a particular tool.
void OnCustomRender(wxDC &aDc, const wxAuiToolBarItem &aItem, const wxRect &aRect) override
void onTimerDone(wxTimerEvent &aEvent)
void doSelectAction(ACTION_GROUP *aGroup, const TOOL_ACTION &aAction)
Update a group toolbar item to look like a specific action.
void onMouseClick(wxMouseEvent &aEvent)
Handler for when a drag event occurs on an item.
void AddButton(const TOOL_ACTION &aAction)
Add a large button such as used in the KiCad Manager Frame's launch bar.
wxAuiManager * m_auiManager
void UpdateControlWidth(int aID)
Update the toolbar item width of a control using its best size.
ACTION_TOOLBAR(EDA_BASE_FRAME *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxAUI_TB_DEFAULT_STYLE)
void Toggle(const TOOL_ACTION &aAction, bool aState)
Apply the default toggle action.
void SelectAction(ACTION_GROUP *aGroup, const TOOL_ACTION &aAction)
Select an action inside a group.
void Add(const TOOL_ACTION &aAction)
Add a TOOL_ACTION-based button to the toolbar.
static std::list< ACTION_TOOLBAR_CONTROL * > & GetAllCustomControls()
Get the list of custom controls that could be used on toolbars.
void onPaletteEvent(wxCommandEvent &aEvent)
Handle the palette timer triggering.
void onRightClick(wxAuiToolBarEvent &aEvent)
Handle a right mouse button release; resolves the tool ourselves to work around a wxAuiToolBar hit-te...
wxTimer * m_paletteTimer
std::map< int, std::unique_ptr< ACTION_MENU > > m_toolMenus
void onToolEvent(wxAuiToolBarEvent &aEvent)
Handle a right-click on a menu item.
void onItemDrag(wxAuiToolBarEvent &aEvent)
The default tool event handler.
std::map< int, bool > m_toolKinds
static std::list< ACTION_TOOLBAR_CONTROL * > GetCustomControlList(FRAME_T aContext)
Get the list of custom controls that could be used on a particular frame type.
std::map< int, std::unique_ptr< ACTION_GROUP > > m_actionGroups
void AddGroup(std::unique_ptr< ACTION_GROUP > aGroup)
Add a set of actions to a toolbar as a group.
void AddToolContextMenu(const TOOL_ACTION &aAction, std::unique_ptr< ACTION_MENU > aMenu)
Add a context menu to a specific tool item on the toolbar.
void DoSetToolTipText(const wxString &aTip) override
std::map< int, bool > m_toolCancellable
void AddScaledSeparator(wxWindow *aWindow)
Add a separator that introduces space on either side to not squash the tools when scaled.
bool KiRealize()
Use this over Realize() to avoid a rendering glitch with fixed orientation toolbars.
void popupPalette(wxAuiToolBarItem *aItem)
Popup the ACTION_TOOLBAR_PALETTE associated with the ACTION_GROUP of the given toolbar item.
virtual ~ACTION_TOOLBAR()
ACTION_TOOLBAR_PALETTE * m_palette
std::vector< int > m_controlIDs
IDs for all the control items in this toolbar.
void onThemeChanged(wxSysColourChangedEvent &aEvent)
Render the triangle in the lower-right corner that represents that an action palette is available for...
EDA_BASE_FRAME * m_parent
std::map< int, const TOOL_ACTION * > m_toolActions
std::map< std::string, std::string > m_groupSelections
Selected action per group name.
void ClearToolbar()
Clear the toolbar and remove all associated menus.
void onRightUp(wxMouseEvent &aEvent)
Show the context menu registered for the given tool ID (handles group remapping).
void showContextMenu(int aToolId)
Handle the button select inside the palette.
void UpdateControlWidths()
Update the width of all wxControl tools on thsi toolbar.
void ApplyConfiguration(const TOOLBAR_CONFIGURATION &aConfig)
Replace the contents of this toolbar with the configuration given in aConfig.
TOOL_MANAGER * m_toolManager
A bitmap button widget that behaves like an AUI toolbar item's button when it is drawn.
void AcceptDragInAsClick(bool aAcceptDragIn=true)
Accept mouse-up as click even if mouse-down happened outside of the control.
void SetDisabledBitmap(const wxBitmapBundle &aBmp)
Set the bitmap shown when the button is disabled.
void SetBitmapCentered(bool aCentered=true)
void SetIsToolbarButton(bool aIsToolbar=true)
void SetPadding(int aPaddingDIP)
Set the amount of padding present on each side of the bitmap.
void SetBitmap(const wxBitmapBundle &aBmp)
Set the bitmap shown when the button is enabled.
void ThemeChanged()
Notifies the store that the icon theme has been changed by the user, so caches must be invalidated.
APPEARANCE m_Appearance
The base frame for deriving all KiCad main window classes.
ACTION_TOOLBAR_CONTROL_FACTORY * GetCustomToolbarControlFactory(const std::string &aName)
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition pgm_base.cpp:546
std::vector< TOOLBAR_ITEM > GetToolbarItems() const
static MENU_FACTORY GetMenuFactory(const std::string &aActionName)
Get the menu factory for an action, if one is registered.
static MENU_FACTORY GetGroupMenuFactory(const std::string &aGroupName)
Get the menu factory for a group, if one is registered.
std::vector< TOOLBAR_ITEM > m_GroupItems
std::string m_ActionName
TOOLBAR_ITEM_TYPE m_Type
Represent a single user action.
static int GetBaseUIId()
Get the base value used to offset the user interface IDs for the actions.
BITMAPS GetIcon() const
Return an icon associated with the action.
int GetId() const
Return the unique id of the TOOL_ACTION object.
const std::string & GetName() const
Return name of the action.
bool CheckToolbarState(TOOLBAR_STATE aState) const
Check if a specific toolbar state is required for this action.
TOOL_EVENT MakeEvent() const
Return the event associated with the action (i.e.
wxString GetButtonTooltip() const
int GetUIId() const
Get the unique ID for this action in the user interface system.
void SetHasPosition(bool aHasPosition)
Definition tool_event.h:257
#define _(s)
FRAME_T
The set of EDA_BASE_FRAME derivatives, typically stored in EDA_BASE_FRAME::m_Ident.
Definition frame_type.h:29
@ FRAME_PCB_EDITOR
Definition frame_type.h:38
@ FRAME_SCH_SYMBOL_EDITOR
Definition frame_type.h:31
@ FRAME_FOOTPRINT_VIEWER
Definition frame_type.h:41
@ FRAME_SCH_VIEWER
Definition frame_type.h:32
@ FRAME_SCH
Definition frame_type.h:30
@ FRAME_PL_EDITOR
Definition frame_type.h:55
@ FRAME_FOOTPRINT_EDITOR
Definition frame_type.h:39
@ FRAME_GERBER
Definition frame_type.h:53
@ FRAME_PCB_DISPLAY3D
Definition frame_type.h:43
const wxChar *const kicadTraceToolStack
Flag to enable tracing of the tool handling stack.
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition wxgtk/ui.cpp:839
bool IsDarkTheme()
Determine if the desktop interface is currently using a dark theme or a light theme.
Definition wxgtk/ui.cpp:51
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
CITER next(CITER it)
Definition ptree.cpp:120
const int scale
Functors that can be used to figure out how the action controls should be displayed in the UI and if ...
@ TOGGLE
Action is a toggle button on the toolbar.
Definition tool_action.h:60
@ CANCEL
Action can be cancelled by clicking the toolbar button again.
Definition tool_action.h:61
@ HIDDEN
Action is hidden from the toolbar.
Definition tool_action.h:59
std::optional< TOOL_EVENT > OPT_TOOL_EVENT
Definition tool_event.h:637
wxLogTrace helper definitions.