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 // A native text box types from the platform key event, which the menu
493 // took, so the character has to be put in by hand. A shifted key other
494 // than a letter is left alone, since its character depends on the layout.
495 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( focus );
496 bool isLetter = keyCode >= 'A' && keyCode <= 'Z';
497
498 if( textEntry && textEntry->IsEditable() && keyEvent.GetSkipped() && !keyEvent.ControlDown()
499 && !keyEvent.AltDown() && keyCode >= WXK_SPACE && keyCode < WXK_START
500 && ( isLetter || !keyEvent.ShiftDown() ) )
501 {
502 textEntry->WriteText( wxString( wxUniChar( keyEvent.m_keyCode ) ) );
503 return;
504 }
505 }
506
507 // Don't bubble-up dangerous actions; the target may be behind a modeless dialog.
508 // Cf. https://gitlab.com/kicad/code/kicad/-/issues/17229
509 if( keyEvent.GetKeyCode() == WXK_BACK || keyEvent.GetKeyCode() == WXK_DELETE )
510 return;
511
512 // If the event was used as a KEY event (not skipped) by the focused window,
513 // just finish. Otherwise this is actually a wxEVT_COMMAND_MENU_SELECTED (or the
514 // focused window is read only).
515 if( !keyEvent.GetSkipped() )
516 return;
517 }
518 }
519
520 // Store the selected position, so it can be checked by the tools
521 m_selected = aEvent.GetId();
522
523 ACTION_MENU* parent = dynamic_cast<ACTION_MENU*>( GetParent() );
524
525 while( parent )
526 {
527 parent->m_selected = m_selected;
528 parent = dynamic_cast<ACTION_MENU*>( parent->GetParent() );
529 }
530
531 // Check if there is a TOOL_ACTION for the given UI ID
532 if( toolMgr && toolMgr->GetActionManager()->IsActionUIId( m_selected ) )
533 evt = findToolAction( m_selected );
534
535 if( !evt )
536 {
537#ifdef __WINDOWS__
538 if( !evt )
539 {
540 // Try to find the submenu which holds the selected item
541 wxMenu* menu = nullptr;
542 FindItem( m_selected, &menu );
543
544 // This conditional compilation is probably not needed.
545 if( menu )
546 {
547 ACTION_MENU* cxmenu = static_cast<ACTION_MENU*>( menu );
548 evt = cxmenu->eventHandler( aEvent );
549 }
550 }
551#else
552 if( !evt )
553 runEventHandlers( aEvent, evt );
554#endif
555
556 // Handling non-ACTION menu entries. Two ranges of ids are supported:
557 // between 0 and ID_CONTEXT_MENU_ID_MAX
558 // between ID_POPUP_MENU_START and ID_POPUP_MENU_END
559
560 #define ID_CONTEXT_MENU_ID_MAX wxID_LOWEST /* = 100 should be plenty */
561
562 if( !evt && ( ( m_selected >= 0 && m_selected < ID_CONTEXT_MENU_ID_MAX )
564 {
565 ACTION_MENU* actionMenu = dynamic_cast<ACTION_MENU*>( GetParent() );
566
567 if( PassHelpTextToHandler() || ( actionMenu && actionMenu->PassHelpTextToHandler() ) )
568 menuText = GetHelpString( aEvent.GetId() );
569 else
570 menuText = GetLabelText( aEvent.GetId() );
571
573 evt->SetParameter( &menuText );
574 }
575 }
576 }
577
578 // forward the action/update event to the TOOL_MANAGER
579 // clients that don't supply a tool will have to check GetSelected() themselves
580 if( evt && toolMgr )
581 {
582 wxLogTrace( kicadTraceToolStack, wxS( "ACTION_MENU::OnMenuEvent %s" ), evt->Format() );
583
584 // WARNING: if you're squeamish, look away.
585 // What follows is a series of egregious hacks necessitated by a lack of information from
586 // wxWidgets on where context-menu-commands and command-key-events originated.
587
588 // If it's a context menu then fetch the mouse position from our context-menu-position
589 // hack.
590 if( m_isContextMenu )
591 {
592 evt->SetMousePosition( g_menu_open_position );
593 }
594 // Check if it is a menubar event, and don't get any position if it is. Note that we
595 // can't use IsAttached() here, as it only differentiates a context menu, and we also
596 // want a hotkey to generate a position.
597 else if( g_last_menu_highlighted_id == aEvent.GetId() )
598 {
599 evt->SetHasPosition( false );
600 }
601 // Otherwise it's a command-key-event and we need to get the mouse position from the tool
602 // manager so that immediate actions work.
603 else
604 {
605 evt->SetMousePosition( toolMgr->GetMousePosition() );
606 }
607
608 toolMgr->ProcessEvent( *evt );
609 }
610 else
611 {
612 aEvent.Skip();
613 }
614}
615
616
617void ACTION_MENU::runEventHandlers( const wxMenuEvent& aMenuEvent, OPT_TOOL_EVENT& aToolEvent )
618{
619 aToolEvent = eventHandler( aMenuEvent );
620
621 if( !aToolEvent )
622 runOnSubmenus( std::bind( &ACTION_MENU::runEventHandlers, _1, aMenuEvent, aToolEvent ) );
623}
624
625
626void ACTION_MENU::runOnSubmenus( std::function<void(ACTION_MENU*)> aFunction )
627{
628 try
629 {
630 std::for_each( m_submenus.begin(), m_submenus.end(),
631 [&]( ACTION_MENU* m )
632 {
633 aFunction( m );
634 m->runOnSubmenus( aFunction );
635 } );
636 }
637 catch( std::exception& )
638 {
639 }
640}
641
642
644{
645 OPT_TOOL_EVENT evt;
646
647 auto findFunc =
648 [&]( ACTION_MENU* m )
649 {
650 if( evt )
651 return;
652
653 const auto it = m->m_toolActions.find( aId );
654
655 if( it != m->m_toolActions.end() )
656 evt = it->second->MakeEvent();
657 };
658
659 findFunc( this );
660
661 if( !evt )
662 runOnSubmenus( findFunc );
663
664 return evt;
665}
666
667
669{
670 m_icon = aMenu.m_icon;
671 m_title = aMenu.m_title;
673 m_selected = -1; // aMenu.m_selected;
674 m_tool = aMenu.m_tool;
676
677 // Copy all menu entries
678 for( int i = 0; i < (int) aMenu.GetMenuItemCount(); ++i )
679 {
680 wxMenuItem* item = aMenu.FindItemByPosition( i );
681 appendCopy( item );
682 }
683}
684
685
686wxMenuItem* ACTION_MENU::appendCopy( const wxMenuItem* aSource )
687{
688 wxMenuItem* newItem = new wxMenuItem( this, aSource->GetId(), aSource->GetItemLabel(),
689 aSource->GetHelp(), aSource->GetKind() );
690
691 // Add the source bitmap if it is not the wxNullBitmap
692 // On Windows, for Checkable Menu items, adding a bitmap adds also
693 // our predefined checked alternate bitmap
694 // On other OS, wxITEM_CHECK and wxITEM_RADIO Menu items do not use custom bitmaps.
695
696#if defined( __WXMSW__ )
697 // On Windows, AddBitmapToMenuItem() uses the unchecked bitmap for wxITEM_CHECK and
698 // wxITEM_RADIO menuitems and automatically adds a checked bitmap.
699 // For other menuitrms, use the "checked" bitmap.
700 bool use_checked_bm = ( aSource->GetKind() == wxITEM_CHECK ||
701 aSource->GetKind() == wxITEM_RADIO ) ? false : true;
702 const wxBitmap& src_bitmap = aSource->GetBitmap( use_checked_bm );
703#else
704 const wxBitmap& src_bitmap = aSource->GetBitmap();
705#endif
706
707 if( src_bitmap.IsOk() && src_bitmap.GetHeight() > 1 ) // a null bitmap has a 0 size
708 KIUI::AddBitmapToMenuItem( newItem, src_bitmap );
709
710 if( aSource->IsSubMenu() )
711 {
712 ACTION_MENU* menu = dynamic_cast<ACTION_MENU*>( aSource->GetSubMenu() );
713 wxASSERT_MSG( menu, wxS( "Submenus are expected to be a ACTION_MENU" ) );
714
715 if( menu )
716 {
717 ACTION_MENU* menuCopy = menu->Clone();
718 newItem->SetSubMenu( menuCopy );
719 m_submenus.push_back( menuCopy );
720 }
721 }
722
723 // wxMenuItem has to be added before enabling/disabling or checking
724 Append( newItem );
725
726 if( aSource->IsCheckable() )
727 newItem->Check( aSource->IsChecked() );
728
729 newItem->Enable( aSource->IsEnabled() );
730
731 return newItem;
732}
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:267
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: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: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:652
@ 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:707