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