KiCad PCB EDA Suite
action_toolbar.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2019 CERN
5  * Copyright (C) 2019 KiCad Developers, see CHANGELOG.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include <algorithm>
26 #include <bitmaps.h>
27 #include <eda_draw_frame.h>
28 #include <functional>
29 #include <math/util.h>
30 #include <memory>
31 #include <pgm_base.h>
33 #include <tool/action_toolbar.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 <widgets/bitmap_button.h>
39 #include <wx/popupwin.h>
40 #include <wx/renderer.h>
41 
42 
43 ACTION_GROUP::ACTION_GROUP( std::string aName, const std::vector<const TOOL_ACTION*>& aActions )
44 {
45  wxASSERT_MSG( aActions.size() > 0, "Action groups must have at least one action" );
46 
47  // The default action is just the first action in the vector
48  m_actions = aActions;
50 
51  m_name = aName;
53 }
54 
55 
57 {
58  bool valid = std::any_of( m_actions.begin(), m_actions.end(),
59  [&]( const TOOL_ACTION* aAction ) -> bool
60  {
61  // For some reason, we can't compare the actions directly
62  return aAction->GetId() == aDefault.GetId();
63  } );
64 
65  wxASSERT_MSG( valid, "Action must be present in a group to be the default" );
66 
67  m_defaultAction = &aDefault;
68 }
69 
70 
71 #define PALETTE_BORDER 4 // The border around the palette buttons on all sides
72 #define BUTTON_BORDER 1 // The border on the sides of the buttons that touch other buttons
73 
74 
75 ACTION_TOOLBAR_PALETTE::ACTION_TOOLBAR_PALETTE( wxWindow* aParent, bool aVertical ) :
76  wxPopupTransientWindow( aParent, wxBORDER_NONE ),
77  m_group( nullptr ),
78  m_isVertical( aVertical ),
79  m_panel( nullptr ),
80  m_mainSizer( nullptr ),
81  m_buttonSizer( nullptr )
82 {
83  m_panel = new wxPanel( this, wxID_ANY );
84  m_panel->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
85 
86  // This sizer holds the buttons for the actions
87  m_buttonSizer = new wxBoxSizer( aVertical ? wxVERTICAL : wxHORIZONTAL );
88 
89  // This sizer holds the other sizer, so that a consistent border is present on all sides
90  m_mainSizer = new wxBoxSizer( aVertical ? wxVERTICAL : wxHORIZONTAL );
91  m_mainSizer->Add( m_buttonSizer, wxSizerFlags().Border( wxALL, PALETTE_BORDER ) );
92 
93  m_panel->SetSizer( m_mainSizer );
94 
95  Connect( wxEVT_CHAR_HOOK, wxCharEventHandler( ACTION_TOOLBAR_PALETTE::onCharHook ),
96  NULL, this );
97 }
98 
99 
101 {
102  wxBitmap normalBmp = KiScaledBitmap( aAction.GetIcon(), this );
103  wxBitmap disabledBmp = normalBmp.ConvertToDisabled();
104 
105  int padding = ( m_buttonSize.GetWidth() - normalBmp.GetWidth() ) / 2;
106 
107  BITMAP_BUTTON* button = new BITMAP_BUTTON( m_panel, aAction.GetUIId() );
108 
109  button->SetBitmap( normalBmp );
110  button->SetDisabledBitmap( disabledBmp );
111  button->SetPadding( padding );
112  button->SetToolTip( aAction.GetDescription() );
113 
114  m_buttons[aAction.GetUIId()] = button;
115 
116  if( m_isVertical )
117  m_buttonSizer->Add( button, wxSizerFlags().Border( wxTOP | wxBOTTOM, BUTTON_BORDER ) );
118  else
119  m_buttonSizer->Add( button, wxSizerFlags().Border( wxLEFT | wxRIGHT, BUTTON_BORDER ) );
120 
121  m_buttonSizer->Layout();
122 }
123 
124 
125 void ACTION_TOOLBAR_PALETTE::EnableAction( const TOOL_ACTION& aAction, bool aEnable )
126 {
127  auto it = m_buttons.find( aAction.GetUIId() );
128 
129  if( it != m_buttons.end() )
130  it->second->Enable( aEnable );
131 }
132 
133 
134 void ACTION_TOOLBAR_PALETTE::CheckAction( const TOOL_ACTION& aAction, bool aCheck )
135 {
136  auto it = m_buttons.find( aAction.GetUIId() );
137 
138  if( it != m_buttons.end() )
139  it->second->Check( aCheck );
140 }
141 
142 
143 void ACTION_TOOLBAR_PALETTE::Popup( wxWindow* aFocus )
144 {
145  m_mainSizer->Fit( m_panel );
146  SetClientSize( m_panel->GetSize() );
147 
148  wxPopupTransientWindow::Popup( aFocus );
149 }
150 
151 
152 void ACTION_TOOLBAR_PALETTE::onCharHook( wxKeyEvent& aEvent )
153 {
154  // Allow the escape key to dismiss this popup
155  if( aEvent.GetKeyCode() == WXK_ESCAPE )
156  Dismiss();
157  else
158  aEvent.Skip();
159 }
160 
161 
162 ACTION_TOOLBAR::ACTION_TOOLBAR( EDA_BASE_FRAME* parent, wxWindowID id, const wxPoint& pos,
163  const wxSize& size, long style ) :
164  wxAuiToolBar( parent, id, pos, size, style ),
165  m_paletteTimer( nullptr ),
166  m_auiManager( nullptr ),
167  m_toolManager( parent->GetToolManager() ),
168  m_palette( nullptr )
169 {
170  m_paletteTimer = new wxTimer( this );
171 
172  Connect( wxEVT_COMMAND_TOOL_CLICKED, wxAuiToolBarEventHandler( ACTION_TOOLBAR::onToolEvent ),
173  NULL, this );
174  Connect( wxEVT_AUITOOLBAR_RIGHT_CLICK, wxAuiToolBarEventHandler( ACTION_TOOLBAR::onToolRightClick ),
175  NULL, this );
176  Connect( wxEVT_AUITOOLBAR_BEGIN_DRAG, wxAuiToolBarEventHandler( ACTION_TOOLBAR::onItemDrag ),
177  NULL, this );
178  Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( ACTION_TOOLBAR::onMouseClick ),
179  NULL, this );
180  Connect( wxEVT_LEFT_UP, wxMouseEventHandler( ACTION_TOOLBAR::onMouseClick ),
181  NULL, this );
182  Connect( m_paletteTimer->GetId(), wxEVT_TIMER, wxTimerEventHandler( ACTION_TOOLBAR::onTimerDone ),
183  NULL, this );
184 }
185 
186 
188 {
189  delete m_paletteTimer;
190 
191  // Clear all the maps keeping track of our items on the toolbar
192  m_toolMenus.clear();
193  m_actionGroups.clear();
194  m_toolCancellable.clear();
195  m_toolKinds.clear();
196  m_toolActions.clear();
197 }
198 
199 
200 void ACTION_TOOLBAR::Add( const TOOL_ACTION& aAction, bool aIsToggleEntry, bool aIsCancellable )
201 {
202  wxASSERT_MSG( !( aIsCancellable && !aIsToggleEntry ), "aIsCancellable requires aIsToggleEntry" );
203 
204  wxWindow* parent = dynamic_cast<wxWindow*>( m_toolManager->GetToolHolder() );
205  int toolId = aAction.GetUIId();
206 
207  AddTool( toolId, wxEmptyString, KiScaledBitmap( aAction.GetIcon(), parent ),
208  aAction.GetDescription(), aIsToggleEntry ? wxITEM_CHECK : wxITEM_NORMAL );
209 
210  m_toolKinds[ toolId ] = aIsToggleEntry;
211  m_toolActions[ toolId ] = &aAction;
212  m_toolCancellable[ toolId ] = aIsCancellable;
213 }
214 
215 
217 {
218  wxWindow* parent = dynamic_cast<wxWindow*>( m_toolManager->GetToolHolder() );
219  int toolId = aAction.GetUIId();
220 
221  AddTool( toolId, wxEmptyString, KiScaledBitmap( aAction.GetIcon(), parent ),
222  aAction.GetName(), wxITEM_NORMAL );
223 
224  m_toolKinds[ toolId ] = false;
225  m_toolActions[ toolId ] = &aAction;
226 }
227 
228 
229 void ACTION_TOOLBAR::AddScaledSeparator( wxWindow* aWindow )
230 {
231  int scale = Pgm().GetCommonSettings()->m_Appearance.icon_scale;
232 
233  if( scale == 0 )
234  scale = KiIconScale( aWindow );
235 
236  if( scale > 4 )
237  AddSpacer( 16 * ( scale - 4 ) / 4 );
238 
239  AddSeparator();
240 
241  if( scale > 4 )
242  AddSpacer( 16 * ( scale - 4 ) / 4 );
243 }
244 
245 
247  std::unique_ptr<ACTION_MENU> aMenu )
248 {
249  int toolId = aAction.GetUIId();
250 
251  m_toolMenus[toolId] = std::move( aMenu );
252 }
253 
254 
255 void ACTION_TOOLBAR::AddGroup( ACTION_GROUP* aGroup, bool aIsToggleEntry )
256 {
257  int groupId = aGroup->GetUIId();
258  const TOOL_ACTION* defaultAction = aGroup->GetDefaultAction();
259  wxWindow* parent = dynamic_cast<wxWindow*>( m_toolManager->GetToolHolder() );
260 
261  wxASSERT( defaultAction );
262 
263  m_toolKinds[ groupId ] = aIsToggleEntry;
264  m_toolActions[ groupId ] = defaultAction;
265  m_actionGroups[ groupId ] = aGroup;
266 
267  // Add the main toolbar item representing the group
268  AddTool( groupId, wxEmptyString, KiScaledBitmap( defaultAction->GetIcon(), parent ),
269  wxEmptyString, aIsToggleEntry ? wxITEM_CHECK : wxITEM_NORMAL );
270 
271  // Select the default action
272  doSelectAction( aGroup, *defaultAction );
273 }
274 
275 
277 {
278  bool valid = std::any_of( aGroup->m_actions.begin(), aGroup->m_actions.end(),
279  [&]( const TOOL_ACTION* action2 ) -> bool
280  {
281  // For some reason, we can't compare the actions directly
282  return aAction.GetId() == action2->GetId();
283  } );
284 
285  if( valid )
286  doSelectAction( aGroup, aAction );
287 }
288 
289 
291 {
292  int groupId = aGroup->GetUIId();
293 
294  wxAuiToolBarItem* item = FindTool( groupId );
295  wxWindow* parent = dynamic_cast<wxWindow*>( m_toolManager->GetToolHolder() );
296 
297  if( !item )
298  return;
299 
300  // Update the item information
301  item->SetShortHelp( aAction.GetDescription() );
302  item->SetBitmap( KiScaledBitmap( aAction.GetIcon(), parent ) );
303  item->SetDisabledBitmap( item->GetBitmap().ConvertToDisabled() );
304 
305  // Register a new handler with the new UI conditions
306  if( m_toolManager )
307  {
308  const ACTION_CONDITIONS* cond = m_toolManager->GetActionManager()->GetCondition( aAction );
309 
310  wxASSERT_MSG( cond, wxString::Format( "Missing UI condition for action %s",
311  aAction.GetName() ) );
312 
315  }
316 
317  // Update the currently selected action
318  m_toolActions[ groupId ] = &aAction;
319 
320  Refresh();
321 }
322 
323 
325 {
326  // Clear all the maps keeping track of our items on the toolbar
327  m_toolMenus.clear();
328  m_actionGroups.clear();
329  m_toolCancellable.clear();
330  m_toolKinds.clear();
331  m_toolActions.clear();
332 
333  // Remove the actual tools from the toolbar
334  Clear();
335 }
336 
337 
338 void ACTION_TOOLBAR::SetToolBitmap( const TOOL_ACTION& aAction, const wxBitmap& aBitmap )
339 {
340  int toolId = aAction.GetUIId();
341  wxAuiToolBar::SetToolBitmap( toolId, aBitmap );
342 
343  // Set the disabled bitmap: we use the disabled bitmap version
344  // of aBitmap.
345  wxAuiToolBarItem* tb_item = wxAuiToolBar::FindTool( toolId );
346 
347  if( tb_item )
348  tb_item->SetDisabledBitmap( aBitmap.ConvertToDisabled() );
349 }
350 
351 
352 void ACTION_TOOLBAR::Toggle( const TOOL_ACTION& aAction, bool aState )
353 {
354  int toolId = aAction.GetUIId();
355 
356  if( m_toolKinds[ toolId ] )
357  ToggleTool( toolId, aState );
358  else
359  EnableTool( toolId, aState );
360 }
361 
362 
363 void ACTION_TOOLBAR::Toggle( const TOOL_ACTION& aAction, bool aEnabled, bool aChecked )
364 {
365  int toolId = aAction.GetUIId();
366 
367  EnableTool( toolId, aEnabled );
368  ToggleTool( toolId, aEnabled && aChecked );
369 }
370 
371 
372 void ACTION_TOOLBAR::onToolEvent( wxAuiToolBarEvent& aEvent )
373 {
374  int id = aEvent.GetId();
375  wxEventType type = aEvent.GetEventType();
376  OPT_TOOL_EVENT evt;
377 
378  bool handled = false;
379 
380  if( m_toolManager && type == wxEVT_COMMAND_TOOL_CLICKED && id >= TOOL_ACTION::GetBaseUIId() )
381  {
382  const auto actionIt = m_toolActions.find( id );
383 
384  // The toolbar item is toggled before the event is sent, so we check for it not being
385  // toggled to see if it was toggled originally
386  if( m_toolCancellable[id] && !GetToolToggled( id ) )
387  {
388  // Send a cancel event
390  handled = true;
391  }
392  else if( actionIt != m_toolActions.end() )
393  {
394  // Dispatch a tool event
395  evt = actionIt->second->MakeEvent();
396  evt->SetHasPosition( false );
397  m_toolManager->ProcessEvent( *evt );
398  handled = true;
399  }
400  }
401 
402  // Skip the event if we don't handle it
403  if( !handled )
404  aEvent.Skip();
405 }
406 
407 
408 void ACTION_TOOLBAR::onToolRightClick( wxAuiToolBarEvent& aEvent )
409 {
410  int toolId = aEvent.GetToolId();
411 
412  // This means the event was not on a button
413  if( toolId == -1 )
414  return;
415 
416  // Ensure that the ID used maps to a proper tool ID.
417  // If right-clicked on a group item, this is needed to get the ID of the currently selected
418  // action, since the event's ID is that of the group.
419  const auto actionIt = m_toolActions.find( toolId );
420 
421  if( actionIt != m_toolActions.end() )
422  toolId = actionIt->second->GetUIId();
423 
424  // Find the menu for the action
425  const auto menuIt = m_toolMenus.find( toolId );
426 
427  if( menuIt == m_toolMenus.end() )
428  return;
429 
430  // Update and show the menu
431  std::unique_ptr<ACTION_MENU>& owningMenu = menuIt->second;
432 
433  // Get the actual menu pointer to show it
434  ACTION_MENU* menu = owningMenu.get();
435  SELECTION dummySel;
436 
437  if( CONDITIONAL_MENU* condMenu = dynamic_cast<CONDITIONAL_MENU*>( menu ) )
438  condMenu->Evaluate( dummySel );
439 
440  menu->UpdateAll();
441  PopupMenu( menu );
442 
443  // Remove hovered item when the menu closes, otherwise it remains hovered even if the
444  // mouse is not on the toolbar
445  SetHoverItem( nullptr );
446 }
447 
448 // The time (in milliseconds) between pressing the left mouse button and opening the palette
449 #define PALETTE_OPEN_DELAY 500
450 
451 
452 void ACTION_TOOLBAR::onMouseClick( wxMouseEvent& aEvent )
453 {
454  wxAuiToolBarItem* item = FindToolByPosition( aEvent.GetX(), aEvent.GetY() );
455 
456  if( item )
457  {
458  // Ensure there is no active palette
459  if( m_palette )
460  {
461  m_palette->Hide();
462  m_palette->Destroy();
463  m_palette = nullptr;
464  }
465 
466  // Start the popup conditions if it is a left mouse click and the tool clicked is a group
467  if( aEvent.LeftDown() && ( m_actionGroups.find( item->GetId() ) != m_actionGroups.end() ) )
468  m_paletteTimer->StartOnce( PALETTE_OPEN_DELAY );
469 
470  // Clear the popup conditions if it is a left up, because that implies a click happened
471  if( aEvent.LeftUp() )
472  m_paletteTimer->Stop();
473  }
474 
475  // Skip the event so wx can continue processing the mouse event
476  aEvent.Skip();
477 }
478 
479 
480 void ACTION_TOOLBAR::onItemDrag( wxAuiToolBarEvent& aEvent )
481 {
482  int toolId = aEvent.GetToolId();
483 
484  if( m_actionGroups.find( toolId ) != m_actionGroups.end() )
485  {
486  wxAuiToolBarItem* item = FindTool( toolId );
487 
488  // Use call after because opening the palette from a mouse handler
489  // creates a weird mouse state that causes problems on OSX.
490  CallAfter( &ACTION_TOOLBAR::popupPalette, item );
491 
492  // Don't skip this event since we are handling it
493  return;
494  }
495 
496  // Skip since we don't care about it
497  aEvent.Skip();
498 }
499 
500 
501 void ACTION_TOOLBAR::onTimerDone( wxTimerEvent& aEvent )
502 {
503  // We need to search for the tool using the client coordinates
504  wxPoint mousePos = ScreenToClient( wxGetMousePosition() );
505 
506  wxAuiToolBarItem* item = FindToolByPosition( mousePos.x, mousePos.y );
507 
508  if( item )
509  popupPalette( item );
510 }
511 
512 
513 void ACTION_TOOLBAR::onPaletteEvent( wxCommandEvent& aEvent )
514 {
515  if( !m_palette )
516  return;
517 
518  OPT_TOOL_EVENT evt;
519  ACTION_GROUP* group = m_palette->GetGroup();
520 
521  // Find the action corresponding to the button press
522  auto actionIt = std::find_if( group->GetActions().begin(), group->GetActions().end(),
523  [=]( const TOOL_ACTION* aAction )
524  {
525  return aAction->GetUIId() == aEvent.GetId();
526  } );
527 
528  if( actionIt != group->GetActions().end() )
529  {
530  const TOOL_ACTION* action = *actionIt;
531 
532  // Dispatch a tool event
533  evt = action->MakeEvent();
534  evt->SetHasPosition( false );
535  m_toolManager->ProcessEvent( *evt );
536 
537  // Update the main toolbar item with the selected action
538  doSelectAction( group, *action );
539  }
540 
541  // Hide the palette
542  m_palette->Hide();
543  m_palette->Destroy();
544  m_palette = nullptr;
545 }
546 
547 
548 void ACTION_TOOLBAR::popupPalette( wxAuiToolBarItem* aItem )
549 {
550  // Clear all popup conditions
551  m_paletteTimer->Stop();
552 
553  wxWindow* parent = dynamic_cast<wxWindow*>( m_toolManager->GetToolHolder() );
554 
555  wxASSERT( m_auiManager );
556  wxASSERT( parent );
557 
558  // Ensure the item we are using for the palette has a group associated with it.
559  const auto it = m_actionGroups.find( aItem->GetId() );
560 
561  if( it == m_actionGroups.end() )
562  return;
563 
564  ACTION_GROUP* group = it->second;
565 
566  wxAuiPaneInfo& pane = m_auiManager->GetPane( this );
567 
568  // We use the size of the toolbar items for our palette buttons
569  wxRect toolRect = GetToolRect( aItem->GetId() );
570 
571  // The position for the palette window must be in screen coordinates
572  wxPoint pos( ClientToScreen( toolRect.GetPosition() ) );
573 
574  // True for vertical buttons, false for horizontal
575  bool dir = true;
576  size_t numActions = group->m_actions.size();
577 
578  // The size of the palette in the long dimension
579  int paletteLongDim = ( 2 * PALETTE_BORDER ) // The border on all sides of the buttons
580  + ( BUTTON_BORDER ) // The border on the start of the buttons
581  + ( numActions * BUTTON_BORDER ) // The other button borders
582  + ( numActions * toolRect.GetHeight() ); // The size of the buttons
583 
584  // Determine the position of the top left corner of the palette window
585  switch( pane.dock_direction )
586  {
587  case wxAUI_DOCK_TOP:
588  // Top toolbars need to shift the palette window down by the toolbar padding
589  dir = true; // Buttons are vertical in the palette
590  pos = ClientToScreen( toolRect.GetBottomLeft() );
591  pos += wxPoint( -PALETTE_BORDER, // Shift left to align the button edges
592  m_bottomPadding ); // Shift down to move away from the toolbar
593  break;
594 
595  case wxAUI_DOCK_BOTTOM:
596  // Bottom toolbars need to shift the palette window up by its height (all buttons + border + toolbar padding)
597  dir = true; // Buttons are vertical in the palette
598  pos = ClientToScreen( toolRect.GetTopLeft() );
599  pos += wxPoint( -PALETTE_BORDER, // Shift left to align the button
600  -( paletteLongDim + m_topPadding ) ); // Shift up by the entire length of the palette
601  break;
602 
603  case wxAUI_DOCK_LEFT:
604  // Left toolbars need to shift the palette window up by the toolbar padding
605  dir = false; // Buttons are horizontal in the palette
606  pos = ClientToScreen( toolRect.GetTopRight() );
607  pos += wxPoint( m_rightPadding, // Shift right to move away from the toolbar
608  -( PALETTE_BORDER + BUTTON_BORDER ) ); // Shift up to align the button tops
609  break;
610 
611  case wxAUI_DOCK_RIGHT:
612  // Right toolbars need to shift the palette window left by its width (all buttons + border + toolbar padding)
613  dir = false; // Buttons are horizontal in the palette
614  pos = ClientToScreen( toolRect.GetTopLeft() );
615  pos += wxPoint( -( paletteLongDim + m_leftPadding ), // Shift left by the entire length of the palette
616  -( PALETTE_BORDER + BUTTON_BORDER ) ); // Shift up to align the button
617  break;
618  }
619 
620  m_palette = new ACTION_TOOLBAR_PALETTE( parent, dir );
621 
622  // We handle the button events in the toolbar class, so connect the right handler
623  m_palette->SetGroup( group );
624  m_palette->SetButtonSize( toolRect );
625  m_palette->Connect( wxEVT_BUTTON, wxCommandEventHandler( ACTION_TOOLBAR::onPaletteEvent ),
626  NULL, this );
627 
628 
629  // Add the actions in the group to the palette and update their state
630  for( const TOOL_ACTION* action : group->m_actions )
631  {
632  wxUpdateUIEvent evt( action->GetUIId() );
633 
634  parent->ProcessWindowEvent( evt );
635 
636  m_palette->AddAction( *action );
637 
638  if( evt.GetSetChecked() )
639  m_palette->CheckAction( *action, evt.GetChecked() );
640 
641  if( evt.GetSetEnabled() )
642  m_palette->EnableAction( *action, evt.GetEnabled() );
643  }
644 
645  // Release the mouse to ensure the first click will be recognized in the palette
646  ReleaseMouse();
647 
648  m_palette->SetPosition( pos );
649  m_palette->Popup();
650 
651  // Clear the mouse state on the toolbar because otherwise wxWidgets gets confused
652  // and won't properly display any highlighted items after the palette is closed.
653  // (This is the equivalent of calling the DoResetMouseState() private function)
654  RefreshOverflowState();
655  SetHoverItem( nullptr );
656  SetPressedItem( nullptr );
657 
658  m_dragging = false;
659  m_tipItem = nullptr;
660  m_actionPos = wxPoint( -1, -1 );
661  m_actionItem = nullptr;
662 }
663 
664 
665 void ACTION_TOOLBAR::OnCustomRender(wxDC& aDc, const wxAuiToolBarItem& aItem,
666  const wxRect& aRect )
667 {
668  auto it = m_actionGroups.find( aItem.GetId() );
669 
670  if( it == m_actionGroups.end() )
671  return;
672 
673  // Choose the color to draw the triangle
674  wxColour clr;
675 
676  if( aItem.GetState() & wxAUI_BUTTON_STATE_DISABLED )
677  clr = wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT );
678  else
679  clr = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNTEXT );
680 
681  // Must set both the pen (for the outline) and the brush (for the polygon fill)
682  aDc.SetPen( wxPen( clr ) );
683  aDc.SetBrush( wxBrush( clr ) );
684 
685  // Make the side length of the triangle approximately 1/5th of the bitmap
686  int sideLength = KiROUND( aRect.height / 5.0 );
687 
688  // This will create a triangle with its point at the bottom right corner,
689  // and its other two corners along the right and bottom sides
690  wxPoint btmRight = aRect.GetBottomRight();
691  wxPoint topCorner( btmRight.x, btmRight.y - sideLength );
692  wxPoint btmCorner( btmRight.x - sideLength, btmRight.y );
693 
694  wxPointList points;
695  points.Append( &btmRight );
696  points.Append( &topCorner );
697  points.Append( &btmCorner );
698 
699  aDc.DrawPolygon( &points );
700 }
const TOOL_ACTION * m_defaultAction
The default action to display on the toolbar item
A bitmap button widget that behaves like an AUI toolbar item's button when it is drawn.
Definition: bitmap_button.h:39
void onItemDrag(wxAuiToolBarEvent &aEvent)
Handler for when a drag event occurs on an item
void CheckAction(const TOOL_ACTION &aAction, bool aCheck=true)
Check/Toggle the button for an action on the palette.
static int MakeActionId(const std::string &aActionName)
Generates an unique ID from for an action with given name.
int GetUIId() const
Definition: tool_action.h:102
ACTION_GROUP * GetGroup()
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:43
void SetButtonSize(wxRect &aSize)
Set the size all the buttons on this palette should be.
void AddToolContextMenu(const TOOL_ACTION &aAction, std::unique_ptr< ACTION_MENU > aMenu)
Add a context menu to a specific tool item on the toolbar.
void AddScaledSeparator(wxWindow *aWindow)
Add a separator that introduces space on either side to not squash the tools when scaled.
void popupPalette(wxAuiToolBarItem *aItem)
Popup the ACTION_TOOLBAR_PALETTE associated with the ACTION_GROUP of the given toolbar item.
void Add(const TOOL_ACTION &aAction, bool aIsToggleEntry=false, bool aIsCancellable=false)
Adds a TOOL_ACTION-based button to the toolbar.
int KiIconScale(wxWindow *aWindow)
Return the automatic scale factor that would be used for a given window by KiScaledBitmap and KiScale...
Definition: bitmap.cpp:92
#define PALETTE_OPEN_DELAY
void onToolRightClick(wxAuiToolBarEvent &aEvent)
Handle a right-click on a menu item
virtual void UnregisterUIUpdateHandler(const TOOL_ACTION &aAction)
Unregister a UI handler for an action that was registered using RegisterUIUpdateHandler.
Definition: tools_holder.h:105
void onTimerDone(wxTimerEvent &aEvent)
Handle the palette timer triggering
void AddGroup(ACTION_GROUP *aGroup, bool aIsToggleEntry=false)
Add a set of actions to a toolbar as a group.
void UpdateAll()
Runs update handlers for the menu and its submenus.
ACTION_TOOLBAR_PALETTE(wxWindow *aParent, bool aVertical)
Create the palette.
void onToolEvent(wxAuiToolBarEvent &aEvent)
The default tool event handler
std::map< int, const TOOL_ACTION * > m_toolActions
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:102
wxBitmap KiScaledBitmap(BITMAP_DEF aBitmap, wxWindow *aWindow)
Construct a wxBitmap from a memory record, scaling it if device DPI demands it.
Definition: bitmap.cpp:118
static int GetBaseUIId()
Definition: tool_action.h:107
const BITMAP_OPAQUE * GetIcon() const
Returns an icon associated with the action.
Definition: tool_action.h:155
void SetDefaultAction(const TOOL_ACTION &aDefault)
Set the default action to use when first creating the toolbar palette icon.
void onMouseClick(wxMouseEvent &aEvent)
Handler for a mouse up/down event
A group of actions that will be displayed together on a toolbar palette.
void AddAction(const TOOL_ACTION &aAction)
Add an action to the palette.
void AddButton(const TOOL_ACTION &aAction)
Adds a large button such as used in the Kicad Manager Frame's launch bar.
#define NULL
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
bool m_isVertical
True if the palette uses vertical buttons, false for horizontal buttons
void doSelectAction(ACTION_GROUP *aGroup, const TOOL_ACTION &aAction)
Update a group toolbar item to look like a specific action.
bool ProcessEvent(const TOOL_EVENT &aEvent)
Propagates an event to tools that requested events of matching type(s).
std::map< int, bool > m_toolCancellable
void SetGroup(ACTION_GROUP *aGroup)
Set the action group that this palette contains the actions for.
void SetPadding(int aPadding)
Set the amount of padding present on each side of the bitmap.
void OnCustomRender(wxDC &aDc, const wxAuiToolBarItem &aItem, const wxRect &aRect) override
Render the triangle in the lower-right corner that represents that an action pallette is available fo...
ACTION_TOOLBAR_PALETTE * m_palette
wxString GetDescription(bool aIncludeHotkey=true) const
Definition: tool_action.cpp:83
std::vector< const TOOL_ACTION * > m_actions
The actions that compose the group
ACTION_TOOLBAR(EDA_BASE_FRAME *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxAUI_TB_DEFAULT_STYLE)
std::map< int, std::unique_ptr< ACTION_MENU > > m_toolMenus
wxRect m_buttonSize
The size each button on the toolbar should be
TOOLS_HOLDER * GetToolHolder() const
Definition: tool_manager.h:301
wxAuiManager * m_auiManager
const TOOL_ACTION * GetDefaultAction() const
Get the default action to use when first creating this group's toolbar palette icon.
TOOL_MANAGER * m_toolManager
int GetId() const
Returns the unique id of the TOOL_ACTION object.
Definition: tool_action.h:94
const int scale
see class PGM_BASE
std::map< int, ACTION_GROUP * > m_actionGroups
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:201
ACTION_MANAGER * GetActionManager()
Definition: tool_manager.h:200
void SetBitmap(const wxBitmap &aBmp)
Set the bitmap shown when the button is enabled.
Functors that can be used to figure out how the action controls should be displayed in the UI and if ...
std::map< int, BITMAP_BUTTON * > m_buttons
The buttons that act as the toolbar on the palette
The base frame for deriving all KiCad main window classes.
Represents a single user action.
Definition: tool_action.h:44
#define PALETTE_BORDER
void SetToolBitmap(const TOOL_ACTION &aAction, const wxBitmap &aBitmap)
Updates the bitmap of a particular tool.
TOOL_EVENT MakeEvent() const
Returns the event associated with the action (i.e.
Definition: tool_action.h:113
void Toggle(const TOOL_ACTION &aAction, bool aState)
Applies the default toggle action.
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:68
int GetUIId() const
Get the ID used in the UI to reference this group.
wxBoxSizer * m_buttonSizer
virtual ~ACTION_TOOLBAR()
void SelectAction(ACTION_GROUP *aGroup, const TOOL_ACTION &aAction)
Select an action inside a group.
const ACTION_CONDITIONS * GetCondition(const TOOL_ACTION &aAction) const
Get the conditions to use for a specific tool action.
void SetDisabledBitmap(const wxBitmap &aBmp)
Set the bitmap shown when the button is disabled.
int m_id
The action ID for this action group
void Popup(wxWindow *aFocus=nullptr) override
Popup this window.
#define BUTTON_BORDER
virtual void RegisterUIUpdateHandler(const TOOL_ACTION &aAction, const ACTION_CONDITIONS &aConditions)
Register an action's update conditions with the UI layer to allow the UI to appropriately display the...
Definition: tools_holder.h:85
void EnableAction(const TOOL_ACTION &aAction, bool aEnable=true)
Enable the button for an action on the palette.
void onCharHook(wxKeyEvent &aEvent)
std::map< int, bool > m_toolKinds
wxTimer * m_paletteTimer
const std::vector< const TOOL_ACTION * > & GetActions() const
Get a vector of all the actions contained inside this group.
ACTION_GROUP(std::string aName, const std::vector< const TOOL_ACTION * > &aActions)
A popup window that contains a row of toolbar-like buttons for the user to choose from.
void SetHasPosition(bool aHasPosition)
Definition: tool_event.h:261
void CancelTool()
Send a cancel event to the tool currently at the top of the tool stack.
void onPaletteEvent(wxCommandEvent &aEvent)
Handle the button select inside the palette
OPT< TOOL_EVENT > OPT_TOOL_EVENT
Definition: tool_event.h:556
std::string m_name
The name of this action group
const std::string & GetName() const
Returns name of the action.
Definition: tool_action.h:75
void ClearToolbar()
Clear the toolbar and remove all associated menus.