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