UI Input
The UI framework routes key presses through shared
Action objects. An action owns
trigger keys, enablement rules, and the callback that runs when the
action is accepted. Its user-facing name, detailed description,
visibility, and display priority live in
HelpData, which you access
through action->help().
Actions are attached to surfaces and pages through
Surface::actions().
The same ActionPtr can be attached to many surfaces, so application
commands such as quit, save, or toggle-help can be implemented once and
reused wherever they make sense.
Button surfaces use ButtonAction instead. A ButtonAction is owned
by one live button and synchronizes its enabled state into that button’s
SurfaceFlags. Create a separate ButtonAction for each button,
even when several buttons call the same callback.
Important
The UI Framework is currently in beta, and parts of the API may change in future releases.
Usage
Focused Dispatch
The active page is the keyboard boundary. It sends a key press to the focused surface first, then each parent surface, and finally to the page itself. This gives focused controls the first chance to interpret keys without letting a transparent page accidentally leak input into the page below it.
auto saveAction = ui::Action::create("save");
saveAction->addKey(U's');
saveAction->setEnabledFn(
[document] { return document->hasUnsavedChanges(); },
ui::Action::EnabledUpdateMode::BeforeRepaint);
saveAction->setTriggerFn([document] {
document->save();
});
editorPage->actions().add(quitAction);
editorPage->actions().add(saveAction);
detailsPanel->actions().add(saveAction);
The enabled callback is always refreshed immediately before triggering, even when the regular update mode is repaint-driven or polled. This avoids stale enabled state when data changes between two paint passes.
Main and Alternative Keys
Use Keys when an action has several
accepted keys. The keys are stored once, in priority order. By default
all keys are shown in compact footer help. When some bindings are only
alternatives for detailed help, set the number of leading main keys.
auto zoomKeys = Keys{U'+', U']'};
zoomKeys.setMainKeyCount(1);
auto zoomInAction = ui::Action::create("zoom in");
zoomInAction->setKeys(zoomKeys);
The action still accepts both + and ]. The footer displays only
[+] zoom in while a future detailed help view can show the
alternative too.
Capturing Text Input
Text-entry controls should override onKeyPress() and mark ordinary
text keys as handled. Page actions such as quit then do not run
while the focused control is editing text.
void SearchField::onKeyPress(ui::KeyPressEvent &event) noexcept {
if (event.key() == Key::Enter) {
submit();
event.setHandled();
return;
}
if (event.key() == Key::Escape) {
cancel();
event.setHandled();
return;
}
if (event.key().type() == Key::Character || event.key().type() == Key::Combined) {
insertText(event.key().combined());
event.setHandled();
return;
}
Surface::onKeyPress(event);
}
Multi-Key Actions
When several keys perform related work, use one action and branch on the trigger key in the callback. This keeps dispatch simple and keeps the footer help focused on the one command the reader can perform.
auto panAction = ui::Action::create("pan");
panAction->setKeys({Key::Left, Key::Up, Key::Down, Key::Right});
panAction->setTriggerFn([view](const ui::ActionTriggerContext &context) {
switch (context.key().type()) {
case Key::Left:
view->panLeft();
break;
case Key::Right:
view->panRight();
break;
case Key::Up:
view->panUp();
break;
case Key::Down:
view->panDown();
break;
default:
break;
}
});
mapPage->actions().add(panAction);
Reference
-
class Action
A shared user-interface action with key triggers, help metadata, and enablement state.
Subclassed by erbsland::cterm::ui::ButtonAction
Public Types
-
enum class EnabledUpdateMode : uint8_t
When a callback-backed enabled state is refreshed automatically.
Values:
-
enumerator Manual
Only update when explicitly requested or before triggering.
-
enumerator BeforeTriggered
Update before key/manual triggering.
-
enumerator BeforeRepaint
Update before repaint-driven action help collection.
-
enumerator Polled100ms
Update at most every 100ms when action help is refreshed.
-
enumerator Manual
-
enum class EnabledRefreshReason : uint8_t
Why the enabled callback is being refreshed.
Values:
-
enumerator Manual
Explicit refresh.
-
enumerator BeforeTriggered
A trigger is about to be attempted.
-
enumerator BeforeRepaint
A repaint is about to display the action.
-
enumerator Polled100ms
The 100ms polling interval elapsed.
-
enumerator Manual
-
using EnabledFn = std::function<bool()>
Callback used to update the enabled state.
-
using TriggerFn = std::function<void(const ActionTriggerContext&)>
Callback invoked when the action is triggered.
-
using SimpleTriggerFn = std::function<void()>
Simple callback invoked when the action is triggered.
Public Functions
-
explicit Action(std::string name)
Create an action with a short help name.
- Parameters:
name – The short action name used in generated help.
-
inline bool isEnabled() const noexcept
Test if this action is currently enabled.
-
void setEnabled(bool enabled) noexcept
Manually set the enabled state.
- Parameters:
enabled – The new enabled state.
-
void setEnabledFn(EnabledFn enabledFn, EnabledUpdateMode updateMode = EnabledUpdateMode::BeforeTriggered)
Replace the enabled callback and update mode.
- Parameters:
enabledFn – The callback that returns the current enabled state.
updateMode – The automatic update mode for the callback.
-
void clearEnabledFn() noexcept
Remove the enabled callback and return to manual enabled state.
-
inline EnabledUpdateMode enabledUpdateMode() const noexcept
Get the enabled update mode.
-
void setEnabledUpdateMode(EnabledUpdateMode updateMode) noexcept
Replace the enabled update mode.
- Parameters:
updateMode – The new update mode.
-
void setTriggerFn(TriggerFn triggerFn)
Replace the trigger callback.
- Parameters:
triggerFn – The new callback.
-
void setTriggerFn(SimpleTriggerFn triggerFn)
Replace the trigger callback with a simple no-argument callback.
- Parameters:
triggerFn – The new callback.
-
void clearTriggerFn() noexcept
Remove the trigger callback.
-
bool matchesKey(const Key &key) const noexcept
Test if the action is triggered by a key.
- Parameters:
key – The key to test.
- Returns:
trueif the key is assigned to the action.
-
bool refreshEnabled(EnabledRefreshReason reason)
Refresh the enabled state if the callback and update mode require it.
- Parameters:
reason – The reason for the refresh.
- Returns:
trueif the enabled callback was evaluated.
-
bool trigger(const ActionTriggerContext &context)
Trigger this action manually.
The enabled callback is always evaluated before triggering when present.
- Parameters:
context – The trigger context.
- Returns:
trueif the action was enabled and was accepted as triggered.
Public Static Functions
-
static ActionPtr create(std::string name)
Create an action with a short help name.
- Parameters:
name – The short action name used in generated help.
- Returns:
The new action.
-
enum class EnabledUpdateMode : uint8_t
-
class ButtonAction : public erbsland::cterm::ui::Action
An action that is owned by one button surface and synchronizes its enabled state.
Public Functions
-
explicit ButtonAction(std::string name)
Create a button action with a short help name.
- Parameters:
name – The short action name used in generated help.
Public Static Functions
-
static ButtonActionPtr create(std::string name)
Create a button action with a short help name.
- Parameters:
name – The short action name used in generated help.
- Returns:
The new button action.
-
explicit ButtonAction(std::string name)
-
class HelpData
Display metadata for a user-interface action.
Public Functions
-
HelpData() = default
Create empty help data.
-
explicit HelpData(std::string name)
Create help data with a short display name.
- Parameters:
name – The short display name.
-
inline const std::string &name() const noexcept
Get the short display name.
-
HelpData &setName(std::string name)
Set the short display name.
- Parameters:
name – The short display name.
- Returns:
This object.
-
inline const std::string &description() const noexcept
Get the detailed help description.
-
inline HelpFormat descriptionFormat() const noexcept
Get the format of the detailed help description.
-
HelpData &setDescription(std::string description, HelpFormat format = HelpFormat::Text)
Set the detailed help description.
- Parameters:
description – The detailed help description.
format – The format of the detailed help description.
- Returns:
This object.
-
inline int priority() const noexcept
Get the display priority.
-
HelpData &setPriority(int priority) noexcept
Set the display priority.
- Parameters:
priority – The display priority; larger values are displayed first.
- Returns:
This object.
-
inline HelpVisibility visibility() const noexcept
Get the help visibility.
-
HelpData &setVisibility(HelpVisibility visibility) noexcept
Set the help visibility.
- Parameters:
visibility – The help visibility.
- Returns:
This object.
Test if this metadata shall be shown in compact footer help.
-
bool isVisibleOnHelpPage() const noexcept
Test if this metadata shall be shown in detailed help.
-
HelpData() = default
-
enum class erbsland::cterm::ui::HelpVisibility : uint8_t
Visibility of action help metadata.
Values:
-
enumerator Hidden
Hide this action from generated help.
Show this action only in compact footer help.
-
enumerator HelpPage
Show this action only in detailed help.
-
enumerator All
Show this action in compact footer help and detailed help.
-
enumerator Hidden
-
class Actions
Ordered action container attached to a surface or page.
Public Functions
-
explicit Actions(SurfaceWeakPtr owner) noexcept
Create an action container for a surface.
- Parameters:
owner – The surface that owns this container.
-
void add(ActionPtr action)
Add an action to this container.
- Parameters:
action – The action to attach.
- Throws:
std::invalid_argument – If the action is null or already attached here.
-
void remove(const ActionPtr &action) noexcept
Remove an action from this container.
- Parameters:
action – The action to remove.
-
void clear() noexcept
Remove all actions.
-
inline bool empty() const noexcept
Test if this container has no actions.
-
inline std::size_t size() const noexcept
Get the number of actions.
-
bool contains(const ActionPtr &action) const noexcept
Test if an action is already attached to this container.
-
void onKeyPress(KeyPressEvent &keyPressEvent)
Handle a key press event using the first enabled matching action.
- Parameters:
keyPressEvent – The key press event to handle.
-
void refreshForRepaint()
Refresh repaint-driven action enablement.
-
explicit Actions(SurfaceWeakPtr owner) noexcept
-
class ActionTriggerContext
Context passed to an action when it is triggered.
Public Functions
-
explicit ActionTriggerContext(Key key, SurfaceWeakPtr sourceSurface = {}) noexcept
Create a trigger context.
- Parameters:
key – The key that triggered the action.
sourceSurface – The surface whose action container triggered the action.
-
inline const SurfaceWeakPtr &sourceSurface() const noexcept
Get the surface whose action container triggered the action.
-
explicit ActionTriggerContext(Key key, SurfaceWeakPtr sourceSurface = {}) noexcept