Add custom UI IDs to the action framework

This replaces a hack where the parameter was used to identify a custom
UI ID with a proper solution. This moves the cut/copy/paste actions to
the new system, but more like help/quit/close should also be moved over
in the future.
This commit is contained in:
Ian McInerney 2022-09-27 22:03:58 +01:00
parent d0d0be196b
commit 0a22bb951c
6 changed files with 85 additions and 40 deletions

View File

@ -68,6 +68,9 @@ void ACTION_MANAGER::RegisterAction( TOOL_ACTION* aAction )
wxASSERT( m_actionNameIndex.find( aAction->m_name ) == m_actionNameIndex.end() ); wxASSERT( m_actionNameIndex.find( aAction->m_name ) == m_actionNameIndex.end() );
m_actionNameIndex[aAction->m_name] = aAction; 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<std::string, TOOL_ACTION*>& ACTION_MANAGER::GetActions() const const std::map<std::string, TOOL_ACTION*>& ACTION_MANAGER::GetActions() const
{ {
return m_actionNameIndex; return m_actionNameIndex;

View File

@ -476,15 +476,9 @@ void ACTION_MENU::OnMenuEvent( wxMenuEvent& aEvent )
parent = dynamic_cast<ACTION_MENU*>( parent->GetParent() ); parent = dynamic_cast<ACTION_MENU*>( parent->GetParent() );
} }
// Check if there is a TOOL_ACTION for the given ID // Check if there is a TOOL_ACTION for the given UI ID
// Note that we also have to check the standard wxWidgets' cut/copy/paste IDs because if( getToolManager()->GetActionManager()->IsActionUIId( m_selected ) )
// 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() )
{
evt = findToolAction( m_selected ); evt = findToolAction( m_selected );
}
if( !evt ) if( !evt )
{ {

View File

@ -147,25 +147,42 @@ TOOL_ACTION ACTIONS::redo( "common.Interactive.redo",
_( "Redo" ), _( "Redo last edit" ), _( "Redo" ), _( "Redo last edit" ),
BITMAPS::redo ); BITMAPS::redo );
TOOL_ACTION ACTIONS::cut( "common.Interactive.cut", // The following actions need to have a hard-coded UI ID using a wx-specific ID
AS_GLOBAL, // to fix things like search controls in standard file dialogs. If wxWidgets
MD_CTRL + 'X', LEGACY_HK_NAME( "Cut" ), // doesn't find these specific IDs somewhere in the menus then it won't enable
_( "Cut" ), _( "Cut selected item(s) to clipboard" ), // cut/copy/paste.
BITMAPS::cut, AF_NONE, (void*) wxID_CUT ); 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", TOOL_ACTION ACTIONS::copy( TOOL_ACTION_ARGS()
AS_GLOBAL, .Name( "common.Interactive.copy" )
MD_CTRL + 'C', LEGACY_HK_NAME( "Copy" ), .Scope( AS_GLOBAL )
_( "Copy" ), _( "Copy selected item(s) to clipboard" ), .DefaultHotkey( MD_CTRL + 'C' )
BITMAPS::copy, AF_NONE, (void*) wxID_COPY ); .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 TOOL_ACTION ACTIONS::paste( TOOL_ACTION_ARGS()
// do not specify a wxID like wxID_PASTE, it prevent the tool working (at least on Windows) .Name( "common.Interactive.paste" )
TOOL_ACTION ACTIONS::paste( "common.Interactive.paste", .Scope( AS_GLOBAL )
AS_GLOBAL, .DefaultHotkey( MD_CTRL + 'V' )
MD_CTRL + 'V', LEGACY_HK_NAME( "Paste" ), .LegacyHotkeyName( "Paste" )
_( "Paste" ), _( "Paste item(s) from clipboard" ), .MenuText( _( "Paste" ) )
BITMAPS::paste, AF_NONE /*, (void*) wxID_PASTE*/ ); .Tooltip( _( "Paste item(s) from clipboard" ) )
.Icon( BITMAPS::paste )
.Flags( AF_NONE )
.UIId( wxID_PASTE ) );
TOOL_ACTION ACTIONS::selectAll( "common.Interactive.selectAll", TOOL_ACTION ACTIONS::selectAll( "common.Interactive.selectAll",
AS_GLOBAL, AS_GLOBAL,

View File

@ -22,6 +22,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include <optional>
#include <tool/tool_action.h> #include <tool/tool_action.h>
#include <tool/tool_event.h> #include <tool/tool_event.h>
#include <tool/action_manager.h> #include <tool/action_manager.h>
@ -74,12 +75,16 @@ TOOL_ACTION::TOOL_ACTION( const TOOL_ACTION_ARGS& aArgs ) :
m_tooltip( aArgs.m_tooltip.value_or( wxEmptyString ) ), m_tooltip( aArgs.m_tooltip.value_or( wxEmptyString ) ),
m_icon( aArgs.m_icon.value_or( BITMAPS::INVALID_BITMAP) ), m_icon( aArgs.m_icon.value_or( BITMAPS::INVALID_BITMAP) ),
m_id( -1 ), m_id( -1 ),
m_uiid( std::nullopt ),
m_flags( aArgs.m_flags.value_or( AF_NONE ) ), m_flags( aArgs.m_flags.value_or( AF_NONE ) ),
m_param( aArgs.m_param.value_or( nullptr ) ) m_param( aArgs.m_param.value_or( nullptr ) )
{ {
// Action name is the only mandatory part // Action name is the only mandatory part
assert( !m_name.empty() ); assert( !m_name.empty() );
if( aArgs.m_uiid.has_value() )
m_uiid = aArgs.m_uiid.value();
ACTION_MANAGER::GetActionList().push_back( this ); ACTION_MANAGER::GetActionList().push_back( this );
} }

View File

@ -113,6 +113,11 @@ public:
*/ */
const std::map<std::string, TOOL_ACTION*>& GetActions() const; const std::map<std::string, TOOL_ACTION*>& 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). * Find an action with a given name (if there is one available).
* *
@ -184,6 +189,9 @@ private:
///< Map for indexing actions by their names ///< Map for indexing actions by their names
std::map<std::string, TOOL_ACTION*> m_actionNameIndex; std::map<std::string, TOOL_ACTION*> m_actionNameIndex;
///< Map for recording actions that have custom UI IDs
std::map<int, TOOL_ACTION*> m_customUIIdIndex;
///< Map for indexing actions by their hotkeys ///< Map for indexing actions by their hotkeys
typedef std::map<int, std::list<TOOL_ACTION*> > HOTKEY_LIST; typedef std::map<int, std::list<TOOL_ACTION*> > HOTKEY_LIST;
HOTKEY_LIST m_actionHotKeys; HOTKEY_LIST m_actionHotKeys;

View File

@ -148,6 +148,15 @@ public:
return *this; 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: protected:
// Let the TOOL_ACTION constructor have direct access to the members here // Let the TOOL_ACTION constructor have direct access to the members here
friend class TOOL_ACTION; friend class TOOL_ACTION;
@ -156,6 +165,8 @@ protected:
std::optional<TOOL_ACTION_SCOPE> m_scope; std::optional<TOOL_ACTION_SCOPE> m_scope;
std::optional<TOOL_ACTION_FLAGS> m_flags; std::optional<TOOL_ACTION_FLAGS> m_flags;
std::optional<int> m_uiid;
std::optional<int> m_defaultHotKey; std::optional<int> m_defaultHotKey;
std::optional<std::string> m_legacyName; std::optional<std::string> m_legacyName;
@ -235,27 +246,20 @@ public:
*/ */
int GetId() const { return m_id; } 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. * 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. * @return The unique ID number for use in the user interface system.
*/ */
int GetUIId() const int GetUIId() const { return m_uiid.value_or( m_id + ACTION_BASE_UI_ID ); }
{
// 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;
}
/* /*
* Get the base value used to offset the user interface IDs for the actions. * 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 BITMAPS m_icon; // Icon for the menu entry
int m_id; // Unique ID for maps. Assigned by ACTION_MANAGER. int m_id; // Unique ID for maps. Assigned by ACTION_MANAGER.
std::optional<int> m_uiid; // ID to use when interacting with the UI (if empty, generate one)
TOOL_ACTION_FLAGS m_flags; TOOL_ACTION_FLAGS m_flags;
void* m_param; // Generic parameter void* m_param; // Generic parameter