UI Actions: Difference between revisions
(Explain some details in the example as a lead-up to the API section) |
No edit summary |
||
(11 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
<span id="ui-actions"></span> | |||
= UI Actions = | |||
== | <span id="introduction"></span> | ||
== Introduction == | |||
The UI actions are a way to trigger specific emulators actions from menu items, hotkeys or controller buttons without code duplication and letting VICE deal with issues like threading and avoiding showing multiple dialogs or retriggering actions that haven’t finished yet. | |||
UI actions are managed through an API living in <code>src/arch/shared/uiactions.h</code>. Actions are triggered by specifying action ID in menu items, or by using an action name in hotkey and joy map files (which VICE translates to IDs). | |||
The file <code>src/arch/shared/uiactions.h</code> contains the UI action IDs available, while the file <code>src/arch/shared/uiactions.c</code> contains a table mapping these IDs to action names. | |||
New actions can be created by adding a unqiue ID in the header file and an entry (with a unique name) in the aformentioned table in the source file. An ''action handler'' is required to implement the action’s logic, this handler is a callback function that gets passed some information about itself (the entry in the table, an <code>ui_action_map_t*</code>). The action will need to be registered with the UI actions system via <code>ui_actions_register()</code>. (See below) | |||
<span id="basic-api-usage"></span> | |||
== Basic API usage == | |||
The basic functions and types used by the UI actions are relatively simple. A selection of the most used functions and types is listed here. | |||
=== | <span id="general-functions-dealing-with-the-ui-actions-system-itself"></span> | ||
=== General functions dealing with the UI actions system itself: === | |||
<syntaxhighlight lang="c">void ui_actions_init (void); | |||
<syntaxhighlight lang="c" | void ui_actions_set_dispatch (void (*dispatch)(ui_action_map_t *)); | ||
void ui_actions_register (const ui_action_map_t *mappings); | |||
void ui_actions_shutdown (void);</syntaxhighlight> | |||
VICE will call <code>ui_actions_init()</code> and <code>ui_actions_shutdown()</code>, and calling <code>ui_actions_set_dispatch()</code> is optional. So the only function required to use is <code>ui_actions_register()</code>. | |||
/ | |||
The function <code>ui_actions_set_dispatch()</code> can be used to install a function that “intercepts” an action before it’s triggered by VICE, in which case the dispatch function is responsible for calling <code>ui_action_trigger(map->action)</code>. The dispatch function is used in the Gtk3 port to make sure an action that is marked as requiring the UI thread is executed on the UI thread. More on this later. | |||
/ | The '''<code>ui_action_map_t</code>''' type is used to register actions and to access information on an action. It maps action IDs to actions handlers and hotkeys. | ||
/* | <syntaxhighlight lang="c">typedef struct ui_action_map_s { | ||
int action; /**< action ID */ | |||
/** | /* | ||
* Action handler data | |||
*/ | |||
/** | void (*handler)(struct ui_action_map_s*); /**< function handling the action */ | ||
void *data; /**< optional user data */ | |||
/** | /* modes */ | ||
bool blocks; /**< action blocks (the same action cannot be | |||
triggered again until it finishes) */ | |||
bool dialog; /**< action pops up a dialog (only one dialog action | |||
is allowed at a time), this implies using the | |||
UI thread */ | |||
bool uithread; /**< must run on the UI thread */ | |||
/* state */ | |||
bool is_busy; /**< action is busy */ | |||
</ | |||
/* Hotkey data left out */ | |||
} ui_action_map_t;</syntaxhighlight> | |||
/* | The “Hotkey data” can be ignored: UI actions and hotkeys are closely related, and VICE uses the same struct to store hotkey data. | ||
In its simplest form an initialization of the map requires providing values for <code>.action</code> and <code>.handler</code>. When providing initializers for UI action maps please use C99 designated initializers: this looks a lot cleaner and allows for adding members to the UI action map type without causing compiler warnings with existing code. | |||
</ | |||
<span id="simple-example-of-an-action-handler"></span> | |||
< | ==== Simple example of an action handler ==== | ||
/ | |||
/* | <syntaxhighlight lang="c">/* Action handler for toggling warp mode */ | ||
static void warp_mode_toggle_action(ui_action_map_t *self) | |||
static void | |||
{ | { | ||
vsync_set_warp_mode(!vsync_get_warp_mode()); | |||
} | } | ||
/* | /* List of actions to register (just one here) */ | ||
static const ui_action_map_t some_actions[] = { | |||
{ .action = ACTION_WARP_MODE_TOGGLE, | |||
.handler = warp_mode_toggle_action | |||
}, | |||
UI_ACTION_MAP_TERMINATOR /* macro used to terminate a list of actions */ | |||
}; | |||
/* Register | /* Register the action: */ | ||
ui_actions_register( | ui_actions_register(some_actions);</syntaxhighlight> | ||
</ | Here we have a single action handler to toggle warp mode, in this case it does not use its ''self'' argument, but the argument can be used to access, for example, the action’s<code>.id</code> member or the <code>.data</code> member to be able to write an action handler that can be used for multiple IDs. | ||
We register the action with a call to <code>ui_actions_register()</code>, after which VICE will call <code>warp_mode_toggle_action()</code> when a menu item, hotkey or controller button is used that is mapped to <code>ACTION_WARP_MODE_TOGGLE</code>. | |||
<span id="functions-dealing-with-individual-actions"></span> | |||
=== Functions dealing with individual actions: === | |||
= | <syntaxhighlight lang="c">void ui_action_trigger (int action); | ||
void ui_action_finish (int action); | |||
int ui_action_get_id (const char *name); | |||
const char *ui_action_get_name (int action); | |||
const char *ui_action_get_desc (int action); | |||
char * ui_action_get_hotkey_label(int action);</syntaxhighlight> |
Latest revision as of 08:20, 2 October 2023
UI Actions
Introduction
The UI actions are a way to trigger specific emulators actions from menu items, hotkeys or controller buttons without code duplication and letting VICE deal with issues like threading and avoiding showing multiple dialogs or retriggering actions that haven’t finished yet.
UI actions are managed through an API living in src/arch/shared/uiactions.h
. Actions are triggered by specifying action ID in menu items, or by using an action name in hotkey and joy map files (which VICE translates to IDs).
The file src/arch/shared/uiactions.h
contains the UI action IDs available, while the file src/arch/shared/uiactions.c
contains a table mapping these IDs to action names.
New actions can be created by adding a unqiue ID in the header file and an entry (with a unique name) in the aformentioned table in the source file. An action handler is required to implement the action’s logic, this handler is a callback function that gets passed some information about itself (the entry in the table, an ui_action_map_t*
). The action will need to be registered with the UI actions system via ui_actions_register()
. (See below)
Basic API usage
The basic functions and types used by the UI actions are relatively simple. A selection of the most used functions and types is listed here.
General functions dealing with the UI actions system itself:
void ui_actions_init (void);
void ui_actions_set_dispatch (void (*dispatch)(ui_action_map_t *));
void ui_actions_register (const ui_action_map_t *mappings);
void ui_actions_shutdown (void);
VICE will call ui_actions_init()
and ui_actions_shutdown()
, and calling ui_actions_set_dispatch()
is optional. So the only function required to use is ui_actions_register()
.
The function ui_actions_set_dispatch()
can be used to install a function that “intercepts” an action before it’s triggered by VICE, in which case the dispatch function is responsible for calling ui_action_trigger(map->action)
. The dispatch function is used in the Gtk3 port to make sure an action that is marked as requiring the UI thread is executed on the UI thread. More on this later.
The ui_action_map_t
type is used to register actions and to access information on an action. It maps action IDs to actions handlers and hotkeys.
typedef struct ui_action_map_s {
int action; /**< action ID */
/*
* Action handler data
*/
void (*handler)(struct ui_action_map_s*); /**< function handling the action */
void *data; /**< optional user data */
/* modes */
bool blocks; /**< action blocks (the same action cannot be
triggered again until it finishes) */
bool dialog; /**< action pops up a dialog (only one dialog action
is allowed at a time), this implies using the
UI thread */
bool uithread; /**< must run on the UI thread */
/* state */
bool is_busy; /**< action is busy */
/* Hotkey data left out */
} ui_action_map_t;
The “Hotkey data” can be ignored: UI actions and hotkeys are closely related, and VICE uses the same struct to store hotkey data.
In its simplest form an initialization of the map requires providing values for .action
and .handler
. When providing initializers for UI action maps please use C99 designated initializers: this looks a lot cleaner and allows for adding members to the UI action map type without causing compiler warnings with existing code.
Simple example of an action handler
/* Action handler for toggling warp mode */
static void warp_mode_toggle_action(ui_action_map_t *self)
{
vsync_set_warp_mode(!vsync_get_warp_mode());
}
/* List of actions to register (just one here) */
static const ui_action_map_t some_actions[] = {
{ .action = ACTION_WARP_MODE_TOGGLE,
.handler = warp_mode_toggle_action
},
UI_ACTION_MAP_TERMINATOR /* macro used to terminate a list of actions */
};
/* Register the action: */
ui_actions_register(some_actions);
Here we have a single action handler to toggle warp mode, in this case it does not use its self argument, but the argument can be used to access, for example, the action’s.id
member or the .data
member to be able to write an action handler that can be used for multiple IDs.
We register the action with a call to ui_actions_register()
, after which VICE will call warp_mode_toggle_action()
when a menu item, hotkey or controller button is used that is mapped to ACTION_WARP_MODE_TOGGLE
.
Functions dealing with individual actions:
void ui_action_trigger (int action);
void ui_action_finish (int action);
int ui_action_get_id (const char *name);
const char *ui_action_get_name (int action);
const char *ui_action_get_desc (int action);
char * ui_action_get_hotkey_label(int action);