Commands describe side effects that update/2 wants the runtime to perform.
They are plain data -- inspectable, testable, serializable. The runtime
interprets them after update/2 returns. Nothing executes inside update.
Categories
- Basic:
none/0,done/2,async/2,stream/2,cancel/1,send_after/2,exit/0 - Focus:
focus/1,focus_next/0,focus_previous/0 - Text:
select_all/1,move_cursor_to_front/1,move_cursor_to_end/1,move_cursor_to/2,select_range/3 - Scroll:
scroll_to/2,snap_to/3,snap_to_end/1,scroll_by/3 - Window ops:
close_window/1,resize_window/3,move_window/3,maximize_window/2,minimize_window/2,set_window_mode/2,toggle_maximize/1,toggle_decorations/1,gain_focus/1,set_window_level/2,drag_window/1,drag_resize_window/2,request_user_attention/2,screenshot/2,set_resizable/2,set_min_size/3,set_max_size/3,enable_mouse_passthrough/1,disable_mouse_passthrough/1,show_system_menu/1,set_icon/4,set_resize_increments/3,allow_automatic_tabbing/1. - Window queries:
get_window_size/2,get_window_position/2,is_maximized/2,is_minimized/2,get_mode/2,get_scale_factor/2,raw_id/2,monitor_size/2 - System queries:
get_system_theme/1,get_system_info/1 - PaneGrid ops:
pane_split/4,pane_close/2,pane_swap/3,pane_maximize/2,pane_restore/1 - Image ops:
create_image/2,create_image/4,update_image/2,update_image/4,delete_image/1,list_images/1,clear_images/0 - Queries:
tree_hash/1,find_focused/1 - Font:
load_font/1 - Accessibility:
announce/1 - Extension:
extension_command/3,extension_commands/1 - Test/Headless:
advance_frame/1 - Batch:
batch/1
Usage
def update(model, %Toddy.Event.Widget{type: :click, id: "save"}) do
cmd = Toddy.Command.async(fn -> save(model) end, :save_result)
{model, cmd}
end
def update(model, %Toddy.Event.Async{tag: :save_result, result: :ok}), do: %{model | saved: true}Multiple commands can be issued at once via batch/1:
cmd = Toddy.Command.batch([
Toddy.Command.focus("name_input"),
Toddy.Command.send_after(5000, :auto_save)
])
Summary
Types
Tag atom used to identify async results in update/2.
A command to be dispatched by the runtime.
Stable string identifier for a widget node in the UI tree.
Stable string identifier for a window node in the UI tree.
Functions
Advance the animation clock by one frame in headless/test mode.
Sets whether the system can automatically organize windows into tabs.
Triggers a screen reader announcement without a visible widget.
Run fun asynchronously in a Task. When it returns, the runtime dispatches
%Toddy.Event.Async{tag: event_tag, result: result} through update/2.
Issue multiple commands. Commands in the batch execute concurrently.
Cancel a running async or stream command by its tag.
Clears all in-memory images.
Close the window identified by window_id.
Creates an in-memory image from encoded PNG/JPEG bytes.
Creates an in-memory image from raw RGBA pixel data.
Deletes an in-memory image by handle name.
Disable mouse passthrough on a window.
Wraps an already-resolved value in a command. The runtime immediately
dispatches msg_fn.(value) through update/2 without spawning a task.
Start drag-resizing the window from the given edge/corner direction.
Start dragging the window.
Enable mouse passthrough on a window (clicks pass through to windows below).
Exit the application.
Send a command to a native extension widget.
Send a batch of extension commands (processed in one cycle).
Queries which widget currently has focus.
Focus the widget identified by widget_id.
Move focus to the next focusable widget.
Move focus to the previous focusable widget.
Give focus to a window.
Query the current window mode (windowed, fullscreen, hidden). Result arrives as an effect response keyed by window ID.
Query the window's current scale factor (DPI scaling). Result arrives as an effect response keyed by window ID.
Query system information (OS, CPU, memory, graphics).
Query the current system theme (light/dark mode).
Query the position of a window. Result arrives as {tag, {x, y}}.
Query the size of a window. Result arrives as {tag, {width, height}}.
Query whether a window is maximized. Result arrives as {tag, boolean}.
Query whether a window is minimized. Result arrives as {tag, boolean}.
Lists all in-memory image handles.
Loads a font at runtime from binary data.
Maximize or restore a window.
Minimize or restore a window.
Query the monitor size for the display containing a window.
Result arrives as an effect response with {width, height} or null
if the monitor cannot be determined.
Move the text cursor to a specific position.
Move the text cursor to the end of the input.
Move the text cursor to the front of the input.
Move a window to the given position.
A no-op command. Returned implicitly when update/2 returns a bare model.
Close a pane in the pane grid.
Maximize a pane in the pane grid.
Restore all panes from maximized state.
Split a pane in the pane grid along the given axis.
Swap two panes in the pane grid.
Query the raw platform window ID (e.g. X11 window ID, HWND). Result arrives as an effect response keyed by window ID.
Request user attention for a window. Urgency can be :informational or :critical.
Resize a window to the given dimensions.
Take a screenshot of a window. Result arrives as a tagged event.
Scroll the widget by a relative offset.
Scroll the widget identified by widget_id to offset.
Select all text in the widget identified by widget_id.
Select a range of text in the input.
Send event through update/2 after delay_ms milliseconds.
Sets the window icon from raw RGBA pixel data.
Set the maximum size of a window.
Set the minimum size of a window.
Set whether a window is resizable.
Sets the resize increment size for a window.
Set window stacking level (:normal, :always_on_top, :always_on_bottom).
Set window mode (windowed, fullscreen, etc.).
Show the system menu for a window.
Snap the scrollable widget to an absolute offset.
Snap the scrollable widget to the end of its content.
Run fun as a streaming async task. The function receives an emit callback
that sends intermediate results to update/2 as
%Toddy.Event.Stream{tag: event_tag, value: value}. The function's final
return value is delivered as %Toddy.Event.Async{tag: event_tag, result: result}.
Toggle window decorations (title bar, borders).
Toggle window maximized state.
Computes a SHA-256 hash of the renderer's current tree state.
Updates an existing in-memory image with new encoded PNG/JPEG bytes.
Updates an existing in-memory image with new raw RGBA pixel data.
Types
@type event_tag() :: atom()
Tag atom used to identify async results in update/2.
A command to be dispatched by the runtime.
Always a %Command{} struct. batch/1 wraps multiple commands into a
single struct with type: :batch. The runtime normalizes bare lists
internally, but the public type is always a struct.
@type widget_id() :: String.t()
Stable string identifier for a widget node in the UI tree.
@type window_id() :: String.t()
Stable string identifier for a window node in the UI tree.
Functions
@spec advance_frame(timestamp :: non_neg_integer()) :: %Toddy.Command{ payload: term(), type: term() }
Advance the animation clock by one frame in headless/test mode.
Sends an advance_frame message to the renderer with the given
timestamp (monotonic milliseconds). If on_animation_frame is
subscribed, the renderer emits an animation_frame event back.
This is a test/headless-only command. In normal daemon mode the renderer drives animation frames from the display vsync.
Example
Toddy.Command.advance_frame(16)
@spec allow_automatic_tabbing(enabled :: boolean()) :: %Toddy.Command{ payload: term(), type: term() }
Sets whether the system can automatically organize windows into tabs.
This is a macOS-specific setting. On other platforms it is a no-op. See: https://developer.apple.com/documentation/appkit/nswindow/1646657-allowsautomaticwindowtabbing
Triggers a screen reader announcement without a visible widget.
The text is immediately announced by assistive technology as a live-region assertion. Useful for status updates, error messages, and other dynamic content that should be announced but doesn't need to be visually displayed.
Example
Command.announce("File saved successfully")
Command.announce("3 search results found")
Run fun asynchronously in a Task. When it returns, the runtime dispatches
%Toddy.Event.Async{tag: event_tag, result: result} through update/2.
Issue multiple commands. Commands in the batch execute concurrently.
Accepts a single command, a list of commands, or a nested list -- anything
List.wrap/1 can normalize.
Cancel a running async or stream command by its tag.
If the task has already completed, this is a no-op. The runtime tracks running tasks by their event tag and terminates the associated process.
Example
Command.cancel(:file_import)
Clears all in-memory images.
Close the window identified by window_id.
@spec create_image(handle :: String.t(), data :: binary()) :: %Toddy.Command{ payload: term(), type: term() }
Creates an in-memory image from encoded PNG/JPEG bytes.
The raw binary is stored as-is in the command payload. The protocol layer handles format-specific encoding (native binary for msgpack, base64 for JSON).
@spec create_image( handle :: String.t(), width :: pos_integer(), height :: pos_integer(), pixels :: binary() ) :: %Toddy.Command{payload: term(), type: term()}
Creates an in-memory image from raw RGBA pixel data.
The raw binary is stored as-is in the command payload. The protocol layer handles format-specific encoding (native binary for msgpack, base64 for JSON).
Deletes an in-memory image by handle name.
@spec disable_mouse_passthrough(window_id :: window_id()) :: %Toddy.Command{ payload: term(), type: term() }
Disable mouse passthrough on a window.
@spec done(value :: term(), msg_fn :: (term() -> term())) :: %Toddy.Command{ payload: term(), type: term() }
Wraps an already-resolved value in a command. The runtime immediately
dispatches msg_fn.(value) through update/2 without spawning a task.
Useful for lifting a pure value into the command pipeline.
@spec drag_resize_window(window_id :: window_id(), direction :: atom() | String.t()) :: %Toddy.Command{ payload: term(), type: term() }
Start drag-resizing the window from the given edge/corner direction.
Start dragging the window.
@spec enable_mouse_passthrough(window_id :: window_id()) :: %Toddy.Command{ payload: term(), type: term() }
Enable mouse passthrough on a window (clicks pass through to windows below).
Exit the application.
@spec extension_command(node_id :: String.t(), op :: String.t(), payload :: map()) :: %Toddy.Command{ payload: term(), type: term() }
Send a command to a native extension widget.
Extension commands bypass the normal tree update / diff / patch cycle and are delivered directly to the target extension widget on the Rust side.
@spec extension_commands(commands :: [{String.t(), String.t(), map()}]) :: %Toddy.Command{ payload: term(), type: term() }
Send a batch of extension commands (processed in one cycle).
Each command in the list is a {node_id, op, payload} tuple.
Queries which widget currently has focus.
The result arrives in update/2 as
%System{type: :find_focused, tag: tag, data: %{"focused" => "..." | nil}}.
Note: if no widget is focused, the "focused" field may be nil.
Focus the widget identified by widget_id.
Move focus to the next focusable widget.
Move focus to the previous focusable widget.
Give focus to a window.
@spec get_mode(window_id :: window_id(), tag :: event_tag()) :: %Toddy.Command{ payload: term(), type: term() }
Query the current window mode (windowed, fullscreen, hidden). Result arrives as an effect response keyed by window ID.
@spec get_scale_factor(window_id :: window_id(), tag :: event_tag()) :: %Toddy.Command{ payload: term(), type: term() }
Query the window's current scale factor (DPI scaling). Result arrives as an effect response keyed by window ID.
Query system information (OS, CPU, memory, graphics).
The result arrives in update/2 as {:system_info, tag, info} where tag
is the stringified event tag and info is a map with keys:
"system_name", "system_kernel", "system_version",
"system_short_version", "cpu_brand", "cpu_cores", "memory_total",
"memory_used", "graphics_backend", "graphics_adapter".
System info is always available (the sysinfo iced feature is enabled
unconditionally).
Example
def update(model, %Toddy.Event.Widget{type: :click, id: "sys_info"}) do
{model, Toddy.Command.get_system_info(:sys_info)}
end
def update(model, {:system_info, "sys_info", info}) do
%{model | system: info}
end
Query the current system theme (light/dark mode).
The result arrives in update/2 as {:system_theme, tag, mode} where
tag is the stringified event tag and mode is "light", "dark", or
"none" (when no system preference is detected). Returns "none" on
Linux systems without a desktop environment. Apps should provide a theme
fallback.
Example
def update(model, %Toddy.Event.Widget{type: :click, id: "check_theme"}) do
{model, Toddy.Command.get_system_theme(:theme_result)}
end
def update(model, {:system_theme, "theme_result", mode}) do
%{model | theme_mode: mode}
end
@spec get_window_position(window_id :: window_id(), tag :: event_tag()) :: %Toddy.Command{ payload: term(), type: term() }
Query the position of a window. Result arrives as {tag, {x, y}}.
@spec get_window_size(window_id :: window_id(), tag :: event_tag()) :: %Toddy.Command{ payload: term(), type: term() }
Query the size of a window. Result arrives as {tag, {width, height}}.
@spec is_maximized(window_id :: window_id(), tag :: event_tag()) :: %Toddy.Command{ payload: term(), type: term() }
Query whether a window is maximized. Result arrives as {tag, boolean}.
@spec is_minimized(window_id :: window_id(), tag :: event_tag()) :: %Toddy.Command{ payload: term(), type: term() }
Query whether a window is minimized. Result arrives as {tag, boolean}.
Lists all in-memory image handles.
The result arrives in update/2 as
%System{type: :image_list, tag: tag, data: %{"handles" => [...]}}.
Loads a font at runtime from binary data.
The font data should be the raw bytes of a TrueType (.ttf) or OpenType
(.otf) font file. Once loaded, the font can be referenced by name in
widget font props.
Example
font_data = File.read!("path/to/CustomFont.ttf")
Toddy.Command.load_font(font_data)
@spec maximize_window(window_id :: window_id(), maximized :: boolean()) :: %Toddy.Command{ payload: term(), type: term() }
Maximize or restore a window.
@spec minimize_window(window_id :: window_id(), minimized :: boolean()) :: %Toddy.Command{ payload: term(), type: term() }
Minimize or restore a window.
@spec monitor_size(window_id :: window_id(), tag :: event_tag()) :: %Toddy.Command{ payload: term(), type: term() }
Query the monitor size for the display containing a window.
Result arrives as an effect response with {width, height} or null
if the monitor cannot be determined.
@spec move_cursor_to(widget_id :: widget_id(), position :: non_neg_integer()) :: %Toddy.Command{ payload: term(), type: term() }
Move the text cursor to a specific position.
@spec move_cursor_to_end(widget_id :: widget_id()) :: %Toddy.Command{ payload: term(), type: term() }
Move the text cursor to the end of the input.
@spec move_cursor_to_front(widget_id :: widget_id()) :: %Toddy.Command{ payload: term(), type: term() }
Move the text cursor to the front of the input.
@spec move_window(window_id :: window_id(), x :: number(), y :: number()) :: %Toddy.Command{ payload: term(), type: term() }
Move a window to the given position.
A no-op command. Returned implicitly when update/2 returns a bare model.
@spec pane_close(pane_grid_id :: widget_id(), pane_id :: term()) :: %Toddy.Command{ payload: term(), type: term() }
Close a pane in the pane grid.
@spec pane_maximize(pane_grid_id :: widget_id(), pane_id :: term()) :: %Toddy.Command{ payload: term(), type: term() }
Maximize a pane in the pane grid.
Restore all panes from maximized state.
@spec pane_split( pane_grid_id :: widget_id(), pane_id :: term(), axis :: atom() | String.t(), new_pane_id :: term() ) :: %Toddy.Command{payload: term(), type: term()}
Split a pane in the pane grid along the given axis.
@spec pane_swap(pane_grid_id :: widget_id(), pane_a :: term(), pane_b :: term()) :: %Toddy.Command{ payload: term(), type: term() }
Swap two panes in the pane grid.
@spec raw_id(window_id :: window_id(), tag :: event_tag()) :: %Toddy.Command{ payload: term(), type: term() }
Query the raw platform window ID (e.g. X11 window ID, HWND). Result arrives as an effect response keyed by window ID.
@spec request_user_attention(window_id :: window_id(), urgency :: atom() | nil) :: %Toddy.Command{ payload: term(), type: term() }
Request user attention for a window. Urgency can be :informational or :critical.
@spec resize_window(window_id :: window_id(), width :: number(), height :: number()) :: %Toddy.Command{ payload: term(), type: term() }
Resize a window to the given dimensions.
@spec screenshot(window_id :: window_id(), tag :: event_tag()) :: %Toddy.Command{ payload: term(), type: term() }
Take a screenshot of a window. Result arrives as a tagged event.
@spec scroll_by(widget_id :: widget_id(), x :: float(), y :: float()) :: %Toddy.Command{ payload: term(), type: term() }
Scroll the widget by a relative offset.
@spec scroll_to(widget_id :: widget_id(), offset :: term()) :: %Toddy.Command{ payload: term(), type: term() }
Scroll the widget identified by widget_id to offset.
Select all text in the widget identified by widget_id.
@spec select_range( widget_id :: widget_id(), start_pos :: non_neg_integer(), end_pos :: non_neg_integer() ) :: %Toddy.Command{payload: term(), type: term()}
Select a range of text in the input.
@spec send_after(delay_ms :: non_neg_integer(), event :: term()) :: %Toddy.Command{ payload: term(), type: term() }
Send event through update/2 after delay_ms milliseconds.
@spec set_icon( window_id :: window_id(), rgba_data :: binary(), width :: pos_integer(), height :: pos_integer() ) :: %Toddy.Command{payload: term(), type: term()}
Sets the window icon from raw RGBA pixel data.
The rgba_data must be a binary of width * height * 4 bytes (one byte
each for R, G, B, A per pixel, row-major). The raw binary is stored as-is
in the command payload. The protocol layer handles format-specific encoding
(native binary for msgpack via Msgpax.Bin, base64 for JSON).
Example
icon_data = File.read!("icon_32x32.rgba")
Toddy.Command.set_icon("main", icon_data, 32, 32)
@spec set_max_size(window_id :: window_id(), width :: number(), height :: number()) :: %Toddy.Command{ payload: term(), type: term() }
Set the maximum size of a window.
@spec set_min_size(window_id :: window_id(), width :: number(), height :: number()) :: %Toddy.Command{ payload: term(), type: term() }
Set the minimum size of a window.
@spec set_resizable(window_id :: window_id(), resizable :: boolean()) :: %Toddy.Command{ payload: term(), type: term() }
Set whether a window is resizable.
@spec set_resize_increments( window_id :: window_id(), width :: number() | nil, height :: number() | nil ) :: %Toddy.Command{payload: term(), type: term()}
Sets the resize increment size for a window.
When set, the window will only resize in multiples of the given width and
height. Pass nil for both to clear the constraint. Useful for terminal
emulators and grid-aligned apps.
@spec set_window_level(window_id :: window_id(), level :: atom() | String.t()) :: %Toddy.Command{ payload: term(), type: term() }
Set window stacking level (:normal, :always_on_top, :always_on_bottom).
On Wayland, window stacking is compositor-controlled and this command may be silently ignored.
@spec set_window_mode(window_id :: window_id(), mode :: atom() | String.t()) :: %Toddy.Command{ payload: term(), type: term() }
Set window mode (windowed, fullscreen, etc.).
@spec snap_to(widget_id :: widget_id(), x :: float(), y :: float()) :: %Toddy.Command{ payload: term(), type: term() }
Snap the scrollable widget to an absolute offset.
Snap the scrollable widget to the end of its content.
@spec stream(fun :: (fun() -> term()), event_tag :: atom()) :: %Toddy.Command{ payload: term(), type: term() }
Run fun as a streaming async task. The function receives an emit callback
that sends intermediate results to update/2 as
%Toddy.Event.Stream{tag: event_tag, value: value}. The function's final
return value is delivered as %Toddy.Event.Async{tag: event_tag, result: result}.
This is sugar over spawning a process manually. You can achieve the same
thing with bare Task and send/2 if you prefer direct Elixir patterns.
Example
Command.stream(fn emit ->
for chunk <- File.stream!("big.csv") do
emit.({:chunk, process(chunk)})
end
:done
end, :file_import)
@spec toggle_decorations(window_id :: window_id()) :: %Toddy.Command{ payload: term(), type: term() }
Toggle window decorations (title bar, borders).
Toggle window maximized state.
Computes a SHA-256 hash of the renderer's current tree state.
The result arrives in update/2 as
%System{type: :tree_hash, tag: tag, data: %{"hash" => "..."}}.
@spec update_image(handle :: String.t(), data :: binary()) :: %Toddy.Command{ payload: term(), type: term() }
Updates an existing in-memory image with new encoded PNG/JPEG bytes.
The raw binary is stored as-is in the command payload. The protocol layer handles format-specific encoding (native binary for msgpack, base64 for JSON).
@spec update_image( handle :: String.t(), width :: pos_integer(), height :: pos_integer(), pixels :: binary() ) :: %Toddy.Command{payload: term(), type: term()}
Updates an existing in-memory image with new raw RGBA pixel data.
The raw binary is stored as-is in the command payload. The protocol layer handles format-specific encoding (native binary for msgpack, base64 for JSON).