From fc565edb33e035d7d23b67f300585c8475390d42 Mon Sep 17 00:00:00 2001 From: Ian McInerney Date: Sun, 27 Sep 2020 00:55:59 +0100 Subject: [PATCH] Add a palette to the toolbars to display groups of actions This adds a palette to toolbar items that displays groups of actions when long-pressed on a button. --- 3d-viewer/3d_viewer/3d_toolbar.cpp | 5 + common/tool/action_toolbar.cpp | 414 ++++++++++++++++++++++- cvpcb/display_footprints_frame.cpp | 10 + cvpcb/toolbars_cvpcb.cpp | 5 + eeschema/libedit/toolbars_libedit.cpp | 15 + eeschema/toolbars_lib_view.cpp | 5 + eeschema/toolbars_sch_editor.cpp | 15 + gerbview/toolbars_gerber.cpp | 15 + include/eda_base_frame.h | 15 +- include/tool/action_toolbar.h | 206 ++++++++++- include/tool/tools_holder.h | 21 ++ kicad/menubar.cpp | 10 + pagelayout_editor/toolbars_pl_editor.cpp | 10 + pcbnew/footprint_wizard_frame.cpp | 5 + pcbnew/pcb_edit_frame.cpp | 17 +- pcbnew/toolbars_footprint_editor.cpp | 15 + pcbnew/toolbars_footprint_viewer.cpp | 10 + pcbnew/toolbars_pcb_editor.cpp | 70 +++- 18 files changed, 817 insertions(+), 46 deletions(-) diff --git a/3d-viewer/3d_viewer/3d_toolbar.cpp b/3d-viewer/3d_viewer/3d_toolbar.cpp index 9a15563193..ee5340d59d 100644 --- a/3d-viewer/3d_viewer/3d_toolbar.cpp +++ b/3d-viewer/3d_viewer/3d_toolbar.cpp @@ -43,10 +43,15 @@ void EDA_3D_VIEWER::ReCreateMainToolbar() wxWindowUpdateLocker dummy( this ); if( m_mainToolBar ) + { m_mainToolBar->ClearToolbar(); + } else + { m_mainToolBar = new ACTION_TOOLBAR( this, ID_H_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT ); + m_mainToolBar->SetAuiManager( &m_auimgr ); + } // Set up toolbar m_mainToolBar->AddTool( ID_RELOAD3D_BOARD, wxEmptyString, diff --git a/common/tool/action_toolbar.cpp b/common/tool/action_toolbar.cpp index 1a7078c1bf..133dc76600 100644 --- a/common/tool/action_toolbar.cpp +++ b/common/tool/action_toolbar.cpp @@ -22,9 +22,11 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#include #include #include #include +#include #include #include #include @@ -33,22 +35,157 @@ #include #include #include +#include +#include +#include + + +ACTION_GROUP::ACTION_GROUP( std::string aName, const std::vector& aActions ) +{ + wxASSERT_MSG( aActions.size() > 0, "Action groups must have at least one action" ); + + // The default action is just the first action in the vector + m_actions = aActions; + m_defaultAction = m_actions[0]; + + m_name = aName; + m_id = ACTION_MANAGER::MakeActionId( m_name ); +} + + +void ACTION_GROUP::SetDefaultAction( const TOOL_ACTION& aDefault ) +{ + bool valid = std::any_of( m_actions.begin(), m_actions.end(), + [&]( const TOOL_ACTION* aAction ) -> bool + { + // For some reason, we can't compare the actions directly + return aAction->GetId() == aDefault.GetId(); + } ); + + wxASSERT_MSG( valid, "Action must be present in a group to be the default" ); + + m_defaultAction = &aDefault; +} + + +#define PALETTE_BORDER 4 // The border around the palette buttons on all sides +#define BUTTON_BORDER 1 // The border on the sides of the buttons that touch other buttons + + +ACTION_TOOLBAR_PALETTE::ACTION_TOOLBAR_PALETTE( wxWindow* aParent, bool aVertical ) : + wxPopupTransientWindow( aParent, wxBORDER_NONE ), + m_group( nullptr ), + m_isVertical( aVertical ), + m_panel( nullptr ), + m_mainSizer( nullptr ), + m_buttonSizer( nullptr ) +{ + m_panel = new wxPanel( this, wxID_ANY ); + m_panel->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); + + // This sizer holds the buttons for the actions + m_buttonSizer = new wxBoxSizer( aVertical ? wxVERTICAL : wxHORIZONTAL ); + + // This sizer holds the other sizer, so that a consistent border is present on all sides + m_mainSizer = new wxBoxSizer( aVertical ? wxVERTICAL : wxHORIZONTAL ); + m_mainSizer->Add( m_buttonSizer, wxSizerFlags().Border( wxALL, PALETTE_BORDER ) ); + + m_panel->SetSizer( m_mainSizer ); + + Connect( wxEVT_CHAR_HOOK, wxCharEventHandler( ACTION_TOOLBAR_PALETTE::onCharHook ), + NULL, this ); +} + + +void ACTION_TOOLBAR_PALETTE::AddAction( const TOOL_ACTION& aAction ) +{ + wxBitmap normalBmp = KiScaledBitmap( aAction.GetIcon(), this ); + wxBitmap disabledBmp = normalBmp.ConvertToDisabled(); + + int padding = ( m_buttonSize.GetWidth() - normalBmp.GetWidth() ) / 2; + + BITMAP_BUTTON* button = new BITMAP_BUTTON( m_panel, aAction.GetUIId() ); + + button->SetBitmap( normalBmp ); + button->SetDisabledBitmap( disabledBmp ); + button->SetPadding( padding ); + button->SetToolTip( aAction.GetDescription() ); + + m_buttons[aAction.GetUIId()] = button; + + if( m_isVertical ) + m_buttonSizer->Add( button, wxSizerFlags().Border( wxTOP | wxBOTTOM, BUTTON_BORDER ) ); + else + m_buttonSizer->Add( button, wxSizerFlags().Border( wxLEFT | wxRIGHT, BUTTON_BORDER ) ); + + m_buttonSizer->Layout(); +} + + +void ACTION_TOOLBAR_PALETTE::EnableAction( const TOOL_ACTION& aAction, bool aEnable ) +{ + auto it = m_buttons.find( aAction.GetUIId() ); + + if( it != m_buttons.end() ) + it->second->Enable( aEnable ); +} + + +void ACTION_TOOLBAR_PALETTE::CheckAction( const TOOL_ACTION& aAction, bool aCheck ) +{ + auto it = m_buttons.find( aAction.GetUIId() ); + + if( it != m_buttons.end() ) + it->second->Check( aCheck ); +} + + +void ACTION_TOOLBAR_PALETTE::Popup( wxWindow* aFocus ) +{ + m_mainSizer->Fit( m_panel ); + SetClientSize( m_panel->GetSize() ); + + wxPopupTransientWindow::Popup( aFocus ); +} + + +void ACTION_TOOLBAR_PALETTE::onCharHook( wxKeyEvent& aEvent ) +{ + // Allow the escape key to dismiss this popup + if( aEvent.GetKeyCode() == WXK_ESCAPE ) + Dismiss(); + else + aEvent.Skip(); +} ACTION_TOOLBAR::ACTION_TOOLBAR( EDA_BASE_FRAME* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxAuiToolBar( parent, id, pos, size, style ), - m_toolManager( parent->GetToolManager() ) + m_toolManager( parent->GetToolManager() ), + m_palette( nullptr ), + m_paletteTimer( nullptr ), + m_auiManager( nullptr ) { + m_paletteTimer = new wxTimer( this ); + Connect( wxEVT_COMMAND_TOOL_CLICKED, wxAuiToolBarEventHandler( ACTION_TOOLBAR::onToolEvent ), NULL, this ); Connect( wxEVT_AUITOOLBAR_RIGHT_CLICK, wxAuiToolBarEventHandler( ACTION_TOOLBAR::onToolRightClick ), NULL, this ); + Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( ACTION_TOOLBAR::onMouseEvent ), + NULL, this ); + Connect( wxEVT_LEFT_UP, wxMouseEventHandler( ACTION_TOOLBAR::onMouseEvent ), + NULL, this ); + Connect( m_paletteTimer->GetId(), wxEVT_TIMER, wxTimerEventHandler( ACTION_TOOLBAR::onTimerDone ), + NULL, this ); } ACTION_TOOLBAR::~ACTION_TOOLBAR() { + delete m_paletteTimer; + // Delete all the menus for( auto it = m_toolMenus.begin(); it != m_toolMenus.end(); it++ ) delete it->second; @@ -123,6 +260,75 @@ void ACTION_TOOLBAR::AddToolContextMenu( const TOOL_ACTION& aAction, ACTION_MENU } +void ACTION_TOOLBAR::AddGroup( ACTION_GROUP* aGroup, bool aIsToggleEntry ) +{ + int groupId = aGroup->GetUIId(); + const TOOL_ACTION* defaultAction = aGroup->GetDefaultAction(); + wxWindow* parent = dynamic_cast( m_toolManager->GetToolHolder() ); + + wxASSERT( defaultAction ); + + m_toolKinds[ groupId ] = aIsToggleEntry; + m_toolActions[ groupId ] = defaultAction; + m_actionGroups[ groupId ] = aGroup; + + // Add the main toolbar item representing the group + AddTool( groupId, wxEmptyString, KiScaledBitmap( defaultAction->GetIcon(), parent ), + wxEmptyString, aIsToggleEntry ? wxITEM_CHECK : wxITEM_NORMAL ); + + // Select the default action + doSelectAction( aGroup, *defaultAction ); +} + + +void ACTION_TOOLBAR::SelectAction( ACTION_GROUP* aGroup, const TOOL_ACTION& aAction ) +{ + bool valid = std::any_of( aGroup->m_actions.begin(), aGroup->m_actions.end(), + [&]( const TOOL_ACTION* action2 ) -> bool + { + // For some reason, we can't compare the actions directly + return aAction.GetId() == action2->GetId(); + } ); + + if( valid ) + doSelectAction( aGroup, aAction ); +} + + +void ACTION_TOOLBAR::doSelectAction( ACTION_GROUP* aGroup, const TOOL_ACTION& aAction ) +{ + int groupId = aGroup->GetUIId(); + + wxAuiToolBarItem* item = FindTool( groupId ); + wxWindow* parent = dynamic_cast( m_toolManager->GetToolHolder() ); + + if( !item ) + return; + + // Update the item information + item->SetShortHelp( aAction.GetDescription() ); + item->SetBitmap( KiScaledBitmap( aAction.GetIcon(), parent ) ); + item->SetDisabledBitmap( item->GetBitmap().ConvertToDisabled() ); + + // Register a new handler with the new UI conditions + if( m_toolManager ) + { + const ACTION_CONDITIONS* cond = m_toolManager->GetActionManager()->GetCondition( aAction ); + + wxASSERT_MSG( cond, wxString::Format( "Missing UI condition for action %s", + aAction.GetName() ) ); + + m_toolManager->GetToolHolder()->UnregisterUIUpdateHandler( groupId ); + m_toolManager->GetToolHolder()->RegisterUIUpdateHandler( groupId, *cond ); + } + + // Update the currently selected action + m_toolActions[ groupId ] = &aAction; + + Refresh(); +} + + void ACTION_TOOLBAR::ClearToolbar() { // Delete all the menus @@ -213,13 +419,22 @@ void ACTION_TOOLBAR::onToolRightClick( wxAuiToolBarEvent& aEvent ) if( toolId == -1 ) return; - const auto it = m_toolMenus.find( aEvent.GetId() ); + // Ensure that the ID used maps to a proper tool ID. + // If right-clicked on a group item, this is needed to get the ID of the currently selected + // action, since the event's ID is that of the group. + const auto actionIt = m_toolActions.find( toolId ); - if( it == m_toolMenus.end() ) + if( actionIt != m_toolActions.end() ) + toolId = actionIt->second->GetUIId(); + + // Find the menu for the action + const auto menuIt = m_toolMenus.find( toolId ); + + if( menuIt == m_toolMenus.end() ) return; // Update and show the menu - ACTION_MENU* menu = it->second; + ACTION_MENU* menu = menuIt->second; SELECTION dummySel; if( CONDITIONAL_MENU* condMenu = dynamic_cast( menu ) ) @@ -232,3 +447,194 @@ void ACTION_TOOLBAR::onToolRightClick( wxAuiToolBarEvent& aEvent ) // mouse is not on the toolbar SetHoverItem( nullptr ); } + +// The time (in milliseconds) between pressing the left mouse button and opening the palette +#define PALETTE_OPEN_DELAY 500 + + +void ACTION_TOOLBAR::onMouseEvent( wxMouseEvent& aEvent ) +{ + wxAuiToolBarItem* item = FindToolByPosition( aEvent.GetX(), aEvent.GetY() ); + + if( item ) + { + // Ensure there is no active palette + if( m_palette ) + { + m_palette->Hide(); + m_palette->Destroy(); + m_palette = nullptr; + } + + // Start the timer if it is a left mouse click and the tool clicked is a group + if( aEvent.LeftDown() && ( m_actionGroups.find( item->GetId() ) != m_actionGroups.end() ) ) + m_paletteTimer->StartOnce( PALETTE_OPEN_DELAY ); + + // Stop the timer if there is a left up, because that implies a click happened + if( aEvent.LeftUp() ) + m_paletteTimer->Stop(); + } + + // Skip the event so wx can continue processing the mouse event + aEvent.Skip(); +} + + +void ACTION_TOOLBAR::onPaletteEvent( wxCommandEvent& aEvent ) +{ + if( !m_palette ) + return; + + OPT_TOOL_EVENT evt; + ACTION_GROUP* group = m_palette->GetGroup(); + + // Find the action corresponding to the button press + auto actionIt = std::find_if( group->GetActions().begin(), group->GetActions().end(), + [=]( const TOOL_ACTION* aAction ) + { + return aAction->GetUIId() == aEvent.GetId(); + } ); + + if( actionIt != group->GetActions().end() ) + { + const TOOL_ACTION* action = *actionIt; + + // Dispatch a tool event + evt = action->MakeEvent(); + evt->SetHasPosition( false ); + m_toolManager->ProcessEvent( *evt ); + + // Update the main toolbar item with the selected action + doSelectAction( group, *action ); + } + + // Hide the palette + m_palette->Hide(); + m_palette->Destroy(); + m_palette = nullptr; +} + +void ACTION_TOOLBAR::onTimerDone( wxTimerEvent& aEvent ) +{ + // We need to search for the tool using the client coordinates + wxPoint mousePos = ScreenToClient( wxGetMousePosition() ); + + wxWindow* parent = dynamic_cast( m_toolManager->GetToolHolder() ); + wxAuiToolBarItem* item = FindToolByPosition( mousePos.x, mousePos.y ); + + wxASSERT( m_auiManager ); + wxASSERT( parent ); + + if( !item ) + return; + + // The mouse could have been moved off of the button with the group, so we test + // for it again to see if we are still on an item with a group. + const auto it = m_actionGroups.find( item->GetId() ); + + if( it == m_actionGroups.end() ) + return; + + ACTION_GROUP* group = it->second; + + m_palette = new ACTION_TOOLBAR_PALETTE( parent, true ); + + // We handle the button events in the toolbar class, so connect the right handler + m_palette->SetGroup( group ); + m_palette->Connect( wxEVT_BUTTON, wxCommandEventHandler( ACTION_TOOLBAR::onPaletteEvent ), + NULL, this ); + + // This button size is used for all buttons on the toolbar + wxRect toolRect = GetToolRect( item->GetId() ); + m_palette->SetButtonSize( toolRect ); + + // Add the actions in the group to the palette and update their state + for( const TOOL_ACTION* action : group->m_actions ) + { + wxUpdateUIEvent evt( action->GetUIId() ); + + parent->ProcessWindowEvent( evt ); + + m_palette->AddAction( *action ); + + if( evt.GetSetChecked() ) + m_palette->CheckAction( *action, evt.GetChecked() ); + + if( evt.GetSetEnabled() ) + m_palette->EnableAction( *action, evt.GetEnabled() ); + } + + wxAuiPaneInfo& pane = m_auiManager->GetPane( this ); + + // The position for the palette window must be in screen coordinates + wxPoint pos( ClientToScreen( toolRect.GetPosition() ) ); + + // Determine the position of the top left corner of the palette window + switch( pane.dock_direction ) + { + case wxAUI_DOCK_TOP: + // Top toolbars need to shift the palette window down by the toolbar padding + pos = ClientToScreen( toolRect.GetBottomLeft() ); + pos += wxPoint( 0, GetToolBorderPadding() ); + break; + + case wxAUI_DOCK_BOTTOM: + // Bottom toolbars need to shift the palette window up by its height (1 button + border + toolbar padding) + pos = ClientToScreen( toolRect.GetTopLeft() ); + pos -= wxPoint( GetToolBorderPadding(), 2*PALETTE_BORDER + toolRect.GetHeight() + GetToolBorderPadding() ); + break; + + case wxAUI_DOCK_LEFT: + // Left toolbars need to shift the palette window up by the toolbar padding + pos = ClientToScreen( toolRect.GetTopRight() ); + pos += wxPoint( GetToolBorderPadding(), 0 ); + break; + + case wxAUI_DOCK_RIGHT: + // Right toolbars need to shift the palette window left by its width (1 button + border + toolbar padding) + pos = ClientToScreen( toolRect.GetTopLeft() ); + pos -= wxPoint( 2*PALETTE_BORDER + toolRect.GetHeight() + GetToolBorderPadding(), 0 ); + break; + } + + m_palette->SetPosition( pos ); + m_palette->Popup(); +} + + +void ACTION_TOOLBAR::OnCustomRender(wxDC& aDc, const wxAuiToolBarItem& aItem, + const wxRect& aRect ) +{ + auto it = m_actionGroups.find( aItem.GetId() ); + + if( it == m_actionGroups.end() ) + return; + + // Choose the color to draw the triangle + wxColour clr; + + if( aItem.GetState() & wxAUI_BUTTON_STATE_DISABLED ) + clr = wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ); + else + clr = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNTEXT ); + + // Must set both the pen (for the outline) and the brush (for the polygon fill) + aDc.SetPen( wxPen( clr ) ); + aDc.SetBrush( wxBrush( clr ) ); + + // Make the side length of the triangle approximately 1/5th of the bitmap + int sideLength = KiROUND( aRect.height / 5.0 ); + + // This will create a triangle with its point at the bottom right corner, + // and its other two corners along the right and bottom sides + wxPoint btmRight = aRect.GetBottomRight(); + wxPoint topCorner( btmRight.x, btmRight.y - sideLength ); + wxPoint btmCorner( btmRight.x - sideLength, btmRight.y ); + + wxPointList points; + points.Append( &btmRight ); + points.Append( &topCorner ); + points.Append( &btmCorner ); + + aDc.DrawPolygon( &points ); +} diff --git a/cvpcb/display_footprints_frame.cpp b/cvpcb/display_footprints_frame.cpp index 89aeea8ed1..eb039727e7 100644 --- a/cvpcb/display_footprints_frame.cpp +++ b/cvpcb/display_footprints_frame.cpp @@ -229,10 +229,15 @@ void DISPLAY_FOOTPRINTS_FRAME::ReCreateVToolbar() void DISPLAY_FOOTPRINTS_FRAME::ReCreateOptToolbar() { if( m_optionsToolBar ) + { m_optionsToolBar->ClearToolbar(); + } else + { m_optionsToolBar = new ACTION_TOOLBAR( this, ID_OPT_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_VERTICAL ); + m_optionsToolBar->SetAuiManager( &m_auimgr ); + } m_optionsToolBar->Add( ACTIONS::selectionTool, ACTION_TOOLBAR::TOGGLE ); m_optionsToolBar->Add( ACTIONS::measureTool, ACTION_TOOLBAR::TOGGLE ); @@ -264,10 +269,15 @@ void DISPLAY_FOOTPRINTS_FRAME::ReCreateHToolbar() // So we do not recreate them after clearing the tools. if( m_mainToolBar ) + { m_mainToolBar->ClearToolbar(); + } else + { m_mainToolBar = new ACTION_TOOLBAR( this, ID_H_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT ); + m_mainToolBar->SetAuiManager( &m_auimgr ); + } m_mainToolBar->Add( ACTIONS::zoomRedraw ); m_mainToolBar->Add( ACTIONS::zoomInCenter ); diff --git a/cvpcb/toolbars_cvpcb.cpp b/cvpcb/toolbars_cvpcb.cpp index 12aec18dc6..7f30172b94 100644 --- a/cvpcb/toolbars_cvpcb.cpp +++ b/cvpcb/toolbars_cvpcb.cpp @@ -35,10 +35,15 @@ void CVPCB_MAINFRAME::ReCreateHToolbar() { if( m_mainToolBar ) + { m_mainToolBar->ClearToolbar(); + } else + { m_mainToolBar = new ACTION_TOOLBAR( this, ID_H_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT ); + m_mainToolBar->SetAuiManager( &m_auimgr ); + } m_mainToolBar->Add( CVPCB_ACTIONS::saveAssociations ); diff --git a/eeschema/libedit/toolbars_libedit.cpp b/eeschema/libedit/toolbars_libedit.cpp index 41d39b0778..ede9a2d4c3 100644 --- a/eeschema/libedit/toolbars_libedit.cpp +++ b/eeschema/libedit/toolbars_libedit.cpp @@ -45,10 +45,15 @@ void LIB_EDIT_FRAME::ReCreateVToolbar() { if( m_drawToolBar ) + { m_drawToolBar->ClearToolbar(); + } else + { m_drawToolBar = new ACTION_TOOLBAR( this, ID_V_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_VERTICAL ); + m_drawToolBar->SetAuiManager( &m_auimgr ); + } // Set up toolbar m_drawToolBar->Add( ACTIONS::selectionTool, ACTION_TOOLBAR::TOGGLE ); @@ -79,10 +84,15 @@ void LIB_EDIT_FRAME::ReCreateVToolbar() void LIB_EDIT_FRAME::ReCreateHToolbar() { if( m_mainToolBar ) + { m_mainToolBar->ClearToolbar(); + } else + { m_mainToolBar = new ACTION_TOOLBAR( this, ID_H_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT ); + m_mainToolBar->SetAuiManager( &m_auimgr ); + } // Set up toolbar m_mainToolBar->Add( EE_ACTIONS::newSymbol ); @@ -137,11 +147,16 @@ void LIB_EDIT_FRAME::ReCreateHToolbar() void LIB_EDIT_FRAME::ReCreateOptToolbar() { if( m_optionsToolBar ) + { m_optionsToolBar->ClearToolbar(); + } else + { m_optionsToolBar = new ACTION_TOOLBAR( this, ID_OPT_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_VERTICAL ); + m_optionsToolBar->SetAuiManager( &m_auimgr ); + } m_optionsToolBar->Add( ACTIONS::toggleGrid, ACTION_TOOLBAR::TOGGLE ); m_optionsToolBar->Add( ACTIONS::imperialUnits, ACTION_TOOLBAR::TOGGLE ); diff --git a/eeschema/toolbars_lib_view.cpp b/eeschema/toolbars_lib_view.cpp index 15d44f2fa5..9434c25aa0 100644 --- a/eeschema/toolbars_lib_view.cpp +++ b/eeschema/toolbars_lib_view.cpp @@ -37,11 +37,16 @@ void LIB_VIEW_FRAME::ReCreateHToolbar() { if( m_mainToolBar ) + { m_mainToolBar->ClearToolbar(); + } else + { m_mainToolBar = new ACTION_TOOLBAR( this, ID_H_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT ); + m_mainToolBar->SetAuiManager( &m_auimgr ); + } m_mainToolBar->AddTool( ID_LIBVIEW_SELECT_PART, wxEmptyString, KiScaledBitmap( add_component_xpm, this ), diff --git a/eeschema/toolbars_sch_editor.cpp b/eeschema/toolbars_sch_editor.cpp index d86bb7fb23..61aa8c91dc 100644 --- a/eeschema/toolbars_sch_editor.cpp +++ b/eeschema/toolbars_sch_editor.cpp @@ -39,11 +39,16 @@ void SCH_EDIT_FRAME::ReCreateHToolbar() { if( m_mainToolBar ) + { m_mainToolBar->ClearToolbar(); + } else + { m_mainToolBar = new ACTION_TOOLBAR( this, ID_H_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT ); + m_mainToolBar->SetAuiManager( &m_auimgr ); + } // Set up toolbar if( Kiface().IsSingle() ) // not when under a project mgr @@ -110,10 +115,15 @@ void SCH_EDIT_FRAME::ReCreateHToolbar() void SCH_EDIT_FRAME::ReCreateVToolbar() { if( m_drawToolBar ) + { m_drawToolBar->ClearToolbar(); + } else + { m_drawToolBar = new ACTION_TOOLBAR( this, ID_V_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_VERTICAL ); + m_drawToolBar->SetAuiManager( &m_auimgr ); + } // Set up toolbar m_drawToolBar->Add( ACTIONS::selectionTool, ACTION_TOOLBAR::TOGGLE ); @@ -148,11 +158,16 @@ void SCH_EDIT_FRAME::ReCreateVToolbar() void SCH_EDIT_FRAME::ReCreateOptToolbar() { if( m_optionsToolBar ) + { m_optionsToolBar->ClearToolbar(); + } else + { m_optionsToolBar = new ACTION_TOOLBAR( this, ID_OPT_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_VERTICAL ); + m_optionsToolBar->SetAuiManager( &m_auimgr ); + } m_optionsToolBar->Add( ACTIONS::toggleGrid, ACTION_TOOLBAR::TOGGLE ); m_optionsToolBar->Add( ACTIONS::imperialUnits, ACTION_TOOLBAR::TOGGLE ); diff --git a/gerbview/toolbars_gerber.cpp b/gerbview/toolbars_gerber.cpp index a76bffabf4..c5511f644c 100644 --- a/gerbview/toolbars_gerber.cpp +++ b/gerbview/toolbars_gerber.cpp @@ -47,10 +47,15 @@ void GERBVIEW_FRAME::ReCreateHToolbar() // So we do not recreate them after clearing the tools. if( m_mainToolBar ) + { m_mainToolBar->ClearToolbar(); + } else + { m_mainToolBar = new ACTION_TOOLBAR( this, ID_H_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT ); + m_mainToolBar->SetAuiManager( &m_auimgr ); + } // Set up toolbar m_mainToolBar->AddTool( ID_GERBVIEW_ERASE_ALL, wxEmptyString, @@ -101,11 +106,16 @@ void GERBVIEW_FRAME::ReCreateAuxiliaryToolbar() wxWindowUpdateLocker dummy( this ); if( m_auxiliaryToolBar ) + { m_auxiliaryToolBar->ClearToolbar(); + } else + { m_auxiliaryToolBar = new ACTION_TOOLBAR( this, ID_AUX_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT ); + m_auxiliaryToolBar->SetAuiManager( &m_auimgr ); + } // Creates box to display and choose components: // (note, when the m_auxiliaryToolBar is recreated, tools are deleted, but controls @@ -223,10 +233,15 @@ void GERBVIEW_FRAME::ReCreateVToolbar() void GERBVIEW_FRAME::ReCreateOptToolbar() { if( m_optionsToolBar ) + { m_optionsToolBar->ClearToolbar(); + } else + { m_optionsToolBar = new ACTION_TOOLBAR( this, ID_OPT_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_VERTICAL ); + m_optionsToolBar->SetAuiManager( &m_auimgr ); + } // TODO: these can be moved to the 'proper' vertical toolbar if and when there are // actual tools to put there. That, or I'll get around to implementing configurable diff --git a/include/eda_base_frame.h b/include/eda_base_frame.h index 774f630b4e..e4ddb219a3 100644 --- a/include/eda_base_frame.h +++ b/include/eda_base_frame.h @@ -283,31 +283,20 @@ public: */ void OnMenuEvent( wxMenuEvent& event ); - virtual void RegisterUIUpdateHandler( const TOOL_ACTION& aAction, - const ACTION_CONDITIONS& aConditions ) override - { - RegisterUIUpdateHandler( aAction.GetUIId(), aConditions ); - } - /** * Register a UI update handler for the control with ID @c aID * * @param aID is the control ID to register the handler for * @param aConditions are the UI conditions to use for the control states */ - virtual void RegisterUIUpdateHandler( int aID, const ACTION_CONDITIONS& aConditions ); - - virtual void UnregisterUIUpdateHandler( const TOOL_ACTION& aAction ) override - { - UnregisterUIUpdateHandler( aAction.GetUIId() ); - } + virtual void RegisterUIUpdateHandler( int aID, const ACTION_CONDITIONS& aConditions ) override; /** * Unregister a UI handler for a given ID that was registered using @c RegisterUIUpdateHandler * * @param aID is the control ID to unregister the handler for */ - virtual void UnregisterUIUpdateHandler( int aID ); + virtual void UnregisterUIUpdateHandler( int aID ) override; /** * Handles events generated when the UI is trying to figure out the current state of the UI controls diff --git a/include/tool/action_toolbar.h b/include/tool/action_toolbar.h index 331a41c648..bae272286f 100644 --- a/include/tool/action_toolbar.h +++ b/include/tool/action_toolbar.h @@ -25,14 +25,156 @@ #define ACTION_TOOLBAR_H #include +#include #include // Needed for the auibar include #include +#include +#include +#include +#include #include class ACTION_MENU; +class BITMAP_BUTTON; class EDA_BASE_FRAME; class TOOL_MANAGER; -class TOOL_ACTION; + +/** + * A group of actions that will be displayed together on a toolbar palette. + */ +class ACTION_GROUP +{ +public: + // Make the toolbar a friend so it can easily access everything inside here + friend class ACTION_TOOLBAR; + + ACTION_GROUP( std::string aName, const std::vector& aActions ); + + /** + * Set the default action to use when first creating the toolbar palette icon. + * If no default action is provided, the default will be the first action in the + * vector. + * + * @param aDefault is the default action. + */ + void SetDefaultAction( const TOOL_ACTION& aDefault ); + + /** + * Get the default action to use when first creating this group's toolbar palette icon. + */ + const TOOL_ACTION* GetDefaultAction() const { return m_defaultAction; } + + /** + * Get the name of the group. + */ + std::string GetName() const { return m_name; } + + /** + * Get the ID used in the UI to reference this group + */ + int GetUIId() const { return m_id + TOOL_ACTION::GetBaseUIId(); } + + /** + * Get a vector of all the actions contained inside this group. + */ + const std::vector< const TOOL_ACTION*>& GetActions() const { return m_actions; } + +protected: + ///> The action ID for this action group + int m_id; + + ///> The name of this action group + std::string m_name; + + ///> The default action to display on the toolbar item + const TOOL_ACTION* m_defaultAction; + + ///> The actions that compose the group + std::vector m_actions; +}; + + +/** + * A popup window that contains a row of toolbar-like buttons for the user to choose from. + */ +class ACTION_TOOLBAR_PALETTE : public wxPopupTransientWindow +{ +public: + /** + * Create the palette. + * + * @param aParent is the parent window + * @param aVertical is true if the palette should make the buttons a vertical line, + * false for a horizonatl line. + */ + ACTION_TOOLBAR_PALETTE( wxWindow* aParent, bool aVertical ); + + /** + * Add an action to the palette. + * + * @param aAction is the action to add + */ + void AddAction( const TOOL_ACTION& aAction ); + + /** + * Enable the button for an action on the palette. + * + * @param aAction is the action who's button should be enabled + * @param aEnable is true to enable the button, false to disable + */ + void EnableAction( const TOOL_ACTION& aAction, bool aEnable = true ); + + /** + * Check/Toggle the button for an action on the palette. + * + * @param aAction is the action who's button should be checked + * @param aCheck is true to check the button, false to uncheck + */ + void CheckAction( const TOOL_ACTION& aAction, bool aCheck = true ); + + /** + * Set the size all the buttons on this palette should be. + * This function will automatically pad all button bitmaps to ensure this + * size is met. + * + * @param aSize is the requested size of the buttons + */ + void SetButtonSize( wxRect& aSize ) { m_buttonSize = aSize; } + + /** + * Popup this window + * + * @param aFocus is the window to keep focus on (if supported) + */ + void Popup( wxWindow* aFocus = nullptr ); + + /** + * Set the action group that this palette contains the actions for + */ + void SetGroup( ACTION_GROUP* aGroup ) { m_group = aGroup; } + ACTION_GROUP* GetGroup() { return m_group; } + +protected: + void onCharHook( wxKeyEvent& aEvent ); + +protected: + // The group that the buttons in the palette are part of + ACTION_GROUP* m_group; + + ///> The size each button on the toolbar should be + wxRect m_buttonSize; + + ///> True if the palette uses vertical buttons, false for horizontal buttons + bool m_isVertical; + + wxPanel* m_panel; + wxBoxSizer* m_mainSizer; + wxBoxSizer* m_buttonSizer; + + ///> The buttons that act as the toolbar on the palette + std::map m_buttons; +}; + /** * ACTION_TOOLBAR @@ -48,6 +190,13 @@ public: virtual ~ACTION_TOOLBAR(); + /** + * Set the AUI manager that this toolbar belongs to. + * + * @param aManager is the AUI manager + */ + void SetAuiManager( wxAuiManager* aManager ) { m_auiManager = aManager; } + /** * Adds a TOOL_ACTION-based button to the toolbar. After selecting the entry, * a TOOL_EVENT command containing name of the action is sent. @@ -84,6 +233,23 @@ public: */ void AddToolContextMenu( const TOOL_ACTION& aAction, ACTION_MENU* aMenu ); + /** + * Add a set of actions to a toolbar as a group. One action from the group will be displayed + * at a time. + * + * @param aGroup is the group to add. The first action in the group will be the first shown on the toolbar. + * @param aIsToggleEntry makes the toolbar item a toggle entry when true + */ + void AddGroup( ACTION_GROUP* aGroup, bool aIsToggleEntry = false ); + + /** + * Select an action inside a group + * + * @param aGroup is the group that contains the action + * @param aAction is the action inside the group + */ + void SelectAction( ACTION_GROUP* aGroup, const TOOL_ACTION& aAction ); + /** * Clear the toolbar and remove all associated menus. */ @@ -107,18 +273,46 @@ public: static constexpr bool CANCEL = true; protected: + /** + * Update a group toolbar item to look like a specific action. + * + * Note: This function does not verify that the action is inside the group. + */ + void doSelectAction( ACTION_GROUP* aGroup, const TOOL_ACTION& aAction ); + + ///> Handler for a mouse up/down event + void onMouseEvent( wxMouseEvent& aEvent ); + ///> The default tool event handler. void onToolEvent( wxAuiToolBarEvent& aEvent ); ///> Handle a right-click on a menu item void onToolRightClick( wxAuiToolBarEvent& aEvent ); + ///> Handle the button select inside the palette + void onPaletteEvent( wxCommandEvent& aEvent ); + + ///> Handle the palette timer triggering + void onTimerDone( wxTimerEvent& aEvent ); + + ///> Render the triangle in the lower-right corner that represents that an action pallette + ///> is available for an item + void OnCustomRender( wxDC& aDc, const wxAuiToolBarItem& aItem, + const wxRect& aRect ) override; + protected: - TOOL_MANAGER* m_toolManager; - std::map m_toolKinds; - std::map m_toolCancellable; - std::map m_toolActions; - std::map m_toolMenus; + TOOL_MANAGER* m_toolManager; + ACTION_TOOLBAR_PALETTE* m_palette; + + wxTimer* m_paletteTimer; + wxAuiManager* m_auiManager; + + std::map m_toolKinds; + std::map m_toolCancellable; + std::map m_toolActions; + std::map m_toolMenus; + + std::map m_actionGroups; }; #endif diff --git a/include/tool/tools_holder.h b/include/tool/tools_holder.h index 159a71c4ff..3431f54a83 100644 --- a/include/tool/tools_holder.h +++ b/include/tool/tools_holder.h @@ -86,6 +86,17 @@ public: */ virtual void RegisterUIUpdateHandler( const TOOL_ACTION& aAction, const ACTION_CONDITIONS& aConditions ) + { + RegisterUIUpdateHandler( aAction.GetUIId(), aConditions ); + } + + /** + * Register a UI update handler for the control with ID @c aID + * + * @param aID is the control ID to register the handler for + * @param aConditions are the UI conditions to use for the control states + */ + virtual void RegisterUIUpdateHandler( int aID, const ACTION_CONDITIONS& aConditions ) {} /** @@ -94,6 +105,16 @@ public: * @param aAction is the action to unregister the handler for */ virtual void UnregisterUIUpdateHandler( const TOOL_ACTION& aAction ) + { + UnregisterUIUpdateHandler( aAction.GetUIId() ); + } + + /** + * Unregister a UI handler for a given ID that was registered using @c RegisterUIUpdateHandler + * + * @param aID is the control ID to unregister the handler for + */ + virtual void UnregisterUIUpdateHandler( int aID ) {} /** diff --git a/kicad/menubar.cpp b/kicad/menubar.cpp index 0cd5295eef..1d6b5f3834 100644 --- a/kicad/menubar.cpp +++ b/kicad/menubar.cpp @@ -177,10 +177,15 @@ void KICAD_MANAGER_FRAME::ReCreateMenuBar() void KICAD_MANAGER_FRAME::RecreateBaseHToolbar() { if( m_mainToolBar ) + { m_mainToolBar->ClearToolbar(); + } else + { m_mainToolBar = new ACTION_TOOLBAR( this, ID_H_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT ); + m_mainToolBar->SetAuiManager( &m_auimgr ); + } // New m_mainToolBar->Add( KICAD_MANAGER_ACTIONS::newProject ); @@ -216,10 +221,15 @@ void KICAD_MANAGER_FRAME::RecreateBaseHToolbar() void KICAD_MANAGER_FRAME::RecreateLauncher() { if( m_launcher ) + { m_launcher->Clear(); + } else + { m_launcher = new ACTION_TOOLBAR( this, ID_H_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT ); + m_launcher->SetAuiManager( &m_auimgr ); + } // Add tools. Note these KICAD_MANAGER_ACTIONS are defined with a bitmap // suitable for menus. The icans will be changed later. diff --git a/pagelayout_editor/toolbars_pl_editor.cpp b/pagelayout_editor/toolbars_pl_editor.cpp index 3e3d872d0b..9441e46d3d 100644 --- a/pagelayout_editor/toolbars_pl_editor.cpp +++ b/pagelayout_editor/toolbars_pl_editor.cpp @@ -31,10 +31,15 @@ void PL_EDITOR_FRAME::ReCreateHToolbar() { if( m_mainToolBar ) + { m_mainToolBar->ClearToolbar(); + } else + { m_mainToolBar = new ACTION_TOOLBAR( this, ID_H_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT ); + m_mainToolBar->SetAuiManager( &m_auimgr ); + } wxString msg; @@ -111,10 +116,15 @@ void PL_EDITOR_FRAME::ReCreateHToolbar() void PL_EDITOR_FRAME::ReCreateVToolbar() { if( m_drawToolBar ) + { m_drawToolBar->ClearToolbar(); + } else + { m_drawToolBar = new ACTION_TOOLBAR( this, ID_V_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_VERTICAL ); + m_drawToolBar->SetAuiManager( &m_auimgr ); + } m_drawToolBar->Add( ACTIONS::selectionTool, ACTION_TOOLBAR::TOGGLE ); diff --git a/pcbnew/footprint_wizard_frame.cpp b/pcbnew/footprint_wizard_frame.cpp index 8928a151fc..a11a480a92 100644 --- a/pcbnew/footprint_wizard_frame.cpp +++ b/pcbnew/footprint_wizard_frame.cpp @@ -582,10 +582,15 @@ void FOOTPRINT_WIZARD_FRAME::Update3DView( bool aForceReload, const wxString* aT void FOOTPRINT_WIZARD_FRAME::ReCreateHToolbar() { if( m_mainToolBar ) + { m_mainToolBar->ClearToolbar(); + } else + { m_mainToolBar = new ACTION_TOOLBAR( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT ); + m_mainToolBar->SetAuiManager( &m_auimgr ); + } // Set up toolbar m_mainToolBar->AddTool( ID_FOOTPRINT_WIZARD_SELECT_WIZARD, wxEmptyString, diff --git a/pcbnew/pcb_edit_frame.cpp b/pcbnew/pcb_edit_frame.cpp index 8835762453..6af2368c20 100644 --- a/pcbnew/pcb_edit_frame.cpp +++ b/pcbnew/pcb_edit_frame.cpp @@ -217,6 +217,8 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) : GetScreen()->m_Center = false; setupTools(); + setupUIConditions(); + ReCreateMenuBar(); ReCreateHToolbar(); ReCreateAuxiliaryToolbar(); @@ -224,10 +226,6 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) : ReCreateOptToolbar(); ReCreateMicrowaveVToolbar(); - // We call this after the toolbars have been created to ensure the layer widget button handler - // doesn't cause problems - setupUIConditions(); - m_selectionFilterPanel = new PANEL_SELECTION_FILTER( this ); // Create the infobar @@ -700,16 +698,6 @@ void PCB_EDIT_FRAME::setupUIConditions() mgr->SetConditions( PCB_ACTIONS::zoneFill, ENABLE( SELECTION_CONDITIONS::MoreThan( 0 ) ) ); mgr->SetConditions( PCB_ACTIONS::zoneUnfill, ENABLE( SELECTION_CONDITIONS::MoreThan( 0 ) ) ); - // The layer indicator is special, so we register a callback directly that will regenerate the - // bitmap instead of using the conditions system - auto layerIndicatorUpdate = - [this] ( wxUpdateUIEvent& ) - { - PrepareLayerIndicator(); - }; - - Bind( wxEVT_UPDATE_UI, layerIndicatorUpdate, PCB_ACTIONS::selectLayerPair.GetUIId() ); - #define CURRENT_TOOL( action ) mgr->SetConditions( action, CHECK( cond.CurrentTool( action ) ) ) @@ -734,6 +722,7 @@ void PCB_EDIT_FRAME::setupUIConditions() CURRENT_EDIT_TOOL( ACTIONS::deleteTool ); CURRENT_EDIT_TOOL( PCB_ACTIONS::placeModule ); CURRENT_EDIT_TOOL( PCB_ACTIONS::routeSingleTrack); + CURRENT_EDIT_TOOL( PCB_ACTIONS::routeDiffPair); CURRENT_EDIT_TOOL( PCB_ACTIONS::drawVia ); CURRENT_EDIT_TOOL( PCB_ACTIONS::drawZone ); CURRENT_EDIT_TOOL( PCB_ACTIONS::drawRuleArea ); diff --git a/pcbnew/toolbars_footprint_editor.cpp b/pcbnew/toolbars_footprint_editor.cpp index 03cfcd8502..676fadd2f3 100644 --- a/pcbnew/toolbars_footprint_editor.cpp +++ b/pcbnew/toolbars_footprint_editor.cpp @@ -42,10 +42,15 @@ void FOOTPRINT_EDIT_FRAME::ReCreateHToolbar() // So we do not recreate them after clearing the tools. if( m_mainToolBar ) + { m_mainToolBar->ClearToolbar(); + } else + { m_mainToolBar = new ACTION_TOOLBAR( this, ID_H_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT ); + m_mainToolBar->SetAuiManager( &m_auimgr ); + } wxString msg; @@ -140,10 +145,15 @@ void FOOTPRINT_EDIT_FRAME::ReCreateHToolbar() void FOOTPRINT_EDIT_FRAME::ReCreateVToolbar() { if( m_drawToolBar ) + { m_drawToolBar->ClearToolbar(); + } else + { m_drawToolBar = new ACTION_TOOLBAR( this, ID_V_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_VERTICAL ); + m_drawToolBar->SetAuiManager( &m_auimgr ); + } m_drawToolBar->Add( ACTIONS::selectionTool, ACTION_TOOLBAR::TOGGLE ); @@ -170,10 +180,15 @@ void FOOTPRINT_EDIT_FRAME::ReCreateVToolbar() void FOOTPRINT_EDIT_FRAME::ReCreateOptToolbar() { if( m_optionsToolBar ) + { m_optionsToolBar->ClearToolbar(); + } else + { m_optionsToolBar = new ACTION_TOOLBAR( this, ID_OPT_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_VERTICAL ); + m_optionsToolBar->SetAuiManager( &m_auimgr ); + } m_optionsToolBar->Add( ACTIONS::toggleGrid, ACTION_TOOLBAR::TOGGLE ); m_optionsToolBar->Add( PCB_ACTIONS::togglePolarCoords, ACTION_TOOLBAR::TOGGLE ); diff --git a/pcbnew/toolbars_footprint_viewer.cpp b/pcbnew/toolbars_footprint_viewer.cpp index 1a873363ee..be900bf25e 100644 --- a/pcbnew/toolbars_footprint_viewer.cpp +++ b/pcbnew/toolbars_footprint_viewer.cpp @@ -43,10 +43,15 @@ void FOOTPRINT_VIEWER_FRAME::ReCreateHToolbar() // So we do not recreate them after clearing the tools. if( m_mainToolBar ) + { m_mainToolBar->ClearToolbar(); + } else + { m_mainToolBar = new ACTION_TOOLBAR( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT ); + m_mainToolBar->SetAuiManager( &m_auimgr ); + } // Set up toolbar m_mainToolBar->AddTool( ID_MODVIEW_PREVIOUS, wxEmptyString, @@ -99,10 +104,15 @@ void FOOTPRINT_VIEWER_FRAME::ReCreateHToolbar() void FOOTPRINT_VIEWER_FRAME::ReCreateOptToolbar() { if( m_optionsToolBar ) + { m_optionsToolBar->ClearToolbar(); + } else + { m_optionsToolBar = new ACTION_TOOLBAR( this, ID_OPT_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_VERTICAL ); + m_optionsToolBar->SetAuiManager( &m_auimgr ); + } m_optionsToolBar->Add( ACTIONS::selectionTool, ACTION_TOOLBAR::TOGGLE ); m_optionsToolBar->Add( ACTIONS::measureTool, ACTION_TOOLBAR::TOGGLE ); diff --git a/pcbnew/toolbars_pcb_editor.cpp b/pcbnew/toolbars_pcb_editor.cpp index 5fc29073f3..52bd2469bf 100644 --- a/pcbnew/toolbars_pcb_editor.cpp +++ b/pcbnew/toolbars_pcb_editor.cpp @@ -222,10 +222,25 @@ void PCB_EDIT_FRAME::ReCreateHToolbar() wxWindowUpdateLocker dummy( this ); if( m_mainToolBar ) + { m_mainToolBar->ClearToolbar(); + } else + { m_mainToolBar = new ACTION_TOOLBAR( this, ID_H_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT ); + m_mainToolBar->SetAuiManager( &m_auimgr ); + + // The layer indicator is special, so we register a callback directly that will regenerate the + // bitmap instead of using the conditions system + auto layerIndicatorUpdate = + [this] ( wxUpdateUIEvent& ) + { + PrepareLayerIndicator(); + }; + + Bind( wxEVT_UPDATE_UI, layerIndicatorUpdate, PCB_ACTIONS::selectLayerPair.GetUIId() ); + } // Set up toolbar if( Kiface().IsSingle() ) @@ -314,11 +329,16 @@ void PCB_EDIT_FRAME::ReCreateOptToolbar() wxWindowUpdateLocker dummy( this ); if( m_optionsToolBar ) + { m_optionsToolBar->ClearToolbar(); + } else + { m_optionsToolBar = new ACTION_TOOLBAR( this, ID_OPT_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_VERTICAL ); + m_optionsToolBar->SetAuiManager( &m_auimgr ); + } m_optionsToolBar->Add( ACTIONS::toggleGrid, ACTION_TOOLBAR::TOGGLE ); @@ -356,10 +376,43 @@ void PCB_EDIT_FRAME::ReCreateVToolbar() wxWindowUpdateLocker dummy( this ); if( m_drawToolBar ) + { m_drawToolBar->ClearToolbar(); + } else + { m_drawToolBar = new ACTION_TOOLBAR( this, ID_V_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_VERTICAL ); + m_drawToolBar->SetAuiManager( &m_auimgr ); + } + + // Groups contained on this toolbar + static ACTION_GROUP* dimensionGroup = nullptr; + static ACTION_GROUP* originGroup = nullptr; + static ACTION_GROUP* routingGroup = nullptr; + + if( !dimensionGroup ) + { + dimensionGroup = new ACTION_GROUP( "group.pcbDimensions", + { &PCB_ACTIONS::drawAlignedDimension, + &PCB_ACTIONS::drawOrthogonalDimension, + &PCB_ACTIONS::drawCenterDimension, + &PCB_ACTIONS::drawLeader } ); + } + + if( !originGroup ) + { + originGroup = new ACTION_GROUP( "group.pcbOrigins", + { &PCB_ACTIONS::drillOrigin, + &PCB_ACTIONS::gridSetOrigin } ); + } + + if( !routingGroup ) + { + routingGroup = new ACTION_GROUP( "group.pcbRouting", + { &PCB_ACTIONS::routeSingleTrack, + &PCB_ACTIONS::routeDiffPair } ); + } m_drawToolBar->Add( ACTIONS::selectionTool, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( PCB_ACTIONS::highlightNetTool, ACTION_TOOLBAR::TOGGLE ); @@ -367,7 +420,7 @@ void PCB_EDIT_FRAME::ReCreateVToolbar() m_drawToolBar->AddScaledSeparator( this ); m_drawToolBar->Add( PCB_ACTIONS::placeModule, ACTION_TOOLBAR::TOGGLE ); - m_drawToolBar->Add( PCB_ACTIONS::routeSingleTrack, ACTION_TOOLBAR::TOGGLE ); + m_drawToolBar->AddGroup( routingGroup, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( PCB_ACTIONS::drawVia, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( PCB_ACTIONS::drawZone, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( PCB_ACTIONS::drawRuleArea, ACTION_TOOLBAR::TOGGLE ); @@ -379,18 +432,12 @@ void PCB_EDIT_FRAME::ReCreateVToolbar() m_drawToolBar->Add( PCB_ACTIONS::drawArc, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( PCB_ACTIONS::drawPolygon, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( PCB_ACTIONS::placeText, ACTION_TOOLBAR::TOGGLE ); - m_drawToolBar->Add( PCB_ACTIONS::drawAlignedDimension, ACTION_TOOLBAR::TOGGLE ); - // TODO: re-insert when we have a multi-select tool button - // m_drawToolBar->Add( PCB_ACTIONS::drawOrthogonalDimension, ACTION_TOOLBAR::TOGGLE ); - // m_drawToolBar->Add( PCB_ACTIONS::drawCenterDimension, ACTION_TOOLBAR::TOGGLE ); - // m_drawToolBar->Add( PCB_ACTIONS::drawLeader, ACTION_TOOLBAR::TOGGLE ); + m_drawToolBar->AddGroup( dimensionGroup, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( PCB_ACTIONS::placeTarget, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( ACTIONS::deleteTool, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->AddScaledSeparator( this ); - // TODO: re-insert when we have a multi-select tool button - // m_drawToolBar->Add( PCB_ACTIONS::drillOrigin, ACTION_TOOLBAR::TOGGLE ); - m_drawToolBar->Add( PCB_ACTIONS::gridSetOrigin, ACTION_TOOLBAR::TOGGLE ); + m_drawToolBar->AddGroup( originGroup, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( ACTIONS::measureTool, ACTION_TOOLBAR::TOGGLE ); SELECTION_TOOL* selTool = m_toolManager->GetTool(); @@ -419,11 +466,16 @@ void PCB_EDIT_FRAME::ReCreateMicrowaveVToolbar() wxWindowUpdateLocker dummy(this); if( m_microWaveToolBar ) + { m_microWaveToolBar->ClearToolbar(); + } else + { m_microWaveToolBar = new ACTION_TOOLBAR( this, ID_MICROWAVE_V_TOOLBAR, wxDefaultPosition, wxDefaultSize, KICAD_AUI_TB_STYLE | wxAUI_TB_VERTICAL ); + m_microWaveToolBar->SetAuiManager( &m_auimgr ); + } // Set up toolbar m_microWaveToolBar->Add( PCB_ACTIONS::microwaveCreateLine, ACTION_TOOLBAR::TOGGLE );