diff options
author | 2023-02-13 11:38:05 +0100 | |
---|---|---|
committer | 2023-04-11 05:11:19 +0200 | |
commit | 7b369842959511f17d5c27941fd0308484bff8ea (patch) | |
tree | db4bcb9ce1f8770e00a51743e397ad4f89b0be60 | |
parent | 931b30dc5ac17b65b1fb996cb4b87fc946c410e3 (diff) | |
download | iced-7b369842959511f17d5c27941fd0308484bff8ea.tar.gz iced-7b369842959511f17d5c27941fd0308484bff8ea.tar.bz2 iced-7b369842959511f17d5c27941fd0308484bff8ea.zip |
feat: added handle to text_input
-rw-r--r-- | examples/text_input/Cargo.toml | 9 | ||||
-rw-r--r-- | examples/text_input/README.md | 10 | ||||
-rw-r--r-- | examples/text_input/fonts/icons.ttf | bin | 0 -> 1612 bytes | |||
-rw-r--r-- | examples/text_input/src/main.rs | 93 | ||||
-rw-r--r-- | native/src/widget/text_input.rs | 119 | ||||
-rw-r--r-- | src/widget.rs | 2 | ||||
-rw-r--r-- | style/src/text_input.rs | 2 | ||||
-rw-r--r-- | style/src/theme.rs | 3 |
8 files changed, 236 insertions, 2 deletions
diff --git a/examples/text_input/Cargo.toml b/examples/text_input/Cargo.toml new file mode 100644 index 00000000..5937ef8e --- /dev/null +++ b/examples/text_input/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "text_input" +version = "0.1.0" +authors = ["Casper Rogild Storm<casper@rogildstorm.com>"] +edition = "2021" +publish = false + +[dependencies] +iced = { path = "../..", features = ["debug"] } diff --git a/examples/text_input/README.md b/examples/text_input/README.md new file mode 100644 index 00000000..2b2d8059 --- /dev/null +++ b/examples/text_input/README.md @@ -0,0 +1,10 @@ +## TextInput + +A `TextInput` is a field that can be filled with text. + +You can run it with `cargo run`: +``` +cargo run --package text_input +``` + +[`main`]: src/main.rs diff --git a/examples/text_input/fonts/icons.ttf b/examples/text_input/fonts/icons.ttf Binary files differnew file mode 100644 index 00000000..bfe8a24b --- /dev/null +++ b/examples/text_input/fonts/icons.ttf diff --git a/examples/text_input/src/main.rs b/examples/text_input/src/main.rs new file mode 100644 index 00000000..b25ed7e1 --- /dev/null +++ b/examples/text_input/src/main.rs @@ -0,0 +1,93 @@ +use iced::widget::{checkbox, column, container, text_input}; +use iced::{Element, Font, Length, Sandbox, Settings}; + +const ICON_FONT: Font = Font::External { + name: "Icons", + bytes: include_bytes!("../fonts/icons.ttf"), +}; + +pub fn main() -> iced::Result { + Example::run(Settings::default()) +} + +#[derive(Default)] +struct Example { + value: String, + is_showing_handle: bool, +} + +#[derive(Debug, Clone)] +enum Message { + Changed(String), + ToggleHandle(bool), +} + +impl Sandbox for Example { + type Message = Message; + + fn new() -> Self { + Self::default() + } + + fn title(&self) -> String { + String::from("Text Input - Iced") + } + + fn update(&mut self, message: Message) { + match message { + Message::Changed(value) => self.value = value, + Message::ToggleHandle(_) => { + self.is_showing_handle = !self.is_showing_handle + } + } + } + + fn view(&self) -> Element<Message> { + let checkbox = + checkbox("Handle", self.is_showing_handle, Message::ToggleHandle) + .spacing(5) + .text_size(16); + + let mut text_input = + text_input("Placeholder", self.value.as_str(), Message::Changed); + + if self.is_showing_handle { + text_input = text_input.handle(text_input::Handle { + font: ICON_FONT, + text: String::from('\u{e900}'), + size: Some(18), + position: text_input::HandlePosition::Right, + }); + } + + let content = column!["What is blazing fast?", text_input, checkbox] + .width(Length::Units(200)) + .spacing(10); + + container(content) + .width(Length::Fill) + .height(Length::Fill) + .center_x() + .center_y() + .into() + } + + fn theme(&self) -> iced::Theme { + iced::Theme::default() + } + + fn style(&self) -> iced::theme::Application { + iced::theme::Application::default() + } + + fn scale_factor(&self) -> f64 { + 1.0 + } + + fn run(settings: Settings<()>) -> Result<(), iced::Error> + where + Self: 'static + Sized, + { + <Self as iced::Application>::run(settings) + } +} diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs index ee0473ea..7696da99 100644 --- a/native/src/widget/text_input.rs +++ b/native/src/widget/text_input.rs @@ -31,6 +31,47 @@ use crate::{ pub use iced_style::text_input::{Appearance, StyleSheet}; +/// The position of the [`Handle`]. +#[derive(Clone, Default, Debug)] +pub enum HandlePosition { + /// Position the handle to the left. + Left, + /// Position the handle to the left. + /// + /// This is the default. + #[default] + Right, +} + +/// The content of the [`Handle`]. +#[derive(Clone)] +pub struct Handle<Renderer> +where + Renderer: text::Renderer, +{ + /// Font that will be used to display the `text`. + pub font: Renderer::Font, + /// Text that will be shown. + pub text: String, + /// Font size of the content. + pub size: Option<u16>, + /// Position of the handle. + pub position: HandlePosition, +} + +impl<Renderer> std::fmt::Debug for Handle<Renderer> +where + Renderer: text::Renderer, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Handle") + .field("text", &self.text) + .field("size", &self.size) + .field("position", &self.position) + .finish() + } +} + /// A field that can be filled with text. /// /// # Example @@ -68,6 +109,7 @@ where on_change: Box<dyn Fn(String) -> Message + 'a>, on_paste: Option<Box<dyn Fn(String) -> Message + 'a>>, on_submit: Option<Message>, + handle: Option<Handle<Renderer>>, style: <Renderer::Theme as StyleSheet>::Style, } @@ -99,6 +141,7 @@ where on_change: Box::new(on_change), on_paste: None, on_submit: None, + handle: None, style: Default::default(), } } @@ -132,6 +175,13 @@ where self.font = font; self } + + /// Sets the [`Handle`] of the [`TextInput`]. + pub fn handle(mut self, handle: Handle<Renderer>) -> Self { + self.handle = Some(handle); + self + } + /// Sets the width of the [`TextInput`]. pub fn width(mut self, width: impl Into<Length>) -> Self { self.width = width.into(); @@ -188,8 +238,10 @@ where value.unwrap_or(&self.value), &self.placeholder, self.size, + self.padding, &self.font, self.is_secure, + self.handle.as_ref(), &self.style, ) } @@ -286,8 +338,10 @@ where &self.value, &self.placeholder, self.size, + self.padding, &self.font, self.is_secure, + self.handle.as_ref(), &self.style, ) } @@ -812,8 +866,10 @@ pub fn draw<Renderer>( value: &Value, placeholder: &str, size: Option<f32>, + padding: Padding, font: &Renderer::Font, is_secure: bool, + handle: Option<&Handle<Renderer>>, style: &<Renderer::Theme as StyleSheet>::Style, ) where Renderer: text::Renderer, @@ -823,7 +879,37 @@ pub fn draw<Renderer>( let value = secure_value.as_ref().unwrap_or(value); let bounds = layout.bounds(); - let text_bounds = layout.children().next().unwrap().bounds(); + let text_bounds = { + let bounds = layout.children().next().unwrap().bounds(); + if let Some(handle) = handle { + let Handle { + font, + size, + text, + position, + } = handle; + + let padding = f32::from(padding.horizontal()); + let size = size.unwrap_or_else(|| renderer.default_size()); + let width = + renderer.measure_width(text.as_str(), size, font.clone()); + + match position { + HandlePosition::Left => Rectangle { + x: bounds.x + (width + padding), + width: bounds.width - (width + padding), + ..bounds + }, + HandlePosition::Right => Rectangle { + x: bounds.x, + width: bounds.width - (width + padding), + ..bounds + }, + } + } else { + bounds + } + }; let is_mouse_over = bounds.contains(cursor_position); @@ -845,6 +931,37 @@ pub fn draw<Renderer>( appearance.background, ); + if let Some(handle) = handle { + let Handle { + size, + font, + text, + position, + } = handle; + + let padding = f32::from(padding.horizontal()); + let size = size.unwrap_or_else(|| renderer.default_size()); + let width = renderer.measure_width(text.as_str(), size, font.clone()); + + renderer.fill_text(Text { + content: text, + size: f32::from(size), + font: font.clone(), + color: appearance.handle_color, + bounds: Rectangle { + x: match position { + HandlePosition::Left => bounds.x + width + padding, + HandlePosition::Right => bounds.x + bounds.width - padding, + }, + y: bounds.center_y() - f32::from(size) / 2.0, + height: f32::from(size), + ..bounds + }, + horizontal_alignment: alignment::Horizontal::Right, + vertical_alignment: alignment::Vertical::Top, + }); + } + let text = value.to_string(); let size = size.unwrap_or_else(|| renderer.default_size()); diff --git a/src/widget.rs b/src/widget.rs index e2b0537e..948456d3 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -124,7 +124,7 @@ pub mod text_input { //! Display fields that can be filled with text. pub use iced_native::widget::text_input::{ focus, move_cursor_to, move_cursor_to_end, move_cursor_to_front, - select_all, Appearance, Id, StyleSheet, + select_all, Appearance, Handle, HandlePosition, Id, StyleSheet, }; /// A field that can be filled with text. diff --git a/style/src/text_input.rs b/style/src/text_input.rs index d97016dc..5e703e61 100644 --- a/style/src/text_input.rs +++ b/style/src/text_input.rs @@ -12,6 +12,8 @@ pub struct Appearance { pub border_width: f32, /// The border [`Color`] of the text input. pub border_color: Color, + /// The handle [`Color`] of the text input. + pub handle_color: Color, } /// A set of rules that dictate the style of a text input. diff --git a/style/src/theme.rs b/style/src/theme.rs index 0ebd82a4..de46d7d4 100644 --- a/style/src/theme.rs +++ b/style/src/theme.rs @@ -1028,6 +1028,7 @@ impl text_input::StyleSheet for Theme { border_radius: 2.0, border_width: 1.0, border_color: palette.background.strong.color, + handle_color: palette.background.weak.text, } } @@ -1043,6 +1044,7 @@ impl text_input::StyleSheet for Theme { border_radius: 2.0, border_width: 1.0, border_color: palette.background.base.text, + handle_color: palette.background.weak.text, } } @@ -1058,6 +1060,7 @@ impl text_input::StyleSheet for Theme { border_radius: 2.0, border_width: 1.0, border_color: palette.primary.strong.color, + handle_color: palette.primary.weak.text, } } |