KiCad PCB EDA Suite
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 (C) 2013-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
7  * @author Maciej Suminski <maciej.suminski@cern.ch>
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 <bitmaps.h>
28 #include <eda_base_frame.h>
29 #include <functional>
30 #include <id.h>
31 #include <kiface_base.h>
32 #include <menus_helpers.h>
33 #include <tool/action_menu.h>
34 #include <tool/actions.h>
35 #include <tool/tool_event.h>
36 #include <tool/tool_interactive.h>
37 #include <tool/tool_manager.h>
38 #include <trace_helpers.h>
39 #include <wx/log.h>
40 #include <wx/stc/stc.h>
41 #include <textentry_tricks.h>
42 #include <wx/listctrl.h>
43 
44 using namespace std::placeholders;
45 
46 
47 ACTION_MENU::ACTION_MENU( bool isContextMenu, TOOL_INTERACTIVE* aTool ) :
48  m_isForcedPosition( false ),
49  m_dirty( true ),
50  m_titleDisplayed( false ),
51  m_isContextMenu( isContextMenu ),
52  m_icon( BITMAPS::INVALID_BITMAP ),
53  m_selected( -1 ),
54  m_tool( aTool )
55 {
56  setupEvents();
57 }
58 
59 
61 {
62  // Set parent to NULL to prevent submenus from unregistering from a nonexistent object
63  for( auto menu : m_submenus )
64  menu->SetParent( nullptr );
65 
66  ACTION_MENU* parent = dynamic_cast<ACTION_MENU*>( GetParent() );
67 
68  if( parent )
69  parent->m_submenus.remove( this );
70 }
71 
72 
74 {
75  m_icon = aIcon;
76 }
77 
78 
80 {
81  Connect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( ACTION_MENU::OnMenuEvent ), nullptr,
82  this );
83  Connect( wxEVT_IDLE, wxIdleEventHandler( ACTION_MENU::OnIdle ), nullptr, this );
84 }
85 
86 
87 void ACTION_MENU::SetTitle( const wxString& aTitle )
88 {
89  // Unfortunately wxMenu::SetTitle() does not work very well, so this is an alternative version
90  m_title = aTitle;
91 
92  // Update the menu title
93  if( m_titleDisplayed )
94  DisplayTitle( true );
95 }
96 
97 
98 void ACTION_MENU::DisplayTitle( bool aDisplay )
99 {
100  if( ( !aDisplay || m_title.IsEmpty() ) && m_titleDisplayed )
101  {
102  // Destroy the menu entry keeping the title..
103  wxMenuItem* item = FindItemByPosition( 0 );
104  wxASSERT( item->GetItemLabelText() == GetTitle() );
105  Destroy( item );
106  // ..and separator
107  item = FindItemByPosition( 0 );
108  wxASSERT( item->IsSeparator() );
109  Destroy( item );
110  m_titleDisplayed = false;
111  }
112 
113  else if( aDisplay && !m_title.IsEmpty() )
114  {
115  if( m_titleDisplayed )
116  {
117  // Simply update the title
118  FindItemByPosition( 0 )->SetItemLabel( m_title );
119  }
120  else
121  {
122  // Add a separator and a menu entry to display the title
123  InsertSeparator( 0 );
124  Insert( 0, new wxMenuItem( this, wxID_NONE, m_title, wxEmptyString, wxITEM_NORMAL ) );
125 
126  if( !!m_icon )
127  AddBitmapToMenuItem( FindItemByPosition( 0 ), KiBitmap( m_icon ) );
128 
129  m_titleDisplayed = true;
130  }
131  }
132 }
133 
134 
135 wxMenuItem* ACTION_MENU::Add( const wxString& aLabel, int aId, BITMAPS aIcon )
136 {
137  wxASSERT_MSG( FindItem( aId ) == nullptr, "Duplicate menu IDs!" );
138 
139  wxMenuItem* item = new wxMenuItem( this, aId, aLabel, wxEmptyString, wxITEM_NORMAL );
140 
141  if( !!aIcon )
142  AddBitmapToMenuItem( item, KiBitmap( aIcon ) );
143 
144  return Append( item );
145 }
146 
147 
148 wxMenuItem* ACTION_MENU::Add( const wxString& aLabel, const wxString& aTooltip, int aId,
149  BITMAPS aIcon, bool aIsCheckmarkEntry )
150 {
151  wxASSERT_MSG( FindItem( aId ) == nullptr, "Duplicate menu IDs!" );
152 
153  wxMenuItem* item = new wxMenuItem( this, aId, aLabel, aTooltip,
154  aIsCheckmarkEntry ? wxITEM_CHECK : wxITEM_NORMAL );
155 
156  if( !!aIcon )
157  AddBitmapToMenuItem( item, KiBitmap( aIcon ) );
158 
159  return Append( item );
160 }
161 
162 
163 wxMenuItem* ACTION_MENU::Add( const TOOL_ACTION& aAction, bool aIsCheckmarkEntry,
164  const wxString& aOverrideLabel )
165 {
167  BITMAPS icon = aAction.GetIcon();
168 
169  // Allow the label to be overridden at point of use
170  wxString menuLabel = aOverrideLabel.IsEmpty() ? aAction.GetMenuItem() : aOverrideLabel;
171 
172  wxMenuItem* item = new wxMenuItem( this, aAction.GetUIId(), menuLabel,
173  aAction.GetDescription(),
174  aIsCheckmarkEntry ? wxITEM_CHECK : wxITEM_NORMAL );
175  if( !!icon )
176  AddBitmapToMenuItem( item, KiBitmap( icon ) );
177 
178  m_toolActions[aAction.GetUIId()] = &aAction;
179 
180  return Append( item );
181 }
182 
183 
184 wxMenuItem* ACTION_MENU::Add( ACTION_MENU* aMenu )
185 {
186  ACTION_MENU* menuCopy = aMenu->Clone();
187  m_submenus.push_back( menuCopy );
188 
189  wxASSERT_MSG( !menuCopy->m_title.IsEmpty(), "Set a title for ACTION_MENU using SetTitle()" );
190 
191  if( !!aMenu->m_icon )
192  {
193  wxMenuItem* newItem = new wxMenuItem( this, -1, menuCopy->m_title );
194  AddBitmapToMenuItem( newItem, KiBitmap( aMenu->m_icon ) );
195  newItem->SetSubMenu( menuCopy );
196  return Append( newItem );
197  }
198  else
199  {
200  return AppendSubMenu( menuCopy, menuCopy->m_title );
201  }
202 }
203 
204 
205 void ACTION_MENU::AddClose( const wxString& aAppname )
206 {
207 #ifdef __WINDOWS__
208  Add( _( "Close" ),
209  wxString::Format( _( "Close %s" ), aAppname ),
210  wxID_CLOSE,
211  BITMAPS::exit );
212 #else
213  Add( _( "Close" ) + "\tCtrl+W",
214  wxString::Format( _( "Close %s" ), aAppname ),
215  wxID_CLOSE,
216  BITMAPS::exit );
217 #endif
218 }
219 
220 
221 void ACTION_MENU::AddQuitOrClose( KIFACE_BASE* aKiface, wxString aAppname )
222 {
223  if( !aKiface || aKiface->IsSingle() ) // not when under a project mgr
224  {
225  // Don't use ACTIONS::quit; wxWidgets moves this on OSX and expects to find it via
226  // wxID_EXIT
227  Add( _( "Quit" ) + "\tCtrl+Q",
228  wxString::Format( _( "Quit %s" ), aAppname ),
229  wxID_EXIT,
230  BITMAPS::exit );
231  }
232  else
233  {
234  AddClose( aAppname );
235  }
236 }
237 
238 
240 {
241  m_titleDisplayed = false;
242 
243  for( int i = GetMenuItemCount() - 1; i >= 0; --i )
244  Destroy( FindItemByPosition( i ) );
245 
246  m_toolActions.clear();
247  m_submenus.clear();
248 
249  wxASSERT( GetMenuItemCount() == 0 );
250 }
251 
252 
254 {
255  for( wxMenuItem* item : GetMenuItems() )
256  {
257  if( item->IsEnabled() && !item->IsSeparator() )
258  return true;
259  }
260 
261  return false;
262 }
263 
264 
266 {
267  try
268  {
269  update();
270  }
271  catch( std::exception& )
272  {
273  }
274 
275  if( m_tool )
276  updateHotKeys();
277 
278  runOnSubmenus( std::bind( &ACTION_MENU::UpdateAll, _1 ) );
279 }
280 
281 
283 {
284  m_dirty = false;
285  runOnSubmenus( std::bind( &ACTION_MENU::ClearDirty, _1 ) );
286 }
287 
288 
290 {
291  m_dirty = true;
292  runOnSubmenus( std::bind( &ACTION_MENU::SetDirty, _1 ) );
293 }
294 
295 
297 {
298  m_tool = aTool;
299  runOnSubmenus( std::bind( &ACTION_MENU::SetTool, _1, aTool ) );
300 }
301 
302 
304 {
305  ACTION_MENU* clone = create();
306  clone->Clear();
307  clone->copyFrom( *this );
308  return clone;
309 }
310 
311 
313 {
314  ACTION_MENU* menu = new ACTION_MENU( false );
315 
316  wxASSERT_MSG( typeid( *this ) == typeid( *menu ),
317  wxString::Format( "You need to override create() method for class %s",
318  typeid( *this ).name() ) );
319 
320  return menu;
321 }
322 
323 
325 {
326  wxASSERT( m_tool );
327  return m_tool ? m_tool->GetManager() : nullptr;
328 }
329 
330 
332 {
333  TOOL_MANAGER* toolMgr = getToolManager();
334 
335  for( std::pair<const int, const TOOL_ACTION*>& ii : m_toolActions )
336  {
337  int id = ii.first;
338  const TOOL_ACTION& action = *ii.second;
339  int key = toolMgr->GetHotKey( action ) & ~MD_MODIFIER_MASK;
340 
341  if( key > 0 )
342  {
343  int mod = toolMgr->GetHotKey( action ) & MD_MODIFIER_MASK;
344  int flags = 0;
345  wxMenuItem* item = FindChildItem( id );
346 
347  if( item )
348  {
349  flags |= ( mod & MD_ALT ) ? wxACCEL_ALT : 0;
350  flags |= ( mod & MD_CTRL ) ? wxACCEL_CTRL : 0;
351  flags |= ( mod & MD_SHIFT ) ? wxACCEL_SHIFT : 0;
352 
353  if( !flags )
354  flags = wxACCEL_NORMAL;
355 
356  wxAcceleratorEntry accel( flags, key, id, item );
357  item->SetAccel( &accel );
358  }
359  }
360  }
361 }
362 
363 
364 // wxWidgets doesn't tell us when a menu command was generated from a hotkey or from
365 // a menu selection. It's important to us because a hotkey can be an immediate action
366 // while the menu selection can not (as it has no associated position).
367 //
368 // We get around this by storing the last highlighted menuId. If it matches the command
369 // id then we know this is a menu selection. (You might think we could use the menuOpen
370 // menuClose events, but these are actually generated for hotkeys as well.)
371 
373 
374 
375 // We need to store the position of the mouse when the menu was opened so it can be passed
376 // to the command event generated when the menu item is selected.
378 
379 
380 void ACTION_MENU::OnIdle( wxIdleEvent& event )
381 {
383  g_menu_open_position.x = 0.0;
384  g_menu_open_position.y = 0.0;
385 }
386 
387 
388 void ACTION_MENU::OnMenuEvent( wxMenuEvent& aEvent )
389 {
390  OPT_TOOL_EVENT evt;
391  wxString menuText;
392  wxEventType type = aEvent.GetEventType();
393  wxWindow* focus = wxWindow::FindFocus();
394 
395  if( type == wxEVT_MENU_OPEN )
396  {
397  if( m_dirty && m_tool )
398  getToolManager()->RunAction( ACTIONS::updateMenu, true, this );
399 
400  wxMenu* parent = dynamic_cast<wxMenu*>( GetParent() );
401 
402  // Don't update the position if this menu has a parent
403  if( !parent && m_tool )
405 
407  }
408  else if( type == wxEVT_MENU_HIGHLIGHT )
409  {
410  if( aEvent.GetId() > 0 )
411  g_last_menu_highlighted_id = aEvent.GetId();
412 
413  evt = TOOL_EVENT( TC_COMMAND, TA_CHOICE_MENU_UPDATE, aEvent.GetId() );
414  }
415  else if( type == wxEVT_COMMAND_MENU_SELECTED )
416  {
417  // Despite our attempts to catch the theft of text editor CHAR_HOOK and CHAR events
418  // in TOOL_DISPATCHER::DispatchWxEvent, wxWidgets sometimes converts those it knows
419  // about into menu commands without ever generating the appropriate CHAR_HOOK and CHAR
420  // events first.
421  if( dynamic_cast<wxTextEntry*>( focus )
422  || dynamic_cast<wxStyledTextCtrl*>( focus )
423  || dynamic_cast<wxListView*>( focus ) )
424  {
425  // Original key event has been lost, so we have to re-create it from the menu's
426  // wxAcceleratorEntry.
427  wxMenuItem* menuItem = FindItem( aEvent.GetId() );
428  wxAcceleratorEntry* acceleratorKey = menuItem ? menuItem->GetAccel() : nullptr;
429 
430  if( acceleratorKey )
431  {
432  wxKeyEvent keyEvent( wxEVT_CHAR_HOOK );
433  keyEvent.m_keyCode = acceleratorKey->GetKeyCode();
434  keyEvent.m_controlDown = ( acceleratorKey->GetFlags() & wxMOD_CONTROL ) > 0;
435  keyEvent.m_shiftDown = ( acceleratorKey->GetFlags() & wxMOD_SHIFT ) > 0;
436  keyEvent.m_altDown = ( acceleratorKey->GetFlags() & wxMOD_ALT ) > 0;
437 
438  if( auto ctrl = dynamic_cast<wxTextEntry*>( focus ) )
439  TEXTENTRY_TRICKS::OnCharHook( ctrl, keyEvent );
440  else
441  focus->HandleWindowEvent( keyEvent );
442 
443  if( keyEvent.GetSkipped() )
444  {
445  keyEvent.SetEventType( wxEVT_CHAR );
446  focus->HandleWindowEvent( keyEvent );
447  }
448 
449  // If the event was used as KEY event (not skipped) by the focused window,
450  // just finish.
451  // Otherwise this is actually a wxEVT_COMMAND_MENU_SELECTED, or the
452  // focused window is read only
453  if( !keyEvent.GetSkipped() )
454  return;
455  }
456  }
457 
458  // Store the selected position, so it can be checked by the tools
459  m_selected = aEvent.GetId();
460 
461  ACTION_MENU* parent = dynamic_cast<ACTION_MENU*>( GetParent() );
462 
463  while( parent )
464  {
465  parent->m_selected = m_selected;
466  parent = dynamic_cast<ACTION_MENU*>( parent->GetParent() );
467  }
468 
469  // Check if there is a TOOL_ACTION for the given ID
471  evt = findToolAction( m_selected );
472 
473  if( !evt )
474  {
475 #ifdef __WINDOWS__
476  if( !evt )
477  {
478  // Try to find the submenu which holds the selected item
479  wxMenu* menu = nullptr;
480  FindItem( m_selected, &menu );
481 
482  // This conditional compilation is probably not needed.
483  // It will be removed later, for the Kicad V 6.x version.
484  // But in "old" 3.0 version, the "&& menu != this" contition was added to avoid
485  // hang. This hang is no longer encountered in wxWidgets 3.0.4 version, and this
486  // condition is no longer needed. And in 3.1.2, we have to remove it, as
487  // "menu != this" never happens ("menu != this" always happens in 3.1.1 and older!).
488 #if wxCHECK_VERSION( 3, 1, 2 )
489  if( menu )
490 #else
491  if( menu && menu != this )
492 #endif
493  {
494  ACTION_MENU* cxmenu = static_cast<ACTION_MENU*>( menu );
495  evt = cxmenu->eventHandler( aEvent );
496  }
497  }
498 #else
499  if( !evt )
500  runEventHandlers( aEvent, evt );
501 #endif
502 
503  // Handling non-ACTION menu entries. Two ranges of ids are supported:
504  // between 0 and ID_CONTEXT_MENU_ID_MAX
505  // between ID_POPUP_MENU_START and ID_POPUP_MENU_END
506 
507  #define ID_CONTEXT_MENU_ID_MAX wxID_LOWEST /* = 100 should be plenty */
508 
509  if( !evt &&
510  ( ( m_selected >= 0 && m_selected < ID_CONTEXT_MENU_ID_MAX ) ||
512  {
513  ACTION_MENU* actionMenu = dynamic_cast<ACTION_MENU*>( GetParent() );
514 
515  if( actionMenu && actionMenu->PassHelpTextToHandler() )
516  menuText = GetHelpString( aEvent.GetId() );
517  else
518  menuText = GetLabelText( aEvent.GetId() );
519 
521  &menuText );
522  }
523  }
524  }
525 
526  // forward the action/update event to the TOOL_MANAGER
527  // clients that don't supply a tool will have to check GetSelected() themselves
528  if( evt && m_tool )
529  {
530  wxLogTrace( kicadTraceToolStack, "ACTION_MENU::OnMenuEvent %s", evt->Format() );
531 
532  // WARNING: if you're squeamish, look away.
533  // What follows is a series of egregious hacks necessitated by a lack of information from
534  // wxWidgets on where context-menu-commands and command-key-events originated.
535 
536  // If it's a context menu then fetch the mouse position from our context-menu-position
537  // hack.
538  if( m_isContextMenu )
539  {
540  evt->SetMousePosition( g_menu_open_position );
541  }
542  // Otherwise, if g_last_menu_highlighted_id matches then it's a menubar menu event and has
543  // no position.
544  else if( g_last_menu_highlighted_id == aEvent.GetId() )
545  {
546  evt->SetHasPosition( false );
547  }
548  // Otherwise it's a command-key-event and we need to get the mouse position from the tool
549  // manager so that immediate actions work.
550  else
551  {
552  evt->SetMousePosition( getToolManager()->GetMousePosition() );
553  }
554 
555  if( m_tool->GetManager() )
556  m_tool->GetManager()->ProcessEvent( *evt );
557  }
558  else
559  {
560  aEvent.Skip();
561  }
562 }
563 
564 
565 void ACTION_MENU::runEventHandlers( const wxMenuEvent& aMenuEvent, OPT_TOOL_EVENT& aToolEvent )
566 {
567  aToolEvent = eventHandler( aMenuEvent );
568 
569  if( !aToolEvent )
570  runOnSubmenus( std::bind( &ACTION_MENU::runEventHandlers, _1, aMenuEvent, aToolEvent ) );
571 }
572 
573 
574 void ACTION_MENU::runOnSubmenus( std::function<void(ACTION_MENU*)> aFunction )
575 {
576  try
577  {
578  std::for_each( m_submenus.begin(), m_submenus.end(), [&]( ACTION_MENU* m ) {
579  aFunction( m );
580  m->runOnSubmenus( aFunction );
581  } );
582  }
583  catch( std::exception& )
584  {
585  }
586 }
587 
588 
590 {
591  OPT_TOOL_EVENT evt;
592 
593  auto findFunc = [&]( ACTION_MENU* m ) {
594  if( evt )
595  return;
596 
597  const auto it = m->m_toolActions.find( aId );
598 
599  if( it != m->m_toolActions.end() )
600  evt = it->second->MakeEvent();
601  };
602 
603  findFunc( this );
604 
605  if( !evt )
606  runOnSubmenus( findFunc );
607 
608  return evt;
609 }
610 
611 
612 void ACTION_MENU::copyFrom( const ACTION_MENU& aMenu )
613 {
614  m_icon = aMenu.m_icon;
615  m_title = aMenu.m_title;
617  m_selected = -1; // aMenu.m_selected;
618  m_tool = aMenu.m_tool;
620 
621  // Copy all menu entries
622  for( int i = 0; i < (int) aMenu.GetMenuItemCount(); ++i )
623  {
624  wxMenuItem* item = aMenu.FindItemByPosition( i );
625  appendCopy( item );
626  }
627 }
628 
629 
630 wxMenuItem* ACTION_MENU::appendCopy( const wxMenuItem* aSource )
631 {
632  wxMenuItem* newItem = new wxMenuItem( this, aSource->GetId(), aSource->GetItemLabel(),
633  aSource->GetHelp(), aSource->GetKind() );
634 
635  // Add the source bitmap if it is not the wxNullBitmap
636  // On Windows, for Checkable Menu items, adding a bitmap adds also
637  // our predefined checked alternate bitmap
638  // On other OS, wxITEM_CHECK and wxITEM_RADIO Menu items do not use custom bitmaps.
639 #if defined( _WIN32 )
640  // On Windows, AddBitmapToMenuItem() uses the unchecked bitmap for wxITEM_CHECK and
641  // wxITEM_RADIO menuitems and autoamtically adds a checked bitmap.
642  // For other menuitrms, use the "checked" bitmap.
643  bool use_checked_bm = ( aSource->GetKind() == wxITEM_CHECK ||
644  aSource->GetKind() == wxITEM_RADIO ) ? false : true;
645  const wxBitmap& src_bitmap = aSource->GetBitmap( use_checked_bm );
646 #else
647  const wxBitmap& src_bitmap = aSource->GetBitmap();
648 #endif
649 
650  if( src_bitmap.IsOk() && src_bitmap.GetHeight() > 1 ) // a null bitmap has a 0 size
651  AddBitmapToMenuItem( newItem, src_bitmap );
652 
653  if( aSource->IsSubMenu() )
654  {
655  ACTION_MENU* menu = dynamic_cast<ACTION_MENU*>( aSource->GetSubMenu() );
656  wxASSERT_MSG( menu, "Submenus are expected to be a ACTION_MENU" );
657 
658  if( menu )
659  {
660  ACTION_MENU* menuCopy = menu->Clone();
661  newItem->SetSubMenu( menuCopy );
662  m_submenus.push_back( menuCopy );
663  }
664  }
665 
666  // wxMenuItem has to be added before enabling/disabling or checking
667  Append( newItem );
668 
669  if( aSource->IsCheckable() )
670  newItem->Check( aSource->IsChecked() );
671 
672  newItem->Enable( aSource->IsEnabled() );
673 
674  return newItem;
675 }
virtual void update()
Update menu state stub.
Definition: action_menu.h:198
bool m_titleDisplayed
Definition: action_menu.h:247
OPT_TOOL_EVENT findToolAction(int aId)
A KIFACE implementation.
Definition: kiface_base.h:37
static int g_last_menu_highlighted_id
int GetUIId() const
Definition: tool_action.h:130
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:48
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:73
VECTOR2D GetMousePosition() const
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:143
void runEventHandlers(const wxMenuEvent &aMenuEvent, OPT_TOOL_EVENT &aToolEvent)
Run a function on the menu and all its submenus.
void ClearDirty()
Clear the dirty flag on the menu and all descendants.
void UpdateAll()
Run update handlers for the menu and its submenus.
BITMAPS m_icon
Stores the id number of selected item.
Definition: action_menu.h:254
virtual ACTION_MENU * create() const
< Return an instance of this class. It has to be overridden in inheriting classes.
static int GetBaseUIId()
Definition: tool_action.h:135
void SetTool(TOOL_INTERACTIVE *aTool)
Set a tool that is the creator of the menu.
TOOL_MANAGER * GetManager() const
Return the instance of TOOL_MANAGER that takes care of the tool.
Definition: tool_base.h:143
virtual OPT_TOOL_EVENT eventHandler(const wxMenuEvent &)
Event handler stub.
Definition: action_menu.h:208
virtual bool PassHelpTextToHandler()
Definition: action_menu.h:180
Master controller class:
Definition: tool_manager.h:54
#define ID_CONTEXT_MENU_ID_MAX
void copyFrom(const ACTION_MENU &aMenu)
Copy another menus data to this instance.
void AddBitmapToMenuItem(wxMenuItem *aMenu, const wxBitmap &aImage)
Add a bitmap to a menuitem.
Definition: bitmap.cpp:243
bool m_isContextMenu
Menu title.
Definition: action_menu.h:248
bool ProcessEvent(const TOOL_EVENT &aEvent)
Propagate an event to tools that requested events of matching type(s).
wxString m_title
Optional icon.
Definition: action_menu.h:251
std::list< ACTION_MENU * > m_submenus
Definition: action_menu.h:266
Generic, UI-independent tool event.
Definition: tool_event.h:152
static VECTOR2D g_menu_open_position
Base window classes and related definitions.
int m_selected
Creator of the menu.
Definition: action_menu.h:257
#define _(s)
const BITMAPS GetIcon() const
Return an icon associated with the action.
Definition: tool_action.h:179
wxLogTrace helper definitions.
ACTION_MENU * Clone() const
Create a deep, recursive copy of this ACTION_MENU.
static TOOL_ACTION updateMenu
Definition: actions.h:167
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:105
TOOL_INTERACTIVE * m_tool
Associates tool actions with menu item IDs. Non-owning.
Definition: action_menu.h:260
wxString GetDescription(bool aIncludeHotkey=true) const
Definition: tool_action.cpp:97
wxMenuItem * appendCopy(const wxMenuItem *aSource)
Append a copy of wxMenuItem.
void runOnSubmenus(std::function< void(ACTION_MENU *)> aFunction)
Check if any of submenus contains a TOOL_ACTION with a specific ID.
std::map< int, const TOOL_ACTION * > m_toolActions
List of submenus.
Definition: action_menu.h:263
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
void OnMenuEvent(wxMenuEvent &aEvent)
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:87
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:32
Global action (toolbar/main menu event, global shortcut)
ACTION_MENU(bool isContextMenu, TOOL_INTERACTIVE *aTool=nullptr)
< Default constructor
Definition: action_menu.cpp:47
static void OnCharHook(wxTextEntry *aTextEntry, wxKeyEvent &aEvent)
TOOL_MANAGER * getToolManager() const
Represent a single user action.
Definition: tool_action.h:67
void setupEvents()
Update hot key settings for TOOL_ACTIONs in this menu.
Definition: action_menu.cpp:79
wxMenuItem * Add(const wxString &aLabel, int aId, BITMAPS aIcon)
Add a wxWidgets-style entry to the menu.
void Clear()
Remove all the entries from the menu (as well as its title).
const wxChar *const kicadTraceToolStack
Flag to enable tracing of the tool handling stack.
bool HasEnabledItems() const
Returns true if the menu has any enabled items.
void OnIdle(wxIdleEvent &event)
void AddQuitOrClose(KIFACE_BASE *aKiface, wxString aAppname="")
Add either a standard Quit or Close item to the menu.
void updateHotKeys()
Traverse the submenus tree looking for a submenu capable of handling a particular menu event.
wxString GetMenuItem() const
Definition: tool_action.cpp:89
~ACTION_MENU() override
Definition: action_menu.cpp:60
void SetDirty()
bool IsSingle() const
Is this KIFACE running under single_top?
Definition: kiface_base.h:104
OPT< TOOL_EVENT > OPT_TOOL_EVENT
Definition: tool_event.h:548
int GetHotKey(const TOOL_ACTION &aAction) const
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.
Definition: action_menu.cpp:98