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