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>
40 #include <wx/popupwin.h>
41 #include <wx/renderer.h>
42 
43 
44 ACTION_GROUP::ACTION_GROUP( std::string aName, const std::vector<const TOOL_ACTION*>& aActions )
45 {
46  wxASSERT_MSG( aActions.size() > 0, "Action groups must have at least one action" );
47 
48  // The default action is just the first action in the vector
49  m_actions = aActions;
51 
52  m_name = aName;
54 }
55 
56 
58 {
59  bool valid = std::any_of( m_actions.begin(), m_actions.end(),
60  [&]( const TOOL_ACTION* aAction ) -> bool
61  {
62  // For some reason, we can't compare the actions directly
63  return aAction->GetId() == aDefault.GetId();
64  } );
65 
66  wxASSERT_MSG( valid, "Action must be present in a group to be the default" );
67 
68  m_defaultAction = &aDefault;
69 }
70 
71 
72 #define PALETTE_BORDER 4 // The border around the palette buttons on all sides
73 #define BUTTON_BORDER 1 // The border on the sides of the buttons that touch other buttons
74 
75 
76 ACTION_TOOLBAR_PALETTE::ACTION_TOOLBAR_PALETTE( wxWindow* aParent, bool aVertical ) :
77  wxPopupTransientWindow( aParent, wxBORDER_NONE ),
78  m_group( nullptr ),
79  m_isVertical( aVertical ),
80  m_panel( nullptr ),
81  m_mainSizer( nullptr ),
82  m_buttonSizer( nullptr )
83 {
84  m_panel = new wxPanel( this, wxID_ANY );
85  m_panel->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
86 
87  // This sizer holds the buttons for the actions
88  m_buttonSizer = new wxBoxSizer( aVertical ? wxVERTICAL : wxHORIZONTAL );
89 
90  // This sizer holds the other sizer, so that a consistent border is present on all sides
91  m_mainSizer = new wxBoxSizer( aVertical ? wxVERTICAL : wxHORIZONTAL );
92  m_mainSizer->Add( m_buttonSizer, wxSizerFlags().Border( wxALL, PALETTE_BORDER ) );
93 
94  m_panel->SetSizer( m_mainSizer );
95 
96  Connect( wxEVT_CHAR_HOOK, wxCharEventHandler( ACTION_TOOLBAR_PALETTE::onCharHook ),
97  NULL, this );
98 }
99 
100 
102 {
103  wxBitmap normalBmp = KiScaledBitmap( aAction.GetIcon(), this );
104  wxBitmap disabledBmp = normalBmp.ConvertToDisabled();
105 
106  int padding = ( m_buttonSize.GetWidth() - normalBmp.GetWidth() ) / 2;
107 
108  BITMAP_BUTTON* button = new BITMAP_BUTTON( m_panel, aAction.GetUIId() );
109 
110  button->SetBitmap( normalBmp );
111  button->SetDisabledBitmap( disabledBmp );
112  button->SetPadding( padding );
113  button->SetToolTip( aAction.GetDescription() );
114 
115  m_buttons[aAction.GetUIId()] = button;
116 
117  if( m_isVertical )
118  m_buttonSizer->Add( button, wxSizerFlags().Border( wxTOP | wxBOTTOM, BUTTON_BORDER ) );
119  else
120  m_buttonSizer->Add( button, wxSizerFlags().Border( wxLEFT | wxRIGHT, BUTTON_BORDER ) );
121 
122  m_buttonSizer->Layout();
123 }
124 
125 
126 void ACTION_TOOLBAR_PALETTE::EnableAction( const TOOL_ACTION& aAction, bool aEnable )
127 {
128  auto it = m_buttons.find( aAction.GetUIId() );
129 
130  if( it != m_buttons.end() )
131  it->second->Enable( aEnable );
132 }
133 
134 
135 void ACTION_TOOLBAR_PALETTE::CheckAction( const TOOL_ACTION& aAction, bool aCheck )
136 {
137  auto it = m_buttons.find( aAction.GetUIId() );
138 
139  if( it != m_buttons.end() )
140  it->second->Check( aCheck );
141 }
142 
143 
144 void ACTION_TOOLBAR_PALETTE::Popup( wxWindow* aFocus )
145 {
146  m_mainSizer->Fit( m_panel );
147  SetClientSize( m_panel->GetSize() );
148 
149  wxPopupTransientWindow::Popup( aFocus );
150 }
151 
152 
153 void ACTION_TOOLBAR_PALETTE::onCharHook( wxKeyEvent& aEvent )
154 {
155  // Allow the escape key to dismiss this popup
156  if( aEvent.GetKeyCode() == WXK_ESCAPE )
157  Dismiss();
158  else
159  aEvent.Skip();
160 }
161 
162 
163 ACTION_TOOLBAR::ACTION_TOOLBAR( EDA_BASE_FRAME* parent, wxWindowID id, const wxPoint& pos,
164  const wxSize& size, long style ) :
165  wxAuiToolBar( parent, id, pos, size, style ),
166  m_paletteTimer( nullptr ),
167  m_auiManager( nullptr ),
168  m_toolManager( parent->GetToolManager() ),
169  m_palette( nullptr )
170 {
171  m_paletteTimer = new wxTimer( this );
172 
173  // Enable this once dark icon switching is available. Without dark theme icons, this just
174  // makes things (even) harder to see
175 #ifdef NOTYET
176 #if !wxCHECK_VERSION( 3, 1, 0 )
177  // Custom art provider makes dark mode work on wx < 3.1
178  WX_AUI_TOOLBAR_ART* newArt = new WX_AUI_TOOLBAR_ART();
179  SetArtProvider( newArt );
180 #endif
181 #endif
182 
183  Connect( wxEVT_COMMAND_TOOL_CLICKED, wxAuiToolBarEventHandler( ACTION_TOOLBAR::onToolEvent ),
184  NULL, this );
185  Connect( wxEVT_AUITOOLBAR_RIGHT_CLICK, wxAuiToolBarEventHandler( ACTION_TOOLBAR::onToolRightClick ),
186  NULL, this );
187  Connect( wxEVT_AUITOOLBAR_BEGIN_DRAG, wxAuiToolBarEventHandler( ACTION_TOOLBAR::onItemDrag ),
188  NULL, this );
189  Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( ACTION_TOOLBAR::onMouseClick ),
190  NULL, this );
191  Connect( wxEVT_LEFT_UP, wxMouseEventHandler( ACTION_TOOLBAR::onMouseClick ),
192  NULL, this );
193  Connect( m_paletteTimer->GetId(), wxEVT_TIMER, wxTimerEventHandler( ACTION_TOOLBAR::onTimerDone ),
194  NULL, this );
195 }
196 
197 
199 {
200  delete m_paletteTimer;
201 
202  // Clear all the maps keeping track of our items on the toolbar
203  m_toolMenus.clear();
204  m_actionGroups.clear();
205  m_toolCancellable.clear();
206  m_toolKinds.clear();
207  m_toolActions.clear();
208 }
209 
210 
211 void ACTION_TOOLBAR::Add( const TOOL_ACTION& aAction, bool aIsToggleEntry, bool aIsCancellable )
212 {
213  wxASSERT( GetParent() );
214  wxASSERT_MSG( !( aIsCancellable && !aIsToggleEntry ), "aIsCancellable requires aIsToggleEntry" );
215 
216  int toolId = aAction.GetUIId();
217 
218  AddTool( toolId, wxEmptyString, KiScaledBitmap( aAction.GetIcon(), GetParent() ),
219  aAction.GetDescription(), aIsToggleEntry ? wxITEM_CHECK : wxITEM_NORMAL );
220 
221  m_toolKinds[ toolId ] = aIsToggleEntry;
222  m_toolActions[ toolId ] = &aAction;
223  m_toolCancellable[ toolId ] = aIsCancellable;
224 }
225 
226 
228 {
229  int toolId = aAction.GetUIId();
230 
231  AddTool( toolId, wxEmptyString, KiScaledBitmap( aAction.GetIcon(), GetParent() ),
232  aAction.GetName(), wxITEM_NORMAL );
233 
234  m_toolKinds[ toolId ] = false;
235  m_toolActions[ toolId ] = &aAction;
236 }
237 
238 
239 void ACTION_TOOLBAR::AddScaledSeparator( wxWindow* aWindow )
240 {
241  int scale = Pgm().GetCommonSettings()->m_Appearance.icon_scale;
242 
243  if( scale == 0 )
244  scale = KiIconScale( aWindow );
245 
246  if( scale > 4 )
247  AddSpacer( 16 * ( scale - 4 ) / 4 );
248 
249  AddSeparator();
250 
251  if( scale > 4 )
252  AddSpacer( 16 * ( scale - 4 ) / 4 );
253 }
254 
255 
257  std::unique_ptr<ACTION_MENU> aMenu )
258 {
259  int toolId = aAction.GetUIId();
260 
261  m_toolMenus[toolId] = std::move( aMenu );
262 }
263 
264 
265 void ACTION_TOOLBAR::AddGroup( ACTION_GROUP* aGroup, bool aIsToggleEntry )
266 {
267  int groupId = aGroup->GetUIId();
268  const TOOL_ACTION* defaultAction = aGroup->GetDefaultAction();
269 
270  wxASSERT( GetParent() );
271  wxASSERT( defaultAction );
272 
273  m_toolKinds[ groupId ] = aIsToggleEntry;
274  m_toolActions[ groupId ] = defaultAction;
275  m_actionGroups[ groupId ] = aGroup;
276 
277  // Add the main toolbar item representing the group
278  AddTool( groupId, wxEmptyString, KiScaledBitmap( defaultAction->GetIcon(), GetParent() ),
279  wxEmptyString, aIsToggleEntry ? wxITEM_CHECK : wxITEM_NORMAL );
280 
281  // Select the default action
282  doSelectAction( aGroup, *defaultAction );
283 }
284 
285 
287 {
288  bool valid = std::any_of( aGroup->m_actions.begin(), aGroup->m_actions.end(),
289  [&]( const TOOL_ACTION* action2 ) -> bool
290  {
291  // For some reason, we can't compare the actions directly
292  return aAction.GetId() == action2->GetId();
293  } );
294 
295  if( valid )
296  doSelectAction( aGroup, aAction );
297 }
298 
299 
301 {
302  wxASSERT( GetParent() );
303 
304  int groupId = aGroup->GetUIId();
305 
306  wxAuiToolBarItem* item = FindTool( groupId );
307 
308  if( !item )
309  return;
310 
311  // Update the item information
312  item->SetShortHelp( aAction.GetDescription() );
313  item->SetBitmap( KiScaledBitmap( aAction.GetIcon(), GetParent() ) );
314  item->SetDisabledBitmap( item->GetBitmap().ConvertToDisabled() );
315 
316  // Register a new handler with the new UI conditions
317  if( m_toolManager )
318  {
319  const ACTION_CONDITIONS* cond = m_toolManager->GetActionManager()->GetCondition( aAction );
320 
321  wxASSERT_MSG( cond, wxString::Format( "Missing UI condition for action %s",
322  aAction.GetName() ) );
323 
326  }
327 
328  // Update the currently selected action
329  m_toolActions[ groupId ] = &aAction;
330 
331  Refresh();
332 }
333 
334 
336 {
337  // Clear all the maps keeping track of our items on the toolbar
338  m_toolMenus.clear();
339  m_actionGroups.clear();
340  m_toolCancellable.clear();
341  m_toolKinds.clear();
342  m_toolActions.clear();
343 
344  // Remove the actual tools from the toolbar
345  Clear();
346 }
347 
348 
349 void ACTION_TOOLBAR::SetToolBitmap( const TOOL_ACTION& aAction, const wxBitmap& aBitmap )
350 {
351  int toolId = aAction.GetUIId();
352  wxAuiToolBar::SetToolBitmap( toolId, aBitmap );
353 
354  // Set the disabled bitmap: we use the disabled bitmap version
355  // of aBitmap.
356  wxAuiToolBarItem* tb_item = wxAuiToolBar::FindTool( toolId );
357 
358  if( tb_item )
359  tb_item->SetDisabledBitmap( aBitmap.ConvertToDisabled() );
360 }
361 
362 
363 void ACTION_TOOLBAR::Toggle( const TOOL_ACTION& aAction, bool aState )
364 {
365  int toolId = aAction.GetUIId();
366 
367  if( m_toolKinds[ toolId ] )
368  ToggleTool( toolId, aState );
369  else
370  EnableTool( toolId, aState );
371 }
372 
373 
374 void ACTION_TOOLBAR::Toggle( const TOOL_ACTION& aAction, bool aEnabled, bool aChecked )
375 {
376  int toolId = aAction.GetUIId();
377 
378  EnableTool( toolId, aEnabled );
379  ToggleTool( toolId, aEnabled && aChecked );
380 }
381 
382 
383 void ACTION_TOOLBAR::onToolEvent( wxAuiToolBarEvent& aEvent )
384 {
385  int id = aEvent.GetId();
386  wxEventType type = aEvent.GetEventType();
387  OPT_TOOL_EVENT evt;
388 
389  bool handled = false;
390 
391  if( m_toolManager && type == wxEVT_COMMAND_TOOL_CLICKED && id >= TOOL_ACTION::GetBaseUIId() )
392  {
393  const auto actionIt = m_toolActions.find( id );
394 
395  // The toolbar item is toggled before the event is sent, so we check for it not being
396  // toggled to see if it was toggled originally
397  if( m_toolCancellable[id] && !GetToolToggled( id ) )
398  {
399  // Send a cancel event
401  handled = true;
402  }
403  else if( actionIt != m_toolActions.end() )
404  {
405  // Dispatch a tool event
406  evt = actionIt->second->MakeEvent();
407  evt->SetHasPosition( false );
408  m_toolManager->ProcessEvent( *evt );
409  handled = true;
410  }
411  }
412 
413  // Skip the event if we don't handle it
414  if( !handled )
415  aEvent.Skip();
416 }
417 
418 
419 void ACTION_TOOLBAR::onToolRightClick( wxAuiToolBarEvent& aEvent )
420 {
421  int toolId = aEvent.GetToolId();
422 
423  // This means the event was not on a button
424  if( toolId == -1 )
425  return;
426 
427  // Ensure that the ID used maps to a proper tool ID.
428  // If right-clicked on a group item, this is needed to get the ID of the currently selected
429  // action, since the event's ID is that of the group.
430  const auto actionIt = m_toolActions.find( toolId );
431 
432  if( actionIt != m_toolActions.end() )
433  toolId = actionIt->second->GetUIId();
434 
435  // Find the menu for the action
436  const auto menuIt = m_toolMenus.find( toolId );
437 
438  if( menuIt == m_toolMenus.end() )
439  return;
440 
441  // Update and show the menu
442  std::unique_ptr<ACTION_MENU>& owningMenu = menuIt->second;
443 
444  // Get the actual menu pointer to show it
445  ACTION_MENU* menu = owningMenu.get();
446  SELECTION dummySel;
447 
448  if( CONDITIONAL_MENU* condMenu = dynamic_cast<CONDITIONAL_MENU*>( menu ) )
449  condMenu->Evaluate( dummySel );
450 
451  menu->UpdateAll();
452  PopupMenu( menu );
453 
454  // Remove hovered item when the menu closes, otherwise it remains hovered even if the
455  // mouse is not on the toolbar
456  SetHoverItem( nullptr );
457 }
458 
459 // The time (in milliseconds) between pressing the left mouse button and opening the palette
460 #define PALETTE_OPEN_DELAY 500
461 
462 
463 void ACTION_TOOLBAR::onMouseClick( wxMouseEvent& aEvent )
464 {
465  wxAuiToolBarItem* item = FindToolByPosition( aEvent.GetX(), aEvent.GetY() );
466 
467  if( item )
468  {
469  // Ensure there is no active palette
470  if( m_palette )
471  {
472  m_palette->Hide();
473  m_palette->Destroy();
474  m_palette = nullptr;
475  }
476 
477  // Start the popup conditions if it is a left mouse click and the tool clicked is a group
478  if( aEvent.LeftDown() && ( m_actionGroups.find( item->GetId() ) != m_actionGroups.end() ) )
479  m_paletteTimer->StartOnce( PALETTE_OPEN_DELAY );
480 
481  // Clear the popup conditions if it is a left up, because that implies a click happened
482  if( aEvent.LeftUp() )
483  m_paletteTimer->Stop();
484  }
485 
486  // Skip the event so wx can continue processing the mouse event
487  aEvent.Skip();
488 }
489 
490 
491 void ACTION_TOOLBAR::onItemDrag( wxAuiToolBarEvent& aEvent )
492 {
493  int toolId = aEvent.GetToolId();
494 
495  if( m_actionGroups.find( toolId ) != m_actionGroups.end() )
496  {
497  wxAuiToolBarItem* item = FindTool( toolId );
498 
499  // Use call after because opening the palette from a mouse handler
500  // creates a weird mouse state that causes problems on OSX.
501  CallAfter( &ACTION_TOOLBAR::popupPalette, item );
502 
503  // Don't skip this event since we are handling it
504  return;
505  }
506 
507  // Skip since we don't care about it
508  aEvent.Skip();
509 }
510 
511 
512 void ACTION_TOOLBAR::onTimerDone( wxTimerEvent& aEvent )
513 {
514  // We need to search for the tool using the client coordinates
515  wxPoint mousePos = ScreenToClient( wxGetMousePosition() );
516 
517  wxAuiToolBarItem* item = FindToolByPosition( mousePos.x, mousePos.y );
518 
519  if( item )
520  popupPalette( item );
521 }
522 
523 
524 void ACTION_TOOLBAR::onPaletteEvent( wxCommandEvent& aEvent )
525 {
526  if( !m_palette )
527  return;
528 
529  OPT_TOOL_EVENT evt;
530  ACTION_GROUP* group = m_palette->GetGroup();
531 
532  // Find the action corresponding to the button press
533  auto actionIt = std::find_if( group->GetActions().begin(), group->GetActions().end(),
534  [=]( const TOOL_ACTION* aAction )
535  {
536  return aAction->GetUIId() == aEvent.GetId();
537  } );
538 
539  if( actionIt != group->GetActions().end() )
540  {
541  const TOOL_ACTION* action = *actionIt;
542 
543  // Dispatch a tool event
544  evt = action->MakeEvent();
545  evt->SetHasPosition( false );
546  m_toolManager->ProcessEvent( *evt );
547 
548  // Update the main toolbar item with the selected action
549  doSelectAction( group, *action );
550  }
551 
552  // Hide the palette
553  m_palette->Hide();
554  m_palette->Destroy();
555  m_palette = nullptr;
556 }
557 
558 
559 void ACTION_TOOLBAR::popupPalette( wxAuiToolBarItem* aItem )
560 {
561  // Clear all popup conditions
562  m_paletteTimer->Stop();
563 
564  wxWindow* toolParent = dynamic_cast<wxWindow*>( m_toolManager->GetToolHolder() );
565 
566  wxASSERT( GetParent() );
567  wxASSERT( m_auiManager );
568  wxASSERT( toolParent );
569 
570  // Ensure the item we are using for the palette has a group associated with it.
571  const auto it = m_actionGroups.find( aItem->GetId() );
572 
573  if( it == m_actionGroups.end() )
574  return;
575 
576  ACTION_GROUP* group = it->second;
577 
578  wxAuiPaneInfo& pane = m_auiManager->GetPane( this );
579 
580  // We use the size of the toolbar items for our palette buttons
581  wxRect toolRect = GetToolRect( aItem->GetId() );
582 
583  // The position for the palette window must be in screen coordinates
584  wxPoint pos( ClientToScreen( toolRect.GetPosition() ) );
585 
586  // True for vertical buttons, false for horizontal
587  bool dir = true;
588  size_t numActions = group->m_actions.size();
589 
590  // The size of the palette in the long dimension
591  int paletteLongDim = ( 2 * PALETTE_BORDER ) // The border on all sides of the buttons
592  + ( BUTTON_BORDER ) // The border on the start of the buttons
593  + ( numActions * BUTTON_BORDER ) // The other button borders
594  + ( numActions * toolRect.GetHeight() ); // The size of the buttons
595 
596  // Determine the position of the top left corner of the palette window
597  switch( pane.dock_direction )
598  {
599  case wxAUI_DOCK_TOP:
600  // Top toolbars need to shift the palette window down by the toolbar padding
601  dir = true; // Buttons are vertical in the palette
602  pos = ClientToScreen( toolRect.GetBottomLeft() );
603  pos += wxPoint( -PALETTE_BORDER, // Shift left to align the button edges
604  m_bottomPadding ); // Shift down to move away from the toolbar
605  break;
606 
607  case wxAUI_DOCK_BOTTOM:
608  // Bottom toolbars need to shift the palette window up by its height (all buttons + border + toolbar padding)
609  dir = true; // Buttons are vertical in the palette
610  pos = ClientToScreen( toolRect.GetTopLeft() );
611  pos += wxPoint( -PALETTE_BORDER, // Shift left to align the button
612  -( paletteLongDim + m_topPadding ) ); // Shift up by the entire length of the palette
613  break;
614 
615  case wxAUI_DOCK_LEFT:
616  // Left toolbars need to shift the palette window up by the toolbar padding
617  dir = false; // Buttons are horizontal in the palette
618  pos = ClientToScreen( toolRect.GetTopRight() );
619  pos += wxPoint( m_rightPadding, // Shift right to move away from the toolbar
620  -( PALETTE_BORDER ) ); // Shift up to align the button tops
621  break;
622 
623  case wxAUI_DOCK_RIGHT:
624  // Right toolbars need to shift the palette window left by its width (all buttons + border + toolbar padding)
625  dir = false; // Buttons are horizontal in the palette
626  pos = ClientToScreen( toolRect.GetTopLeft() );
627  pos += wxPoint( -( paletteLongDim + m_leftPadding ), // Shift left by the entire length of the palette
628  -( PALETTE_BORDER ) ); // Shift up to align the button
629  break;
630  }
631 
632  m_palette = new ACTION_TOOLBAR_PALETTE( GetParent(), dir );
633 
634  // We handle the button events in the toolbar class, so connect the right handler
635  m_palette->SetGroup( group );
636  m_palette->SetButtonSize( toolRect );
637  m_palette->Connect( wxEVT_BUTTON, wxCommandEventHandler( ACTION_TOOLBAR::onPaletteEvent ),
638  NULL, this );
639 
640 
641  // Add the actions in the group to the palette and update their enabled state
642  // We purposely don't check items in the palette
643  for( const TOOL_ACTION* action : group->m_actions )
644  {
645  wxUpdateUIEvent evt( action->GetUIId() );
646 
647  toolParent->ProcessWindowEvent( evt );
648 
649  m_palette->AddAction( *action );
650 
651  if( evt.GetSetEnabled() )
652  m_palette->EnableAction( *action, evt.GetEnabled() );
653  }
654 
655  // Release the mouse to ensure the first click will be recognized in the palette
656  ReleaseMouse();
657 
658  m_palette->SetPosition( pos );
659  m_palette->Popup();
660 
661  // Clear the mouse state on the toolbar because otherwise wxWidgets gets confused
662  // and won't properly display any highlighted items after the palette is closed.
663  // (This is the equivalent of calling the DoResetMouseState() private function)
664  RefreshOverflowState();
665  SetHoverItem( nullptr );
666  SetPressedItem( nullptr );
667 
668  m_dragging = false;
669  m_tipItem = nullptr;
670  m_actionPos = wxPoint( -1, -1 );
671  m_actionItem = nullptr;
672 }
673 
674 
675 void ACTION_TOOLBAR::OnCustomRender(wxDC& aDc, const wxAuiToolBarItem& aItem,
676  const wxRect& aRect )
677 {
678  auto it = m_actionGroups.find( aItem.GetId() );
679 
680  if( it == m_actionGroups.end() )
681  return;
682 
683  // Choose the color to draw the triangle
684  wxColour clr;
685 
686  if( aItem.GetState() & wxAUI_BUTTON_STATE_DISABLED )
687  clr = wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT );
688  else
689  clr = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNTEXT );
690 
691  // Must set both the pen (for the outline) and the brush (for the polygon fill)
692  aDc.SetPen( wxPen( clr ) );
693  aDc.SetBrush( wxBrush( clr ) );
694 
695  // Make the side length of the triangle approximately 1/5th of the bitmap
696  int sideLength = KiROUND( aRect.height / 5.0 );
697 
698  // This will create a triangle with its point at the bottom right corner,
699  // and its other two corners along the right and bottom sides
700  wxPoint btmRight = aRect.GetBottomRight();
701  wxPoint topCorner( btmRight.x, btmRight.y - sideLength );
702  wxPoint btmCorner( btmRight.x - sideLength, btmRight.y );
703 
704  wxPointList points;
705  points.Append( &btmRight );
706  points.Append( &topCorner );
707  points.Append( &btmCorner );
708 
709  aDc.DrawPolygon( &points );
710 }
711 
712 
714 {
715  wxClientDC dc( this );
716  if( !dc.IsOk() )
717  return false;
718 
719  // calculate hint sizes for both horizontal and vertical
720  // in the order that leaves toolbar in correct final state
721 
722  // however, skip calculating alternate orientations if we dont need them due to window style
723  bool retval = true;
724  if( m_orientation == wxHORIZONTAL )
725  {
726  if( !( GetWindowStyle() & wxAUI_TB_HORIZONTAL ) )
727  {
728  m_vertHintSize = GetSize();
729  retval = RealizeHelper( dc, false );
730  }
731 
732  if( retval && RealizeHelper( dc, true ) )
733  {
734  m_horzHintSize = GetSize();
735  }
736  else
737  {
738  retval = false;
739  }
740  }
741  else
742  {
743  if( !( GetWindowStyle() & wxAUI_TB_VERTICAL ) )
744  {
745  m_horzHintSize = GetSize();
746  retval = RealizeHelper( dc, true );
747  }
748 
749  if( retval && RealizeHelper( dc, false ) )
750  {
751  m_vertHintSize = GetSize();
752  }
753  else
754  {
755  retval = false;
756  }
757  }
758 
759  Refresh( false );
760  return retval;
761 }
const TOOL_ACTION * m_defaultAction
The actions that compose the group.
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)
The default tool event handler.
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)
Generate an unique ID from for an action with given name.
int GetUIId() const
Definition: tool_action.h:112
ACTION_GROUP * GetGroup()
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:45
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)
Add 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 the button select inside the palette.
virtual void UnregisterUIUpdateHandler(const TOOL_ACTION &aAction)
Unregister a UI handler for an action that was registered using RegisterUIUpdateHandler.
Definition: tools_holder.h:84
void onTimerDone(wxTimerEvent &aEvent)
Render the triangle in the lower-right corner that represents that an action palette is available for...
void AddGroup(ACTION_GROUP *aGroup, bool aIsToggleEntry=false)
Add a set of actions to a toolbar as a group.
void UpdateAll()
Run update handlers for the menu and its submenus.
ACTION_TOOLBAR_PALETTE(wxWindow *aParent, bool aVertical)
Create the palette.
void onToolEvent(wxAuiToolBarEvent &aEvent)
Handle a right-click on a menu item.
std::map< int, const TOOL_ACTION * > m_toolActions
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:106
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
bool KiRealize()
Use this over Realize() to avoid a rendering glitch with fixed orientation toolbars.
static int GetBaseUIId()
Definition: tool_action.h:117
const BITMAP_OPAQUE * GetIcon() const
Return an icon associated with the action.
Definition: tool_action.h:169
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 when a drag event occurs on an item.
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)
Add a large button such as used in the KiCad Manager Frame's launch bar.
wxWidgets 3.1 has support for dark mode detection, but 3.0 doesn't.
#define NULL
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
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)
Propagate 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
ACTION_TOOLBAR_PALETTE * m_palette
wxString GetDescription(bool aIncludeHotkey=true) const
Definition: tool_action.cpp:83
std::vector< const TOOL_ACTION * > m_actions
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
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
wxRect m_buttonSize
True if the palette uses vertical buttons, false for horizontal buttons.
TOOLS_HOLDER * GetToolHolder() const
Definition: tool_manager.h:300
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
Return the unique id of the TOOL_ACTION object.
Definition: tool_action.h:103
const int scale
see class PGM_BASE
std::map< int, ACTION_GROUP * > m_actionGroups
ACTION_MANAGER * GetActionManager()
Definition: tool_manager.h:197
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 base frame for deriving all KiCad main window classes.
Represent a single user action.
Definition: tool_action.h:49
#define PALETTE_BORDER
void SetToolBitmap(const TOOL_ACTION &aAction, const wxBitmap &aBitmap)
Updates the bitmap of a particular tool.
TOOL_EVENT MakeEvent() const
Return the event associated with the action (i.e.
Definition: tool_action.h:123
void Toggle(const TOOL_ACTION &aAction, bool aState)
Apply 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
The buttons that act as the toolbar on the palette.
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:64
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)
Returns if the action associated with this event should be treated as immediate regardless of the cur...
Definition: tool_event.h:262
void CancelTool()
Send a cancel event to the tool currently at the top of the tool stack.
void onPaletteEvent(wxCommandEvent &aEvent)
Handle the palette timer triggering.
OPT< TOOL_EVENT > OPT_TOOL_EVENT
Definition: tool_event.h:569
std::string m_name
The default action to display on the toolbar item.
const std::string & GetName() const
Return name of the action.
Definition: tool_action.h:83
void ClearToolbar()
Clear the toolbar and remove all associated menus.