iced-runtime-kora 0.15.0

A renderer-agnostic runtime for iced (Playtron's Kora fork of iced_runtime)
Documentation
//! Change internal widget state.
use crate::core::widget::Id;
use crate::core::widget::operation;
use crate::task;
use crate::{Action, Task};

pub use crate::core::widget::operation::focusable::FocusDirection;
pub use crate::core::widget::operation::scrollable::{
    AbsoluteOffset, EnsureVisibleConfig, RelativeOffset, ScrollAnimation,
};

/// Snaps the scrollable with the given [`Id`] to the provided [`RelativeOffset`].
pub fn snap_to<T>(id: impl Into<Id>, offset: impl Into<RelativeOffset<Option<f32>>>) -> Task<T> {
    task::effect(Action::widget(operation::scrollable::snap_to(
        id.into(),
        offset.into(),
    )))
}

/// Snaps the scrollable with the given [`Id`] to the [`RelativeOffset::END`].
pub fn snap_to_end<T>(id: impl Into<Id>) -> Task<T> {
    task::effect(Action::widget(operation::scrollable::snap_to(
        id.into(),
        RelativeOffset::END.into(),
    )))
}

/// Scrolls the scrollable with the given [`Id`] to the provided [`AbsoluteOffset`].
pub fn scroll_to<T>(id: impl Into<Id>, offset: impl Into<AbsoluteOffset<Option<f32>>>) -> Task<T> {
    task::effect(Action::widget(operation::scrollable::scroll_to(
        id.into(),
        offset.into(),
    )))
}

/// Scrolls the scrollable with the given [`Id`] by the provided [`AbsoluteOffset`].
pub fn scroll_by<T>(id: impl Into<Id>, offset: AbsoluteOffset) -> Task<T> {
    task::effect(Action::widget(operation::scrollable::scroll_by(
        id.into(),
        offset,
    )))
}

/// Scrolls the nearest scrollable ancestor of the currently focused widget
/// so the focused widget is visible at the configured alignment.
///
/// Works with any scrollable — no explicit [`Id`] required. If the
/// scrollable does have an ID it is ignored; the operation identifies the
/// scrollable by its position in the widget tree.
///
/// Pass [`EnsureVisibleConfig::default()`] for 35% from top (Flutter Grid
/// default), or [`EnsureVisibleConfig::CENTER`] for center alignment.
///
/// Returns `Task::none()` if no focused widget or scrollable ancestor is found.
///
/// # Example
///
/// ```rust,ignore
/// use iced::widget::operation::{ensure_focused_visible, EnsureVisibleConfig};
///
/// // In update(), when focus changes:
/// ensure_focused_visible(EnsureVisibleConfig::default())
/// ```
pub fn ensure_focused_visible<T: Send + 'static>(config: EnsureVisibleConfig) -> Task<T> {
    task::effect(Action::widget(
        operation::scrollable::ensure_focused_visible_op(config),
    ))
}

/// Focuses the previous focusable widget.
pub fn focus_previous<T>() -> Task<T> {
    task::effect(Action::widget(operation::focusable::focus_previous()))
}

/// Focuses the next focusable widget.
pub fn focus_next<T>() -> Task<T> {
    task::effect(Action::widget(operation::focusable::focus_next()))
}

/// Focuses the nearest focusable widget in the given spatial [`FocusDirection`].
///
/// Uses widget bounds to determine the closest candidate. If nothing is
/// focused, the first focusable widget receives focus. Wraps to the opposite
/// edge when no candidate exists in the requested direction.
pub fn focus_direction<T>(direction: FocusDirection) -> Task<T> {
    task::effect(Action::widget(operation::focusable::focus_directional(
        direction,
    )))
}

/// Like [`focus_direction`], but does **not** wrap to the opposite edge
/// when no candidate exists in the requested direction. Focus simply stays
/// on the currently focused widget.
pub fn focus_direction_no_wrap<T>(direction: FocusDirection) -> Task<T> {
    task::effect(Action::widget(
        operation::focusable::focus_directional_no_wrap(direction),
    ))
}

/// Focuses the first widget marked for auto-focus.
///
/// If no auto-focus widget is found, focuses the first focusable widget
/// instead. Use this after page transitions to automatically focus the
/// appropriate widget.
pub fn focus_auto<T>() -> Task<T> {
    task::effect(Action::widget(operation::auto_focusable::focus_auto()))
}

/// Activates the currently focused widget by calling its
/// [`Focusable::press()`](operation::Focusable::press) method.
///
/// This is the preferred way to trigger a focused widget from gamepad
/// input — it targets only the focused widget without injecting synthetic
/// keyboard events.
pub fn press_focused<T>() -> Task<T> {
    task::effect(Action::widget(operation::focusable::press_focused()))
}

/// Returns whether the widget with the given [`Id`] is focused or not.
pub fn is_focused(id: impl Into<Id>) -> Task<bool> {
    task::widget(operation::focusable::is_focused(id.into()))
}

/// Focuses the widget with the given [`Id`].
pub fn focus<T>(id: impl Into<Id>) -> Task<T> {
    task::effect(Action::widget(operation::focusable::focus(id.into())))
}

/// Unfocuses the currently focused widget.
pub fn unfocus<T>() -> Task<T> {
    task::effect(Action::widget(operation::focusable::unfocus()))
}

/// Moves the cursor of the widget with the given [`Id`] to the end.
pub fn move_cursor_to_end<T>(id: impl Into<Id>) -> Task<T> {
    task::effect(Action::widget(operation::text_input::move_cursor_to_end(
        id.into(),
    )))
}

/// Moves the cursor of the widget with the given [`Id`] to the front.
pub fn move_cursor_to_front<T>(id: impl Into<Id>) -> Task<T> {
    task::effect(Action::widget(operation::text_input::move_cursor_to_front(
        id.into(),
    )))
}

/// Moves the cursor of the widget with the given [`Id`] to the provided position.
pub fn move_cursor_to<T>(id: impl Into<Id>, position: usize) -> Task<T> {
    task::effect(Action::widget(operation::text_input::move_cursor_to(
        id.into(),
        position,
    )))
}

/// Selects all the content of the widget with the given [`Id`].
pub fn select_all<T>(id: impl Into<Id>) -> Task<T> {
    task::effect(Action::widget(operation::text_input::select_all(id.into())))
}

/// Selects the given content range of the widget with the given [`Id`].
pub fn select_range<T>(id: impl Into<Id>, start: usize, end: usize) -> Task<T> {
    task::effect(Action::widget(operation::text_input::select_range(
        id.into(),
        start,
        end,
    )))
}