Move all operations to widget::operation module

This commit is contained in:
Héctor Ramón Jiménez 2025-08-23 03:54:54 +02:00
parent 885d45f435
commit 34a42b5ad4
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
14 changed files with 124 additions and 136 deletions

View file

@ -1,8 +1,8 @@
use iced::highlighter; use iced::highlighter;
use iced::keyboard; use iced::keyboard;
use iced::widget::{ use iced::widget::{
self, button, center_x, column, container, horizontal_space, pick_list, button, center_x, column, container, horizontal_space, operation,
row, text, text_editor, toggler, tooltip, pick_list, row, text, text_editor, toggler, tooltip,
}; };
use iced::{Center, Element, Fill, Font, Task, Theme}; use iced::{Center, Element, Fill, Font, Task, Theme};
@ -59,7 +59,7 @@ impl Editor {
)), )),
Message::FileOpened, Message::FileOpened,
), ),
widget::focus_next(), operation::focus_next(),
]), ]),
) )
} }

View file

@ -5,8 +5,8 @@ use iced::clipboard;
use iced::highlighter; use iced::highlighter;
use iced::time::{self, Instant, milliseconds}; use iced::time::{self, Instant, milliseconds};
use iced::widget::{ use iced::widget::{
self, button, center_x, container, horizontal_space, hover, image, button, center_x, container, horizontal_space, hover, image, markdown,
markdown, right, row, scrollable, sensor, text_editor, toggler, operation, right, row, scrollable, sensor, text_editor, toggler,
}; };
use iced::window; use iced::window;
use iced::{ use iced::{
@ -78,7 +78,7 @@ impl Markdown {
theme: Theme::TokyoNight, theme: Theme::TokyoNight,
now: Instant::now(), now: Instant::now(),
}, },
widget::focus_next(), operation::focus_next(),
) )
} }
@ -140,10 +140,7 @@ impl Markdown {
pending: self.raw.text(), pending: self.raw.text(),
}; };
scrollable::snap_to( operation::snap_to_end("preview")
"preview",
scrollable::RelativeOffset::END,
)
} else { } else {
self.mode = Mode::Preview; self.mode = Mode::Preview;

View file

@ -2,8 +2,8 @@ use iced::event::{self, Event};
use iced::keyboard; use iced::keyboard;
use iced::keyboard::key; use iced::keyboard::key;
use iced::widget::{ use iced::widget::{
self, button, center, column, container, horizontal_space, mouse_area, button, center, column, container, horizontal_space, mouse_area, opaque,
opaque, pick_list, row, stack, text, text_input, operation, pick_list, row, stack, text, text_input,
}; };
use iced::{Bottom, Color, Element, Fill, Subscription, Task}; use iced::{Bottom, Color, Element, Fill, Subscription, Task};
@ -43,7 +43,7 @@ impl App {
match message { match message {
Message::ShowModal => { Message::ShowModal => {
self.show_modal = true; self.show_modal = true;
widget::focus_next() operation::focus_next()
} }
Message::HideModal => { Message::HideModal => {
self.hide_modal(); self.hide_modal();
@ -75,9 +75,9 @@ impl App {
.. ..
}) => { }) => {
if modifiers.shift() { if modifiers.shift() {
widget::focus_previous() operation::focus_previous()
} else { } else {
widget::focus_next() operation::focus_next()
} }
} }
Event::Keyboard(keyboard::Event::KeyPressed { Event::Keyboard(keyboard::Event::KeyPressed {

View file

@ -1,6 +1,6 @@
use iced::widget::{ use iced::widget::{
button, center, center_x, column, container, horizontal_space, scrollable, button, center, center_x, column, container, horizontal_space, operation,
text, text_input, scrollable, text, text_input,
}; };
use iced::window; use iced::window;
use iced::{ use iced::{
@ -85,7 +85,7 @@ impl Example {
} }
Message::WindowOpened(id) => { Message::WindowOpened(id) => {
let window = Window::new(self.windows.len() + 1); let window = Window::new(self.windows.len() + 1);
let focus_input = text_input::focus(format!("input-{id}")); let focus_input = operation::focus(format!("input-{id}"));
self.windows.insert(id, window); self.windows.insert(id, window);

View file

@ -1,6 +1,6 @@
use iced::widget::{ use iced::widget::{
button, column, container, horizontal_space, progress_bar, radio, row, button, column, container, horizontal_space, operation, progress_bar,
scrollable, slider, text, vertical_space, radio, row, scrollable, slider, text, vertical_space,
}; };
use iced::{Border, Center, Color, Element, Fill, Task, Theme}; use iced::{Border, Center, Color, Element, Fill, Task, Theme};
@ -60,13 +60,13 @@ impl ScrollableDemo {
self.current_scroll_offset = scrollable::RelativeOffset::START; self.current_scroll_offset = scrollable::RelativeOffset::START;
self.scrollable_direction = direction; self.scrollable_direction = direction;
scrollable::snap_to(SCROLLABLE, self.current_scroll_offset) operation::snap_to(SCROLLABLE, self.current_scroll_offset)
} }
Message::AlignmentChanged(alignment) => { Message::AlignmentChanged(alignment) => {
self.current_scroll_offset = scrollable::RelativeOffset::START; self.current_scroll_offset = scrollable::RelativeOffset::START;
self.anchor = alignment; self.anchor = alignment;
scrollable::snap_to(SCROLLABLE, self.current_scroll_offset) operation::snap_to(SCROLLABLE, self.current_scroll_offset)
} }
Message::ScrollbarWidthChanged(width) => { Message::ScrollbarWidthChanged(width) => {
self.scrollbar_width = width; self.scrollbar_width = width;
@ -86,12 +86,12 @@ impl ScrollableDemo {
Message::ScrollToBeginning => { Message::ScrollToBeginning => {
self.current_scroll_offset = scrollable::RelativeOffset::START; self.current_scroll_offset = scrollable::RelativeOffset::START;
scrollable::snap_to(SCROLLABLE, self.current_scroll_offset) operation::snap_to(SCROLLABLE, self.current_scroll_offset)
} }
Message::ScrollToEnd => { Message::ScrollToEnd => {
self.current_scroll_offset = scrollable::RelativeOffset::END; self.current_scroll_offset = scrollable::RelativeOffset::END;
scrollable::snap_to(SCROLLABLE, self.current_scroll_offset) operation::snap_to(SCROLLABLE, self.current_scroll_offset)
} }
Message::Scrolled(viewport) => { Message::Scrolled(viewport) => {
self.current_scroll_offset = viewport.relative_offset(); self.current_scroll_offset = viewport.relative_offset();

View file

@ -2,7 +2,7 @@ use iced::event::{self, Event};
use iced::keyboard; use iced::keyboard;
use iced::keyboard::key; use iced::keyboard::key;
use iced::widget::{ use iced::widget::{
self, button, center, column, pick_list, row, slider, text, text_input, button, center, column, operation, pick_list, row, slider, text, text_input,
}; };
use iced::{Center, Element, Fill, Subscription, Task}; use iced::{Center, Element, Fill, Subscription, Task};
@ -83,11 +83,11 @@ impl App {
key: keyboard::Key::Named(key::Named::Tab), key: keyboard::Key::Named(key::Named::Tab),
modifiers, modifiers,
.. ..
})) if modifiers.shift() => widget::focus_previous(), })) if modifiers.shift() => operation::focus_previous(),
Message::Event(Event::Keyboard(keyboard::Event::KeyPressed { Message::Event(Event::Keyboard(keyboard::Event::KeyPressed {
key: keyboard::Key::Named(key::Named::Tab), key: keyboard::Key::Named(key::Named::Tab),
.. ..
})) => widget::focus_next(), })) => operation::focus_next(),
Message::Event(_) => Task::none(), Message::Event(_) => Task::none(),
} }
} }

View file

@ -1,7 +1,7 @@
use iced::keyboard; use iced::keyboard;
use iced::widget::{ use iced::widget::{
self, Text, button, center, center_x, checkbox, column, keyed_column, row, self, Text, button, center, center_x, checkbox, column, keyed_column,
scrollable, text, text_input, operation, row, scrollable, text, text_input,
}; };
use iced::window; use iced::window;
use iced::{ use iced::{
@ -91,7 +91,7 @@ impl Todos {
_ => {} _ => {}
} }
text_input::focus("new-task") operation::focus("new-task")
} }
Todos::Loaded(state) => { Todos::Loaded(state) => {
let mut saved = false; let mut saved = false;
@ -132,8 +132,8 @@ impl Todos {
if should_focus { if should_focus {
let id = Task::text_input_id(i); let id = Task::text_input_id(i);
Command::batch(vec![ Command::batch(vec![
text_input::focus(id.clone()), operation::focus(id.clone()),
text_input::select_all(id), operation::select_all(id),
]) ])
} else { } else {
Command::none() Command::none()
@ -150,9 +150,9 @@ impl Todos {
} }
Message::TabPressed { shift } => { Message::TabPressed { shift } => {
if shift { if shift {
widget::focus_previous() operation::focus_previous()
} else { } else {
widget::focus_next() operation::focus_next()
} }
} }
Message::ToggleFullscreen(mode) => window::get_latest() Message::ToggleFullscreen(mode) => window::get_latest()

View file

@ -2,7 +2,7 @@ mod echo;
use iced::futures::stream; use iced::futures::stream;
use iced::widget::{ use iced::widget::{
self, button, center, column, row, scrollable, text, text_input, button, center, column, operation, row, scrollable, text, text_input,
}; };
use iced::{Center, Element, Fill, Subscription, Task, color}; use iced::{Center, Element, Fill, Subscription, Task, color};
@ -34,7 +34,7 @@ impl WebSocket {
new_message: String::new(), new_message: String::new(),
state: State::Disconnected, state: State::Disconnected,
}, },
widget::focus_next(), operation::focus_next(),
) )
} }
@ -73,10 +73,7 @@ impl WebSocket {
echo::Event::MessageReceived(message) => { echo::Event::MessageReceived(message) => {
self.messages.push(message); self.messages.push(message);
scrollable::snap_to( operation::snap_to_end(MESSAGE_LOG)
MESSAGE_LOG,
scrollable::RelativeOffset::END,
)
} }
}, },
Message::Server => Task::none(), Message::Server => Task::none(),

View file

@ -326,7 +326,7 @@
//! //!
//! Tasks can also be used to interact with the iced runtime. Some modules //! Tasks can also be used to interact with the iced runtime. Some modules
//! expose functions that create tasks for different purposes—like [changing //! expose functions that create tasks for different purposes—like [changing
//! window settings](window#functions), [focusing a widget](widget::focus_next), or //! window settings](window#functions), [focusing a widget](widget::operation::focus_next), or
//! [querying its visible bounds](widget::container::visible_bounds). //! [querying its visible bounds](widget::container::visible_bounds).
//! //!
//! Like futures and streams, tasks expose [a monadic interface](Task::then)—but they can also be //! Like futures and streams, tasks expose [a monadic interface](Task::then)—but they can also be

View file

@ -15,8 +15,6 @@ use crate::pick_list::{self, PickList};
use crate::progress_bar::{self, ProgressBar}; use crate::progress_bar::{self, ProgressBar};
use crate::radio::{self, Radio}; use crate::radio::{self, Radio};
use crate::rule::{self, Rule}; use crate::rule::{self, Rule};
use crate::runtime::Action;
use crate::runtime::task::{self, Task};
use crate::scrollable::{self, Scrollable}; use crate::scrollable::{self, Scrollable};
use crate::slider::{self, Slider}; use crate::slider::{self, Slider};
use crate::text::{self, Text}; use crate::text::{self, Text};
@ -2036,16 +2034,6 @@ where
crate::Shader::new(program) crate::Shader::new(program)
} }
/// 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()))
}
/// Creates a new [`MouseArea`]. /// Creates a new [`MouseArea`].
pub fn mouse_area<'a, Message, Theme, Renderer>( pub fn mouse_area<'a, Message, Theme, Renderer>(
widget: impl Into<Element<'a, Message, Theme, Renderer>>, widget: impl Into<Element<'a, Message, Theme, Renderer>>,

View file

@ -25,6 +25,7 @@ pub mod container;
pub mod float; pub mod float;
pub mod grid; pub mod grid;
pub mod keyed; pub mod keyed;
pub mod operation;
pub mod overlay; pub mod overlay;
pub mod pane_grid; pub mod pane_grid;
pub mod pick_list; pub mod pick_list;

88
widget/src/operation.rs Normal file
View file

@ -0,0 +1,88 @@
//! Change internal widget state.
use crate::Id;
use crate::core::widget::operation;
use crate::runtime::task;
use crate::runtime::{Action, Task};
pub use crate::core::widget::operation::scrollable::{
AbsoluteOffset, RelativeOffset,
};
/// Snaps the scrollable with the given [`Id`] to the provided [`RelativeOffset`].
pub fn snap_to<T>(id: impl Into<Id>, offset: RelativeOffset) -> Task<T> {
task::effect(Action::widget(operation::scrollable::snap_to(
id.into(),
offset,
)))
}
/// 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,
)))
}
/// Scrolls the scrollable with the given [`Id`] to the provided [`AbsoluteOffset`].
pub fn scroll_to<T>(id: impl Into<Id>, offset: AbsoluteOffset) -> Task<T> {
task::effect(Action::widget(operation::scrollable::scroll_to(
id.into(),
offset,
)))
}
/// 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,
)))
}
/// 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()))
}
/// 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())))
}
/// 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())))
}

