diff --git a/common/tool/action_manager.cpp b/common/tool/action_manager.cpp index 6d164d21d8..22b6c76684 100644 --- a/common/tool/action_manager.cpp +++ b/common/tool/action_manager.cpp @@ -68,6 +68,9 @@ void ACTION_MANAGER::RegisterAction( TOOL_ACTION* aAction ) wxASSERT( m_actionNameIndex.find( aAction->m_name ) == m_actionNameIndex.end() ); m_actionNameIndex[aAction->m_name] = aAction; + + if( aAction->HasCustomUIId() ) + m_customUIIdIndex[aAction->GetUIId()] = aAction; } @@ -232,6 +235,19 @@ bool ACTION_MANAGER::RunHotKey( int aHotKey ) const } +bool ACTION_MANAGER::IsActionUIId( int aId ) const +{ + // Automatically assigned IDs are always in this range + if( aId >= TOOL_ACTION::GetBaseUIId() ) + return true; + + // Search the custom assigned UI IDs + auto it = m_customUIIdIndex.find( aId ); + + return ( it != m_customUIIdIndex.end() ); +} + + const std::map& ACTION_MANAGER::GetActions() const { return m_actionNameIndex; diff --git a/common/tool/action_menu.cpp b/common/tool/action_menu.cpp index bfdf2344ce..de60c3a360 100644 --- a/common/tool/action_menu.cpp +++ b/common/tool/action_menu.cpp @@ -476,15 +476,9 @@ void ACTION_MENU::OnMenuEvent( wxMenuEvent& aEvent ) parent = dynamic_cast( parent->GetParent() ); } - // Check if there is a TOOL_ACTION for the given ID - // Note that we also have to check the standard wxWidgets' cut/copy/paste IDs because - // we can't use our own IDs there without losing cut/copy/paste in places like search - // boxes in standard file dialogs. - if( m_selected == wxID_CUT || m_selected == wxID_COPY || m_selected == wxID_PASTE - || m_selected >= TOOL_ACTION::GetBaseUIId() ) - { + // Check if there is a TOOL_ACTION for the given UI ID + if( getToolManager()->GetActionManager()->IsActionUIId( m_selected ) ) evt = findToolAction( m_selected ); - } if( !evt ) { diff --git a/common/tool/actions.cpp b/common/tool/actions.cpp index dd707d6744..f2ec2d07b8 100644 --- a/common/tool/actions.cpp +++ b/common/tool/actions.cpp @@ -147,25 +147,42 @@ TOOL_ACTION ACTIONS::redo( "common.Interactive.redo", _( "Redo" ), _( "Redo last edit" ), BITMAPS::redo ); -TOOL_ACTION ACTIONS::cut( "common.Interactive.cut", - AS_GLOBAL, - MD_CTRL + 'X', LEGACY_HK_NAME( "Cut" ), - _( "Cut" ), _( "Cut selected item(s) to clipboard" ), - BITMAPS::cut, AF_NONE, (void*) wxID_CUT ); +// The following actions need to have a hard-coded UI ID using a wx-specific ID +// to fix things like search controls in standard file dialogs. If wxWidgets +// doesn't find these specific IDs somewhere in the menus then it won't enable +// cut/copy/paste. +TOOL_ACTION ACTIONS::cut( TOOL_ACTION_ARGS() + .Name( "common.Interactive.cut" ) + .Scope( AS_GLOBAL ) + .DefaultHotkey( MD_CTRL + 'X' ) + .LegacyHotkeyName( "Cut" ) + .MenuText( _( "Cut" ) ) + .Tooltip( _( "Cut selected item(s) to clipboard" ) ) + .Icon( BITMAPS::cut ) + .Flags( AF_NONE ) + .UIId( wxID_CUT ) ); -TOOL_ACTION ACTIONS::copy( "common.Interactive.copy", - AS_GLOBAL, - MD_CTRL + 'C', LEGACY_HK_NAME( "Copy" ), - _( "Copy" ), _( "Copy selected item(s) to clipboard" ), - BITMAPS::copy, AF_NONE, (void*) wxID_COPY ); +TOOL_ACTION ACTIONS::copy( TOOL_ACTION_ARGS() + .Name( "common.Interactive.copy" ) + .Scope( AS_GLOBAL ) + .DefaultHotkey( MD_CTRL + 'C' ) + .LegacyHotkeyName( "Copy" ) + .MenuText( _( "Copy" ) ) + .Tooltip( _( "Copy selected item(s) to clipboard" ) ) + .Icon( BITMAPS::copy ) + .Flags( AF_NONE ) + .UIId( wxID_COPY ) ); -// This action is also used for a tool in the main horizontal toolbar in schematic editor -// do not specify a wxID like wxID_PASTE, it prevent the tool working (at least on Windows) -TOOL_ACTION ACTIONS::paste( "common.Interactive.paste", - AS_GLOBAL, - MD_CTRL + 'V', LEGACY_HK_NAME( "Paste" ), - _( "Paste" ), _( "Paste item(s) from clipboard" ), - BITMAPS::paste, AF_NONE /*, (void*) wxID_PASTE*/ ); +TOOL_ACTION ACTIONS::paste( TOOL_ACTION_ARGS() + .Name( "common.Interactive.paste" ) + .Scope( AS_GLOBAL ) + .DefaultHotkey( MD_CTRL + 'V' ) + .LegacyHotkeyName( "Paste" ) + .MenuText( _( "Paste" ) ) + .Tooltip( _( "Paste item(s) from clipboard" ) ) + .Icon( BITMAPS::paste ) + .Flags( AF_NONE ) + .UIId( wxID_PASTE ) ); TOOL_ACTION ACTIONS::selectAll( "common.Interactive.selectAll", AS_GLOBAL, diff --git a/common/tool/tool_action.cpp b/common/tool/tool_action.cpp index 8e87e33a7f..294c2c8006 100644 --- a/common/tool/tool_action.cpp +++ b/common/tool/tool_action.cpp @@ -22,6 +22,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#include #include #include #include @@ -74,12 +75,16 @@ TOOL_ACTION::TOOL_ACTION( const TOOL_ACTION_ARGS& aArgs ) : m_tooltip( aArgs.m_tooltip.value_or( wxEmptyString ) ), m_icon( aArgs.m_icon.value_or( BITMAPS::INVALID_BITMAP) ), m_id( -1 ), + m_uiid( std::nullopt ), m_flags( aArgs.m_flags.value_or( AF_NONE ) ), m_param( aArgs.m_param.value_or( nullptr ) ) { // Action name is the only mandatory part assert( !m_name.empty() ); + if( aArgs.m_uiid.has_value() ) + m_uiid = aArgs.m_uiid.value(); + ACTION_MANAGER::GetActionList().push_back( this ); } diff --git a/include/tool/action_manager.h b/include/tool/action_manager.h index 9c22e91569..98f98e446f 100644 --- a/include/tool/action_manager.h +++ b/include/tool/action_manager.h @@ -113,6 +113,11 @@ public: */ const std::map& GetActions() const; + /** + * Test if a UI ID corresponds to an action ID in our system. + */ + bool IsActionUIId( int aId ) const; + /** * Find an action with a given name (if there is one available). * @@ -184,6 +189,9 @@ private: ///< Map for indexing actions by their names std::map m_actionNameIndex; + ///< Map for recording actions that have custom UI IDs + std::map m_customUIIdIndex; + ///< Map for indexing actions by their hotkeys typedef std::map > HOTKEY_LIST; HOTKEY_LIST m_actionHotKeys; diff --git a/include/tool/tool_action.h b/include/tool/tool_action.h index ce1a3c347a..1a32aa43c0 100644 --- a/include/tool/tool_action.h +++ b/include/tool/tool_action.h @@ -148,6 +148,15 @@ public: return *this; } + /** + * The ID number to use for the action when interacting with any UI elements. + */ + TOOL_ACTION_ARGS& UIId( int aUIId ) + { + m_uiid = aUIId; + return *this; + } + protected: // Let the TOOL_ACTION constructor have direct access to the members here friend class TOOL_ACTION; @@ -156,6 +165,8 @@ protected: std::optional m_scope; std::optional m_flags; + std::optional m_uiid; + std::optional m_defaultHotKey; std::optional m_legacyName; @@ -235,27 +246,20 @@ public: */ int GetId() const { return m_id; } + /** + * Return true if this action has a custom UI ID set. + */ + bool HasCustomUIId() const { return m_uiid.has_value(); } + /* * Get the unique ID for this action in the user interface system. * - * This is simply the action ID offset by @c ACTION_BASE_UI_ID. + * This can be either set to a specific ID during creation or computed + * by offsetting the action ID by @c ACTION_BASE_UI_ID. * * @return The unique ID number for use in the user interface system. */ - int GetUIId() const - { - // Hack for wxWidgets' use in stuff like search controls in standard file dialogs. If - // it doesn't find these specific IDs somewhere in the menus then it won't enable - // cut/copy/paste. - if( m_param == (void*) wxID_CUT ) - return wxID_CUT; - else if( m_param == (void*) wxID_COPY ) - return wxID_COPY; - else if( m_param == (void*) wxID_PASTE ) - return wxID_PASTE; - - return m_id + ACTION_BASE_UI_ID; - } + int GetUIId() const { return m_uiid.value_or( m_id + ACTION_BASE_UI_ID ); } /* * Get the base value used to offset the user interface IDs for the actions. @@ -330,6 +334,7 @@ protected: BITMAPS m_icon; // Icon for the menu entry int m_id; // Unique ID for maps. Assigned by ACTION_MANAGER. + std::optional m_uiid; // ID to use when interacting with the UI (if empty, generate one) TOOL_ACTION_FLAGS m_flags; void* m_param; // Generic parameter