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() );
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
{
return m_actionNameIndex;

View File

@ -476,15 +476,9 @@ void ACTION_MENU::OnMenuEvent( wxMenuEvent& aEvent )
parent = dynamic_cast<ACTION_MENU*>( 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 )
{

View File

@ -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,

View File

@ -22,6 +22,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <optional>
#include <tool/tool_action.h>
#include <tool/tool_event.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_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 );
}

View File

@ -113,6 +113,11 @@ public:
*/
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).
*
@ -184,6 +189,9 @@ private:
///< Map for indexing actions by their names
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
typedef std::map<int, std::list<TOOL_ACTION*> > HOTKEY_LIST;
HOTKEY_LIST m_actionHotKeys;

View File

@ -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<TOOL_ACTION_SCOPE> m_scope;
std::optional<TOOL_ACTION_FLAGS> m_flags;
std::optional<int> m_uiid;
std::optional<int> m_defaultHotKey;
std::optional<std::string> 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<int> m_uiid; // ID to use when interacting with the UI (if empty, generate one)
TOOL_ACTION_FLAGS m_flags;
void* m_param; // Generic parameter