From 1448c5bfa5d0977e54670bb8c640ba186bb13167 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Wed, 18 Sep 2024 20:30:14 +0200
Subject: Implement some `From` traits for `text_input::Id`

---
 core/src/window/id.rs             |  8 +++++++-
 examples/multi_window/src/main.rs |  6 ++----
 examples/todos/Cargo.toml         |  1 -
 examples/todos/src/main.rs        |  7 ++-----
 widget/src/text_input.rs          | 39 +++++++++++++++++++++++++++------------
 5 files changed, 38 insertions(+), 23 deletions(-)

diff --git a/core/src/window/id.rs b/core/src/window/id.rs
index 1a75fa27..5d5a817e 100644
--- a/core/src/window/id.rs
+++ b/core/src/window/id.rs
@@ -1,5 +1,5 @@
+use std::fmt;
 use std::hash::Hash;
-
 use std::sync::atomic::{self, AtomicU64};
 
 /// The id of the window.
@@ -14,3 +14,9 @@ impl Id {
         Id(COUNT.fetch_add(1, atomic::Ordering::Relaxed))
     }
 }
+
+impl fmt::Display for Id {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.0.fmt(f)
+    }
+}
diff --git a/examples/multi_window/src/main.rs b/examples/multi_window/src/main.rs
index ab09116e..b43a627a 100644
--- a/examples/multi_window/src/main.rs
+++ b/examples/multi_window/src/main.rs
@@ -25,7 +25,6 @@ struct Window {
     scale_input: String,
     current_scale: f64,
     theme: Theme,
-    input_id: iced::widget::text_input::Id,
 }
 
 #[derive(Debug, Clone)]
@@ -86,7 +85,7 @@ impl Example {
             }
             Message::WindowOpened(id) => {
                 let window = Window::new(self.windows.len() + 1);
-                let focus_input = text_input::focus(window.input_id.clone());
+                let focus_input = text_input::focus(format!("input-{id}"));
 
                 self.windows.insert(id, window);
 
@@ -163,7 +162,6 @@ impl Window {
             scale_input: "1.0".to_string(),
             current_scale: 1.0,
             theme: Theme::ALL[count % Theme::ALL.len()].clone(),
-            input_id: text_input::Id::unique(),
         }
     }
 
@@ -182,7 +180,7 @@ impl Window {
             text("Window title:"),
             text_input("Window Title", &self.title)
                 .on_input(move |msg| { Message::TitleChanged(id, msg) })
-                .id(self.input_id.clone())
+                .id(format!("input-{id}"))
         ];
 
         let new_window_button =
diff --git a/examples/todos/Cargo.toml b/examples/todos/Cargo.toml
index 3c62bfbc..0d72be86 100644
--- a/examples/todos/Cargo.toml
+++ b/examples/todos/Cargo.toml
@@ -9,7 +9,6 @@ publish = false
 iced.workspace = true
 iced.features = ["async-std", "debug"]
 
-once_cell.workspace = true
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
 uuid = { version = "1.0", features = ["v4", "fast-rng", "serde"] }
diff --git a/examples/todos/src/main.rs b/examples/todos/src/main.rs
index a5f7b36a..25e3ead2 100644
--- a/examples/todos/src/main.rs
+++ b/examples/todos/src/main.rs
@@ -6,12 +6,9 @@ use iced::widget::{
 use iced::window;
 use iced::{Center, Element, Fill, Font, Subscription, Task as Command};
 
-use once_cell::sync::Lazy;
 use serde::{Deserialize, Serialize};
 use uuid::Uuid;
 
-static INPUT_ID: Lazy<text_input::Id> = Lazy::new(text_input::Id::unique);
-
 pub fn main() -> iced::Result {
     #[cfg(not(target_arch = "wasm32"))]
     tracing_subscriber::fmt::init();
@@ -85,7 +82,7 @@ impl Todos {
                     _ => {}
                 }
 
-                text_input::focus(INPUT_ID.clone())
+                text_input::focus("new-task")
             }
             Todos::Loaded(state) => {
                 let mut saved = false;
@@ -198,7 +195,7 @@ impl Todos {
                     .align_x(Center);
 
                 let input = text_input("What needs to be done?", input_value)
-                    .id(INPUT_ID.clone())
+                    .id("new-task")
                     .on_input(Message::InputChanged)
                     .on_submit(Message::CreateTask)
                     .padding(15)
diff --git a/widget/src/text_input.rs b/widget/src/text_input.rs
index d5ede524..3032dd13 100644
--- a/widget/src/text_input.rs
+++ b/widget/src/text_input.rs
@@ -114,8 +114,8 @@ where
     }
 
     /// Sets the [`Id`] of the [`TextInput`].
-    pub fn id(mut self, id: Id) -> Self {
-        self.id = Some(id);
+    pub fn id(mut self, id: impl Into<Id>) -> Self {
+        self.id = Some(id.into());
         self
     }
 
@@ -1226,38 +1226,53 @@ impl From<Id> for widget::Id {
     }
 }
 
+impl From<&'static str> for Id {
+    fn from(id: &'static str) -> Self {
+        Self::new(id)
+    }
+}
+
+impl From<String> for Id {
+    fn from(id: String) -> Self {
+        Self::new(id)
+    }
+}
+
 /// Produces a [`Task`] that focuses the [`TextInput`] with the given [`Id`].
-pub fn focus<T>(id: Id) -> Task<T> {
-    task::effect(Action::widget(operation::focusable::focus(id.0)))
+pub fn focus<T>(id: impl Into<Id>) -> Task<T> {
+    task::effect(Action::widget(operation::focusable::focus(id.into().0)))
 }
 
 /// Produces a [`Task`] that moves the cursor of the [`TextInput`] with the given [`Id`] to the
 /// end.
-pub fn move_cursor_to_end<T>(id: Id) -> Task<T> {
+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.0,
+        id.into().0,
     )))
 }
 
 /// Produces a [`Task`] that moves the cursor of the [`TextInput`] with the given [`Id`] to the
 /// front.
-pub fn move_cursor_to_front<T>(id: Id) -> Task<T> {
+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.0,
+        id.into().0,
     )))
 }
 
 /// Produces a [`Task`] that moves the cursor of the [`TextInput`] with the given [`Id`] to the
 /// provided position.
-pub fn move_cursor_to<T>(id: Id, position: usize) -> Task<T> {
+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.0, position,
+        id.into().0,
+        position,
     )))
 }
 
 /// Produces a [`Task`] that selects all the content of the [`TextInput`] with the given [`Id`].
-pub fn select_all<T>(id: Id) -> Task<T> {
-    task::effect(Action::widget(operation::text_input::select_all(id.0)))
+pub fn select_all<T>(id: impl Into<Id>) -> Task<T> {
+    task::effect(Action::widget(operation::text_input::select_all(
+        id.into().0,
+    )))
 }
 
 /// The state of a [`TextInput`].
-- 
cgit