From 496cb8846ffc9dbb21534f2669fbd858abaea028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Tue, 29 Oct 2024 21:49:47 +0100 Subject: [PATCH] Add `.id` method and `text_editor::focus` task --- examples/editor/src/main.rs | 8 ++++-- widget/src/text_editor.rs | 57 ++++++++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/examples/editor/src/main.rs b/examples/editor/src/main.rs index d55f9bdfec..c6b42ef0a1 100644 --- a/examples/editor/src/main.rs +++ b/examples/editor/src/main.rs @@ -1,7 +1,7 @@ use iced::highlighter; use iced::keyboard; use iced::widget::{ - self, button, column, container, horizontal_space, pick_list, row, text, + button, column, container, horizontal_space, pick_list, row, text, text_editor, toggler, tooltip, }; use iced::{Center, Element, Fill, Font, Task, Theme}; @@ -20,6 +20,7 @@ pub fn main() -> iced::Result { } struct Editor { + editor_id: text_editor::Id, file: Option, content: text_editor::Content, theme: highlighter::Theme, @@ -42,8 +43,10 @@ enum Message { impl Editor { fn new() -> (Self, Task) { + let id = text_editor::Id::unique(); ( Self { + editor_id: id.clone(), file: None, content: text_editor::Content::new(), theme: highlighter::Theme::SolarizedDark, @@ -59,7 +62,7 @@ impl Editor { )), Message::FileOpened, ), - widget::focus_next(), + text_editor::focus(id), ]), ) } @@ -188,6 +191,7 @@ impl Editor { column![ controls, text_editor(&self.content) + .id(self.editor_id.clone()) .height(Fill) .on_action(Message::ActionPerformed) .wrapping(if self.word_wrap { diff --git a/widget/src/text_editor.rs b/widget/src/text_editor.rs index a298252a6c..2533ad8a83 100644 --- a/widget/src/text_editor.rs +++ b/widget/src/text_editor.rs @@ -51,6 +51,9 @@ use crate::core::{ Rectangle, Shell, Size, SmolStr, Theme, Vector, }; +use crate::runtime::task::{self, Task}; +use crate::runtime::Action as RuntimeAction; + use std::cell::RefCell; use std::fmt; use std::ops::DerefMut; @@ -103,6 +106,7 @@ pub struct TextEditor< Theme: Catalog, Renderer: text::Renderer, { + id: Option, content: &'a Content, placeholder: Option>, font: Option, @@ -131,6 +135,7 @@ where /// Creates new [`TextEditor`] with the given [`Content`]. pub fn new(content: &'a Content) -> Self { Self { + id: None, content, placeholder: None, font: None, @@ -149,6 +154,12 @@ where }, } } + + /// Sets the [`Id`] of the [`TextEditor`]. + pub fn id(mut self, id: impl Into) -> Self { + self.id = Some(id.into()); + self + } } impl<'a, Highlighter, Message, Theme, Renderer> @@ -256,6 +267,7 @@ where ) -> highlighter::Format, ) -> TextEditor<'a, H, Message, Theme, Renderer> { TextEditor { + id: self.id, content: self.content, placeholder: self.placeholder, font: self.font, @@ -958,7 +970,7 @@ where ) { let state = tree.state.downcast_mut::>(); - operation.focusable(state, None); + operation.focusable(state, self.id.as_ref().map(|id| &id.0)); } } @@ -978,6 +990,49 @@ where } } +/// The identifier of a [`TextEditor`]. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Id(widget::Id); + +impl Id { + /// Creates a custom [`Id`]. + pub fn new(id: impl Into>) -> Self { + Self(widget::Id::new(id)) + } + + /// Creates a unique [`Id`]. + /// + /// This function produces a different [`Id`] every time it is called. + pub fn unique() -> Self { + Self(widget::Id::unique()) + } +} + +impl From for widget::Id { + fn from(id: Id) -> Self { + id.0 + } +} + +impl From<&'static str> for Id { + fn from(id: &'static str) -> Self { + Self::new(id) + } +} + +impl From for Id { + fn from(id: String) -> Self { + Self::new(id) + } +} + +/// Produces a [`Task`] that focuses the [`TextEditor`] with the given [`Id`]. +pub fn focus(id: impl Into) -> Task { + task::effect(RuntimeAction::widget(operation::focusable::focus( + id.into().0, + ))) +} + /// A binding to an action in the [`TextEditor`]. #[derive(Debug, Clone, PartialEq)] pub enum Binding {