Skip to main content

iced_runtime/widget/
operation.rs

1//! Change internal widget state.
2use crate::core::widget::Id;
3use crate::core::widget::operation;
4use crate::task;
5use crate::{Action, Task};
6
7pub use crate::core::widget::operation::focusable::FocusDirection;
8pub use crate::core::widget::operation::scrollable::{
9    AbsoluteOffset, EnsureVisibleConfig, RelativeOffset, ScrollAnimation,
10};
11
12/// Snaps the scrollable with the given [`Id`] to the provided [`RelativeOffset`].
13pub fn snap_to<T>(id: impl Into<Id>, offset: impl Into<RelativeOffset<Option<f32>>>) -> Task<T> {
14    task::effect(Action::widget(operation::scrollable::snap_to(
15        id.into(),
16        offset.into(),
17    )))
18}
19
20/// Snaps the scrollable with the given [`Id`] to the [`RelativeOffset::END`].
21pub fn snap_to_end<T>(id: impl Into<Id>) -> Task<T> {
22    task::effect(Action::widget(operation::scrollable::snap_to(
23        id.into(),
24        RelativeOffset::END.into(),
25    )))
26}
27
28/// Scrolls the scrollable with the given [`Id`] to the provided [`AbsoluteOffset`].
29pub fn scroll_to<T>(id: impl Into<Id>, offset: impl Into<AbsoluteOffset<Option<f32>>>) -> Task<T> {
30    task::effect(Action::widget(operation::scrollable::scroll_to(
31        id.into(),
32        offset.into(),
33    )))
34}
35
36/// Scrolls the scrollable with the given [`Id`] by the provided [`AbsoluteOffset`].
37pub fn scroll_by<T>(id: impl Into<Id>, offset: AbsoluteOffset) -> Task<T> {
38    task::effect(Action::widget(operation::scrollable::scroll_by(
39        id.into(),
40        offset,
41    )))
42}
43
44/// Scrolls the nearest scrollable ancestor of the currently focused widget
45/// so the focused widget is visible at the configured alignment.
46///
47/// Works with any scrollable — no explicit [`Id`] required. If the
48/// scrollable does have an ID it is ignored; the operation identifies the
49/// scrollable by its position in the widget tree.
50///
51/// Pass [`EnsureVisibleConfig::default()`] for 35% from top (Flutter Grid
52/// default), or [`EnsureVisibleConfig::CENTER`] for center alignment.
53///
54/// Returns `Task::none()` if no focused widget or scrollable ancestor is found.
55///
56/// # Example
57///
58/// ```rust,ignore
59/// use iced::widget::operation::{ensure_focused_visible, EnsureVisibleConfig};
60///
61/// // In update(), when focus changes:
62/// ensure_focused_visible(EnsureVisibleConfig::default())
63/// ```
64pub fn ensure_focused_visible<T: Send + 'static>(config: EnsureVisibleConfig) -> Task<T> {
65    task::effect(Action::widget(
66        operation::scrollable::ensure_focused_visible_op(config),
67    ))
68}
69
70/// Focuses the previous focusable widget.
71pub fn focus_previous<T>() -> Task<T> {
72    task::effect(Action::widget(operation::focusable::focus_previous()))
73}
74
75/// Focuses the next focusable widget.
76pub fn focus_next<T>() -> Task<T> {
77    task::effect(Action::widget(operation::focusable::focus_next()))
78}
79
80/// Focuses the nearest focusable widget in the given spatial [`FocusDirection`].
81///
82/// Uses widget bounds to determine the closest candidate. If nothing is
83/// focused, the first focusable widget receives focus. Wraps to the opposite
84/// edge when no candidate exists in the requested direction.
85pub fn focus_direction<T>(direction: FocusDirection) -> Task<T> {
86    task::effect(Action::widget(operation::focusable::focus_directional(
87        direction,
88    )))
89}
90
91/// Like [`focus_direction`], but does **not** wrap to the opposite edge
92/// when no candidate exists in the requested direction. Focus simply stays
93/// on the currently focused widget.
94pub fn focus_direction_no_wrap<T>(direction: FocusDirection) -> Task<T> {
95    task::effect(Action::widget(
96        operation::focusable::focus_directional_no_wrap(direction),
97    ))
98}
99
100/// Focuses the first widget marked for auto-focus.
101///
102/// If no auto-focus widget is found, focuses the first focusable widget
103/// instead. Use this after page transitions to automatically focus the
104/// appropriate widget.
105pub fn focus_auto<T>() -> Task<T> {
106    task::effect(Action::widget(operation::auto_focusable::focus_auto()))
107}
108
109/// Activates the currently focused widget by calling its
110/// [`Focusable::press()`](operation::Focusable::press) method.
111///
112/// This is the preferred way to trigger a focused widget from gamepad
113/// input — it targets only the focused widget without injecting synthetic
114/// keyboard events.
115pub fn press_focused<T>() -> Task<T> {
116    task::effect(Action::widget(operation::focusable::press_focused()))
117}
118
119/// Returns whether the widget with the given [`Id`] is focused or not.
120pub fn is_focused(id: impl Into<Id>) -> Task<bool> {
121    task::widget(operation::focusable::is_focused(id.into()))
122}
123
124/// Focuses the widget with the given [`Id`].
125pub fn focus<T>(id: impl Into<Id>) -> Task<T> {
126    task::effect(Action::widget(operation::focusable::focus(id.into())))
127}
128
129/// Unfocuses the currently focused widget.
130pub fn unfocus<T>() -> Task<T> {
131    task::effect(Action::widget(operation::focusable::unfocus()))
132}
133
134/// Moves the cursor of the widget with the given [`Id`] to the end.
135pub fn move_cursor_to_end<T>(id: impl Into<Id>) -> Task<T> {
136    task::effect(Action::widget(operation::text_input::move_cursor_to_end(
137        id.into(),
138    )))
139}
140
141/// Moves the cursor of the widget with the given [`Id`] to the front.
142pub fn move_cursor_to_front<T>(id: impl Into<Id>) -> Task<T> {
143    task::effect(Action::widget(operation::text_input::move_cursor_to_front(
144        id.into(),
145    )))
146}
147
148/// Moves the cursor of the widget with the given [`Id`] to the provided position.
149pub fn move_cursor_to<T>(id: impl Into<Id>, position: usize) -> Task<T> {
150    task::effect(Action::widget(operation::text_input::move_cursor_to(
151        id.into(),
152        position,
153    )))
154}
155
156/// Selects all the content of the widget with the given [`Id`].
157pub fn select_all<T>(id: impl Into<Id>) -> Task<T> {
158    task::effect(Action::widget(operation::text_input::select_all(id.into())))
159}
160
161/// Selects the given content range of the widget with the given [`Id`].
162pub fn select_range<T>(id: impl Into<Id>, start: usize, end: usize) -> Task<T> {
163    task::effect(Action::widget(operation::text_input::select_range(
164        id.into(),
165        start,
166        end,
167    )))
168}