KiCad PCB EDA Suite
Loading...
Searching...
No Matches
action_menu.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) 2013-2019 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Tomasz Wlostowski <[email protected]>
7 * @author Maciej Suminski <[email protected]>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23#include "tool/action_menu.h"
24
25#include <wx/grid.h>
26#include <wx/listctrl.h>
27#include <wx/log.h>
28#include <wx/textentry.h>
29#include <wx/stc/stc.h>
30
31#include <bitmaps.h>
32#include <eda_base_frame.h>
33#include <functional>
34#include <id.h>
35#include <kiface_base.h>
36#include <tool/actions.h>
37#include <tool/tool_event.h>
39#include <tool/tool_manager.h>
40#include <trace_helpers.h>
41#include <textentry_tricks.h>
42#include <widgets/ui_common.h>
43
44using namespace std::placeholders;
45
46
47ACTION_MENU::ACTION_MENU( bool isContextMenu, TOOL_INTERACTIVE* aTool ) :
48 m_isForcedPosition( false ),
49 m_dirty( true ),
50 m_titleDisplayed( false ),
51 m_isContextMenu( isContextMenu ),
53 m_selected( -1 ),
54 m_tool( aTool )
55{
57}
58
59
61{
62 Disconnect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( ACTION_MENU::OnMenuEvent ), nullptr, this );
63 Disconnect( wxEVT_IDLE, wxIdleEventHandler( ACTION_MENU::OnIdle ), nullptr, this );
64
65 // Explicitly release the GDI resources
66 for( auto subitem : GetMenuItems() )
67 subitem->SetBitmap( wxNullBitmap );
68
69 // Set parent to NULL to prevent submenus from unregistering from a nonexistent object
70 for( ACTION_MENU* menu : m_submenus )
71 {
72 for( auto menuItem : GetMenuItems() )
73 menuItem->SetBitmap( wxNullBitmap );
74
75 menu->SetParent( nullptr );
76 }
77
78 ACTION_MENU* parent = dynamic_cast<ACTION_MENU*>( GetParent() );
79
80 if( parent )
81 parent->m_submenus.remove( this );
82}
83
84
86{
87 m_icon = aIcon;
88}
89
90
92{
93 Connect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( ACTION_MENU::OnMenuEvent ), nullptr, this );
94 Connect( wxEVT_IDLE, wxIdleEventHandler( ACTION_MENU::OnIdle ), nullptr, this );
95}
96
97
98void ACTION_MENU::SetTitle( const wxString& aTitle )
99{
100 // Unfortunately wxMenu::SetTitle() does not work very well, so this is an alternative version
101 m_title = aTitle;
102
103 // Update the menu title
104 if( m_titleDisplayed )
105 DisplayTitle( true );
106}
107
108
109void ACTION_MENU::DisplayTitle( bool aDisplay )
110{
111 if( ( !aDisplay || m_title.IsEmpty() ) && m_titleDisplayed )
112 {
113 // Destroy the menu entry keeping the title..
114 wxMenuItem* item = FindItemByPosition( 0 );
115 wxASSERT( item->GetItemLabelText() == GetTitle() );
116 item->SetBitmap( wxNullBitmap );
117 Destroy( item );
118
119 // ..and separator
120 item = FindItemByPosition( 0 );
121 wxASSERT( item->IsSeparator() );
122 Destroy( item );
123 m_titleDisplayed = false;
124 }
125
126 else if( aDisplay && !m_title.IsEmpty() )
127 {
128 if( m_titleDisplayed )
129 {
130 // Simply update the title
131 FindItemByPosition( 0 )->SetItemLabel( m_title );
132 }
133 else
134 {
135 // Add a separator and a menu entry to display the title
136 InsertSeparator( 0 );
137 Insert( 0, new wxMenuItem( this, wxID_NONE, m_title, wxEmptyString, wxITEM_NORMAL ) );
138
139 if( !!m_icon )
140 KIUI::AddBitmapToMenuItem( FindItemByPosition( 0 ), KiBitmapBundle( m_icon ) );
141
142 m_titleDisplayed = true;
143 }
144 }
145}
146
147
148wxMenuItem* ACTION_MENU::Add( const wxString& aLabel, int aId, BITMAPS aIcon )
149{
150 wxASSERT_MSG( FindItem( aId ) == nullptr, wxS( "Duplicate menu IDs!" ) );
151
152 wxMenuItem* item = new wxMenuItem( this, aId, aLabel, wxEmptyString, wxITEM_NORMAL );
153
154 if( !!aIcon )
156
157 return Append( item );
158}
159
160
161wxMenuItem* ACTION_MENU::Add( const wxString& aLabel, const wxString& aTooltip, int aId,
162 BITMAPS aIcon, bool aIsCheckmarkEntry )
163{
164 wxASSERT_MSG( FindItem( aId ) == nullptr, wxS( "Duplicate menu IDs!" ) );
165
166 wxMenuItem* item = new wxMenuItem( this, aId, aLabel, aTooltip, aIsCheckmarkEntry ? wxITEM_CHECK
167 : wxITEM_NORMAL );
168
169 if( !!aIcon )
171
172 return Append( item );
173}
174
175
176wxMenuItem* ACTION_MENU::Add( const TOOL_ACTION& aAction, bool aIsCheckmarkEntry,
177 const wxString& aOverrideLabel )
178{
179 // ID numbers for tool actions are assigned above ACTION_BASE_UI_ID inside TOOL_EVENT
180 BITMAPS icon = aAction.GetIcon();
181
182 // Allow the label to be overridden at point of use
183 wxString menuLabel = aOverrideLabel.IsEmpty() ? aAction.GetMenuItem() : aOverrideLabel;
184
185 wxMenuItem* item = new wxMenuItem( this, aAction.GetUIId(), menuLabel, aAction.GetTooltip(),
186 aIsCheckmarkEntry ? wxITEM_CHECK : wxITEM_NORMAL );
187 if( !!icon )
189
190 m_toolActions[aAction.GetUIId()] = &aAction;
191
192 return Append( item );
193}
194
195
196wxMenuItem* ACTION_MENU::Add( ACTION_MENU* aMenu )
197{
198 m_submenus.push_back( aMenu );
199
200 wxASSERT_MSG( !aMenu->m_title.IsEmpty(), wxS( "Set a title for ACTION_MENU using SetTitle()" ) );
201
202 if( !!aMenu->m_icon )
203 {
204 wxMenuItem* newItem = new wxMenuItem( this, -1, aMenu->m_title );
205 KIUI::AddBitmapToMenuItem( newItem, KiBitmapBundle( aMenu->m_icon ) );
206 newItem->SetSubMenu( aMenu );
207 return Append( newItem );
208 }
209 else
210 {
211 return AppendSubMenu( aMenu, aMenu->m_title );
212 }
213}
214
215
216void ACTION_MENU::AddClose( const wxString& aAppname )
217{
218#ifdef __WINDOWS__
219 Add( _( "Close" ),
220 wxString::Format( _( "Close %s" ), aAppname ),
221 wxID_CLOSE,
223#else
224 Add( _( "Close" ) + wxS( "\tCtrl+W" ),
225 wxString::Format( _( "Close %s" ), aAppname ),
226 wxID_CLOSE,
228#endif
229}
230
231
232void ACTION_MENU::AddQuitOrClose( KIFACE_BASE* aKiface, wxString aAppname )
233{
234 if( !aKiface || aKiface->IsSingle() ) // not when under a project mgr
235 {
236 // Don't use ACTIONS::quit; wxWidgets moves this on OSX and expects to find it via
237 // wxID_EXIT
238 Add( _( "Quit" ) + wxS( "\tCtrl+Q" ),
239 wxString::Format( _( "Quit %s" ), aAppname ),
240 wxID_EXIT,
242 }
243 else
244 {
245 AddClose( aAppname );
246 }
247}
248
249
250void ACTION_MENU::AddQuit( const wxString& aAppname )
251{
252 // Don't use ACTIONS::quit; wxWidgets moves this on OSX and expects to find it via
253 // wxID_EXIT
254 Add( _( "Quit" ) + wxS( "\tCtrl+Q" ),
255 wxString::Format( _( "Quit %s" ), aAppname ),
256 wxID_EXIT,
258}
259
260
262{
263 m_titleDisplayed = false;
264
265 for( int i = GetMenuItemCount() - 1; i >= 0; --i )
266 Destroy( FindItemByPosition( i ) );
267
268 m_toolActions.clear();
269 m_submenus.clear();
270
271 wxASSERT( GetMenuItemCount() == 0 );
272}
273
274
276{
277 for( wxMenuItem* item : GetMenuItems() )
278 {
279 if( item->IsEnabled() && !item->IsSeparator() )
280 return true;
281 }
282
283 return false;
284}
285
286
288{
289 try
290 {
291 update();
292 }
293 catch( std::exception& )
294 {
295 }
296
297 if( m_tool )
299
300 runOnSubmenus( std::bind( &ACTION_MENU::UpdateAll, _1 ) );
301}
302
303
305{
306 m_dirty = false;
307 runOnSubmenus( std::bind( &ACTION_MENU::ClearDirty, _1 ) );
308}
309
310
312{
313 m_dirty = true;
314 runOnSubmenus( std::bind( &ACTION_MENU::SetDirty, _1 ) );
315}
316
317
319{
320 m_tool = aTool;
321 runOnSubmenus( std::bind( &ACTION_MENU::SetTool, _1, aTool ) );
322}
323
324
326{
327 ACTION_MENU* clone = create();
328 clone->Clear();
329 clone->copyFrom( *this );
330 return clone;
331}
332
333
335{
336 ACTION_MENU* menu = new ACTION_MENU( false );
337
338 wxASSERT_MSG( typeid( *this ) == typeid( *menu ),
339 wxString::Format( "You need to override create() method for class %s", typeid( *this ).name() ) );
340
341 return menu;
342}
343
344
346{
347 return m_tool ? m_tool->GetManager() : nullptr;
348}
349
350
352{
353 TOOL_MANAGER* toolMgr = getToolManager();
354
355 wxASSERT( toolMgr );
356
357 for( std::pair<const int, const TOOL_ACTION*>& ii : m_toolActions )
358 {
359 int id = ii.first;
360 const TOOL_ACTION& action = *ii.second;
361 int key = toolMgr->GetHotKey( action ) & ~MD_MODIFIER_MASK;
362
363 if( key > 0 )
364 {
365 int mod = toolMgr->GetHotKey( action ) & MD_MODIFIER_MASK;
366 int flags = 0;
367 wxMenuItem* item = FindChildItem( id );
368
369 if( item )
370 {
371 flags |= ( mod & MD_ALT ) ? wxACCEL_ALT : 0;
372 flags |= ( mod & MD_CTRL ) ? wxACCEL_CTRL : 0;
373 flags |= ( mod & MD_SHIFT ) ? wxACCEL_SHIFT : 0;
374
375 if( !flags )
376 flags = wxACCEL_NORMAL;
377
378 wxAcceleratorEntry accel( flags, key, id, item );
379 item->SetAccel( &accel );
380 }
381 }
382 }
383}
384
385
386// wxWidgets doesn't tell us when a menu command was generated from a hotkey or from
387// a menu selection. It's important to us because a hotkey can be an immediate action
388// while the menu selection can not (as it has no associated position).
389//
390// We get around this by storing the last highlighted menuId. If it matches the command
391// id then we know this is a menu selection. (You might think we could use the menuOpen
392// menuClose events, but these are actually generated for hotkeys as well.)
393
395
396
397// We need to store the position of the mouse when the menu was opened so it can be passed
398// to the command event generated when the menu item is selected.
400
401
402void ACTION_MENU::OnIdle( wxIdleEvent& event )
403{
405 g_menu_open_position.x = 0.0;
406 g_menu_open_position.y = 0.0;
407}
408
409
410void ACTION_MENU::OnMenuEvent( wxMenuEvent& aEvent )
411{
412 OPT_TOOL_EVENT evt;
413 wxString menuText;
414 wxEventType type = aEvent.GetEventType();
415 wxWindow* focus = wxWindow::FindFocus();
416 TOOL_MANAGER* toolMgr = getToolManager();
417
418 if( type == wxEVT_MENU_OPEN )
419 {
420 if( m_dirty && toolMgr )
421 toolMgr->RunAction<ACTION_MENU*>( ACTIONS::updateMenu, this );
422
423 wxMenu* parent = dynamic_cast<wxMenu*>( GetParent() );
424
425 // Don't update the position if this menu has a parent or is a menubar menu
426 if( !parent && !IsAttached() && toolMgr )
428
430 }
431 else if( type == wxEVT_MENU_HIGHLIGHT )
432 {
433 if( aEvent.GetId() > 0 )
434 g_last_menu_highlighted_id = aEvent.GetId();
435
436 evt = TOOL_EVENT( TC_COMMAND, TA_CHOICE_MENU_UPDATE, aEvent.GetId() );
437 }
438 else if( type == wxEVT_COMMAND_MENU_SELECTED )
439 {
440 // Despite our attempts to catch the theft of text editor CHAR_HOOK and CHAR events
441 // in TOOL_DISPATCHER::DispatchWxEvent, wxWidgets sometimes converts those it knows
442 // about into menu commands without ever generating the appropriate CHAR_HOOK and CHAR
443 // events first.
444 if( dynamic_cast<wxTextEntry*>( focus )
445 || dynamic_cast<wxStyledTextCtrl*>( focus )
446 || dynamic_cast<wxListView*>( focus )
447 || dynamic_cast<wxGrid*>( focus ) )
448 {
449 // Original key event has been lost, so we have to re-create it from the menu's
450 // wxAcceleratorEntry.
451 wxMenuItem* menuItem = FindItem( aEvent.GetId() );
452 wxAcceleratorEntry* acceleratorKey = menuItem ? menuItem->GetAccel() : nullptr;
453
454 if( acceleratorKey )
455 {
456 wxKeyEvent keyEvent( wxEVT_CHAR_HOOK );
457 keyEvent.m_keyCode = acceleratorKey->GetKeyCode();
458 keyEvent.m_controlDown = ( acceleratorKey->GetFlags() & wxMOD_CONTROL ) > 0;
459 keyEvent.m_shiftDown = ( acceleratorKey->GetFlags() & wxMOD_SHIFT ) > 0;
460 keyEvent.m_altDown = ( acceleratorKey->GetFlags() & wxMOD_ALT ) > 0;
461
462 if( wxTextEntry* ctrl = dynamic_cast<wxTextEntry*>( focus ) )
463 TEXTENTRY_TRICKS::OnCharHook( ctrl, keyEvent );
464 else
465 focus->HandleWindowEvent( keyEvent );
466
467 if( keyEvent.GetSkipped() )
468 {
469 keyEvent.SetEventType( wxEVT_CHAR );
470
471 // CHAR_HOOK always uses uppercase key codes for letters, but
472 // wxEVT_CHAR should use the translated (case-correct) character.
473 // Since the original key event was lost to the menu system, check
474 // the actual keyboard state to determine proper case.
475 int keyCode = keyEvent.GetKeyCode();
476
477 if( keyCode >= 'A' && keyCode <= 'Z' )
478 {
479 bool shiftActive = wxGetKeyState( WXK_SHIFT );
480 bool capsActive = wxGetKeyState( WXK_CAPITAL );
481
482 if( !( shiftActive ^ capsActive ) )
483 keyEvent.m_keyCode = keyCode + 32; // Convert to lowercase
484 }
485
486 #if wxUSE_UNICODE
487 keyEvent.m_uniChar = keyEvent.m_keyCode;
488 #endif
489
490 focus->HandleWindowEvent( keyEvent );
491 }
492
493 // Don't bubble-up dangerous actions; the target may be behind a modeless dialog.
494 // Cf. https://gitlab.com/kicad/code/kicad/-/issues/17229
495 if( keyEvent.GetKeyCode() == WXK_BACK || keyEvent.GetKeyCode() == WXK_DELETE )
496 return;
497
498 // If the event was used as a KEY event (not skipped) by the focused window,
499 // just finish. Otherwise this is actually a wxEVT_COMMAND_MENU_SELECTED (or the
500 // focused window is read only).
501 if( !keyEvent.GetSkipped() )
502 return;
503 }
504 }
505
506 // Store the selected position, so it can be checked by the tools
507 m_selected = aEvent.GetId();
508
509 ACTION_MENU* parent = dynamic_cast<ACTION_MENU*>( GetParent() );
510
511 while( parent )
512 {
513 parent->m_selected = m_selected;
514 parent = dynamic_cast<ACTION_MENU*>( parent->GetParent() );
515 }
516
517 // Check if there is a TOOL_ACTION for the given UI ID
518 if( toolMgr && toolMgr->GetActionManager()->IsActionUIId( m_selected ) )
519 evt = findToolAction( m_selected );
520
521 if( !evt )
522 {
523#ifdef __WINDOWS__
524 if( !evt )
525 {
526 // Try to find the submenu which holds the selected item
527 wxMenu* menu = nullptr;
528 FindItem( m_selected, &menu );
529
530 // This conditional compilation is probably not needed.
531 if( menu )
532 {
533 ACTION_MENU* cxmenu = static_cast<ACTION_MENU*>( menu );
534 evt = cxmenu->eventHandler( aEvent );
535 }
536 }
537#else
538 if( !evt )
539 runEventHandlers( aEvent, evt );
540#endif
541
542 // Handling non-ACTION menu entries. Two ranges of ids are supported:
543 // between 0 and ID_CONTEXT_MENU_ID_MAX
544 // between ID_POPUP_MENU_START and ID_POPUP_MENU_END
545
546 #define ID_CONTEXT_MENU_ID_MAX wxID_LOWEST /* = 100 should be plenty */
547
548 if( !evt && ( ( m_selected >= 0 && m_selected < ID_CONTEXT_MENU_ID_MAX )
550 {
551 ACTION_MENU* actionMenu = dynamic_cast<ACTION_MENU*>( GetParent() );
552
553 if( PassHelpTextToHandler() || ( actionMenu && actionMenu->PassHelpTextToHandler() ) )
554 menuText = GetHelpString( aEvent.GetId() );
555 else
556 menuText = GetLabelText( aEvent.GetId() );
557
559 evt->SetParameter( &menuText );
560 }
561 }
562 }
563
564 // forward the action/update event to the TOOL_MANAGER
565 // clients that don't supply a tool will have to check GetSelected() themselves
566 if( evt && toolMgr )
567 {
568 wxLogTrace( kicadTraceToolStack, wxS( "ACTION_MENU::OnMenuEvent %s" ), evt->Format() );
569
570 // WARNING: if you're squeamish, look away.
571 // What follows is a series of egregious hacks necessitated by a lack of information from
572 // wxWidgets on where context-menu-commands and command-key-events originated.
573
574 // If it's a context menu then fetch the mouse position from our context-menu-position
575 // hack.
576 if( m_isContextMenu )
577 {
578 evt->SetMousePosition( g_menu_open_position );
579 }
580 // Check if it is a menubar event, and don't get any position if it is. Note that we
581 // can't use IsAttached() here, as it only differentiates a context menu, and we also
582 // want a hotkey to generate a position.
583 else if( g_last_menu_highlighted_id == aEvent.GetId() )
584 {
585 evt->SetHasPosition( false );
586 }
587 // Otherwise it's a command-key-event and we need to get the mouse position from the tool
588 // manager so that immediate actions work.
589 else
590 {
591 evt->SetMousePosition( toolMgr->GetMousePosition() );
592 }
593
594 toolMgr->ProcessEvent( *evt );
595 }
596 else
597 {
598 aEvent.Skip();
599 }
600}
601
602
603void ACTION_MENU::runEventHandlers( const wxMenuEvent& aMenuEvent, OPT_TOOL_EVENT& aToolEvent )
604{
605 aToolEvent = eventHandler( aMenuEvent );
606
607 if( !aToolEvent )
608 runOnSubmenus( std::bind( &ACTION_MENU::runEventHandlers, _1, aMenuEvent, aToolEvent ) );
609}
610
611
612void ACTION_MENU::runOnSubmenus( std::function<void(ACTION_MENU*)> aFunction )
613{
614 try
615 {
616 std::for_each( m_submenus.begin(), m_submenus.end(),
617 [&]( ACTION_MENU* m )
618 {
619 aFunction( m );
620 m->runOnSubmenus( aFunction );
621 } );
622 }
623 catch( std::exception& )
624 {
625 }
626}
627
628
630{
631 OPT_TOOL_EVENT evt;
632
633 auto findFunc =
634 [&]( ACTION_MENU* m )
635 {
636 if( evt )
637 return;
638
639 const auto it = m->m_toolActions.find( aId );
640
641 if( it != m->m_toolActions.end() )
642 evt = it->second->MakeEvent();
643 };
644
645 findFunc( this );
646
647 if( !evt )
648 runOnSubmenus( findFunc );
649
650 return evt;
651}
652
653
655{
656 m_icon = aMenu.m_icon;
657 m_title = aMenu.m_title;
659 m_selected = -1; // aMenu.m_selected;
660 m_tool = aMenu.m_tool;
662
663 // Copy all menu entries
664 for( int i = 0; i < (int) aMenu.GetMenuItemCount(); ++i )
665 {
666 wxMenuItem* item = aMenu.FindItemByPosition( i );
667 appendCopy( item );
668 }
669}
670
671
672wxMenuItem* ACTION_MENU::appendCopy( const wxMenuItem* aSource )
673{
674 wxMenuItem* newItem = new wxMenuItem( this, aSource->GetId(), aSource->GetItemLabel(),
675 aSource->GetHelp(), aSource->GetKind() );
676
677 // Add the source bitmap if it is not the wxNullBitmap
678 // On Windows, for Checkable Menu items, adding a bitmap adds also
679 // our predefined checked alternate bitmap
680 // On other OS, wxITEM_CHECK and wxITEM_RADIO Menu items do not use custom bitmaps.
681
682#if defined( __WXMSW__ )
683 // On Windows, AddBitmapToMenuItem() uses the unchecked bitmap for wxITEM_CHECK and
684 // wxITEM_RADIO menuitems and automatically adds a checked bitmap.
685 // For other menuitrms, use the "checked" bitmap.
686 bool use_checked_bm = ( aSource->GetKind() == wxITEM_CHECK ||
687 aSource->GetKind() == wxITEM_RADIO ) ? false : true;
688 const wxBitmap& src_bitmap = aSource->GetBitmap( use_checked_bm );
689#else
690 const wxBitmap& src_bitmap = aSource->GetBitmap();
691#endif
692
693 if( src_bitmap.IsOk() && src_bitmap.GetHeight() > 1 ) // a null bitmap has a 0 size
694 KIUI::AddBitmapToMenuItem( newItem, src_bitmap );
695
696 if( aSource->IsSubMenu() )
697 {
698 ACTION_MENU* menu = dynamic_cast<ACTION_MENU*>( aSource->GetSubMenu() );
699 wxASSERT_MSG( menu, wxS( "Submenus are expected to be a ACTION_MENU" ) );
700
701 if( menu )
702 {
703 ACTION_MENU* menuCopy = menu->Clone();
704 newItem->SetSubMenu( menuCopy );
705 m_submenus.push_back( menuCopy );
706 }
707 }
708
709 // wxMenuItem has to be added before enabling/disabling or checking
710 Append( newItem );
711
712 if( aSource->IsCheckable() )
713 newItem->Check( aSource->IsChecked() );
714
715 newItem->Enable( aSource->IsEnabled() );
716
717 return newItem;
718}
static int g_last_menu_highlighted_id
static VECTOR2D g_menu_open_position
#define ID_CONTEXT_MENU_ID_MAX
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:106
BITMAPS
A list of all bitmap identifiers.
@ INVALID_BITMAP
static TOOL_ACTION updateMenu
Definition actions.h:266
bool IsActionUIId(int aId) const
Test if a UI ID corresponds to an action ID in our system.
void updateHotKeys()
Update hot key settings for TOOL_ACTIONs in this menu.
ACTION_MENU(bool isContextMenu, TOOL_INTERACTIVE *aTool=nullptr)
Default constructor.
TOOL_MANAGER * getToolManager() const
Return an instance of TOOL_MANAGER class.
void setupEvents()
Initialize handlers for events.
wxString m_title
Menu title.
virtual ACTION_MENU * create() const
Return an instance of this class. It has to be overridden in inheriting classes.
virtual void update()
Update menu state stub.
void AddQuitOrClose(KIFACE_BASE *aKiface, wxString aAppname="")
Add either a standard Quit or Close item to the menu.
void ClearDirty()
Clear the dirty flag on the menu and all descendants.
bool m_isForcedPosition
wxMenuItem * appendCopy(const wxMenuItem *aSource)
Append a copy of wxMenuItem.
OPT_TOOL_EVENT findToolAction(int aId)
Check if any of submenus contains a TOOL_ACTION with a specific ID.
void runEventHandlers(const wxMenuEvent &aMenuEvent, OPT_TOOL_EVENT &aToolEvent)
Traverse the submenus tree looking for a submenu capable of handling a particular menu event.
std::map< int, const TOOL_ACTION * > m_toolActions
Associates tool actions with menu item IDs. Non-owning.
bool m_isContextMenu
virtual OPT_TOOL_EVENT eventHandler(const wxMenuEvent &)
Event handler stub.
void OnMenuEvent(wxMenuEvent &aEvent)
void AddClose(const wxString &aAppname="")
Add a standard close item to the menu with the accelerator key CTRL-W.
void DisplayTitle(bool aDisplay=true)
Decide whether a title for a pop up menu should be displayed.
void AddQuit(const wxString &aAppname="")
Add a standard Quit item to the menu.
ACTION_MENU * Clone() const
Create a deep, recursive copy of this ACTION_MENU.
void Clear()
Remove all the entries from the menu (as well as its title).
void UpdateAll()
Run update handlers for the menu and its submenus.
void SetTitle(const wxString &aTitle) override
Set title for the menu.
void SetTool(TOOL_INTERACTIVE *aTool)
Set a tool that is the creator of the menu.
void OnIdle(wxIdleEvent &event)
std::list< ACTION_MENU * > m_submenus
List of submenus.
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
~ACTION_MENU() override
wxString GetTitle() const
Definition action_menu.h:63
wxMenuItem * Add(const wxString &aLabel, int aId, BITMAPS aIcon)
Add a wxWidgets-style entry to the menu.
bool m_titleDisplayed
friend class TOOL_INTERACTIVE
int m_selected
Store the id number of selected item.
BITMAPS m_icon
Optional icon.
bool HasEnabledItems() const
Return true if the menu has any enabled items.
TOOL_INTERACTIVE * m_tool
Creator of the menu.
void runOnSubmenus(std::function< void(ACTION_MENU *)> aFunction)
Run a function on the menu and all its submenus.
virtual bool PassHelpTextToHandler()
void copyFrom(const ACTION_MENU &aMenu)
Copy another menus data to this instance.
A KIFACE implementation.
Definition kiface_base.h:35
bool IsSingle() const
Is this KIFACE running under single_top?
Represent a single user action.
wxString GetTooltip(bool aIncludeHotkey=true) const
BITMAPS GetIcon() const
Return an icon associated with the action.
wxString GetMenuItem() const
int GetUIId() const
Get the unique ID for this action in the user interface system.
Generic, UI-independent tool event.
Definition tool_event.h:167
Master controller class:
bool ProcessEvent(const TOOL_EVENT &aEvent)
Propagate an event to tools that requested events of matching type(s).
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
ACTION_MANAGER * GetActionManager() const
VECTOR2D GetMousePosition() const
int GetHotKey(const TOOL_ACTION &aAction) const
Return the hot key associated with a given action or 0 if there is none.
#define _(s)
Base window classes and related definitions.
const wxChar *const kicadTraceToolStack
Flag to enable tracing of the tool handling stack.
@ ID_POPUP_MENU_START
Definition id.h:158
@ ID_POPUP_MENU_END
Definition id.h:163
KICOMMON_API void AddBitmapToMenuItem(wxMenuItem *aMenu, const wxBitmapBundle &aImage)
Add a bitmap to a menuitem.
static void OnCharHook(wxTextEntry *aTextEntry, wxKeyEvent &aEvent)
@ AS_GLOBAL
Global action (toolbar/main menu event, global shortcut)
Definition tool_action.h:45
@ TA_CHOICE_MENU_CHOICE
Context menu choice.
Definition tool_event.h:94
@ TA_CHOICE_MENU_UPDATE
Context menu update.
Definition tool_event.h:90
std::optional< TOOL_EVENT > OPT_TOOL_EVENT
Definition tool_event.h:637
@ MD_MODIFIER_MASK
Definition tool_event.h:145
@ MD_ALT
Definition tool_event.h:141
@ MD_CTRL
Definition tool_event.h:140
@ MD_SHIFT
Definition tool_event.h:139
@ TC_COMMAND
Definition tool_event.h:53
wxLogTrace helper definitions.
Functions to provide common constants and other functions to assist in making a consistent UI.
VECTOR2< double > VECTOR2D
Definition vector2d.h:682