View file

@ -37,8 +37,6 @@ use crate::core::{
Length, Padding, Pixels, Point, Rectangle, Shell, Size, Theme, Vector, Length, Padding, Pixels, Point, Rectangle, Shell, Size, Theme, Vector,
Widget, Widget,
}; };
use crate::runtime::Action;
use crate::runtime::task::{self, Task};
pub use operation::scrollable::{AbsoluteOffset, RelativeOffset}; pub use operation::scrollable::{AbsoluteOffset, RelativeOffset};
@ -1262,42 +1260,6 @@ where
} }
} }
/// Produces a [`Task`] that snaps the [`Scrollable`] with the given [`widget::Id`]
/// to the provided [`RelativeOffset`].
pub fn snap_to<T>(
id: impl Into<widget::Id>,
offset: RelativeOffset,
) -> Task<T> {
task::effect(Action::widget(operation::scrollable::snap_to(
id.into(),
offset,
)))
}
/// Produces a [`Task`] that scrolls the [`Scrollable`] with the given [`widget::Id`]
/// to the provided [`AbsoluteOffset`].
pub fn scroll_to<T>(
id: impl Into<widget::Id>,
offset: AbsoluteOffset,
) -> Task<T> {
task::effect(Action::widget(operation::scrollable::scroll_to(
id.into(),
offset,
)))
}
/// Produces a [`Task`] that scrolls the [`Scrollable`] with the given [`widget::Id`]
/// by the provided [`AbsoluteOffset`].
pub fn scroll_by<T>(
id: impl Into<widget::Id>,
offset: AbsoluteOffset,
) -> Task<T> {
task::effect(Action::widget(operation::scrollable::scroll_by(
id.into(),
offset,
)))
}
fn notify_scroll<Message>( fn notify_scroll<Message>(
state: &mut State, state: &mut State,
on_scroll: &Option<Box<dyn Fn(Viewport) -> Message + '_>>, on_scroll: &Option<Box<dyn Fn(Viewport) -> Message + '_>>,

View file

@ -61,8 +61,6 @@ use crate::core::{
Length, Padding, Pixels, Point, Rectangle, Shell, Size, Theme, Vector, Length, Padding, Pixels, Point, Rectangle, Shell, Size, Theme, Vector,
Widget, Widget,
}; };
use crate::runtime::Action;
use crate::runtime::task::{self, Task};
/// A field that can be filled with text. /// A field that can be filled with text.
/// ///
@ -1445,49 +1443,6 @@ pub enum Side {
Right, Right,
} }
/// Produces a [`Task`] that returns whether the [`TextInput`] with the given [`widget::Id`] is focused or not.
pub fn is_focused(id: impl Into<widget::Id>) -> Task<bool> {
task::widget(operation::focusable::is_focused(id.into()))
}
/// Produces a [`Task`] that focuses the [`TextInput`] with the given [`widget::Id`].
pub fn focus<T>(id: impl Into<widget::Id>) -> Task<T> {
task::effect(Action::widget(operation::focusable::focus(id.into())))
}
/// Produces a [`Task`] that moves the cursor of the [`TextInput`] with the given [`widget::Id`] to the
/// end.
pub fn move_cursor_to_end<T>(id: impl Into<widget::Id>) -> Task<T> {
task::effect(Action::widget(operation::text_input::move_cursor_to_end(
id.into(),
)))
}
/// Produces a [`Task`] that moves the cursor of the [`TextInput`] with the given [`widget::Id`] to the
/// front.
pub fn move_cursor_to_front<T>(id: impl Into<widget::Id>) -> Task<T> {
task::effect(Action::widget(operation::text_input::move_cursor_to_front(
id.into(),
)))
}
/// Produces a [`Task`] that moves the cursor of the [`TextInput`] with the given [`widget::Id`] to the
/// provided position.
pub fn move_cursor_to<T>(
id: impl Into<widget::Id>,
position: usize,
) -> Task<T> {
task::effect(Action::widget(operation::text_input::move_cursor_to(
id.into(),
position,
)))
}
/// Produces a [`Task`] that selects all the content of the [`TextInput`] with the given [`widget::Id`].
pub fn select_all<T>(id: impl Into<widget::Id>) -> Task<T> {
task::effect(Action::widget(operation::text_input::select_all(id.into())))
}
/// The state of a [`TextInput`]. /// The state of a [`TextInput`].
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
pub struct State<P: text::Paragraph> { pub struct State<P: text::Paragraph> {