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