diff options
Diffstat (limited to 'pure/src/widget/text_input.rs')
-rw-r--r-- | pure/src/widget/text_input.rs | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/pure/src/widget/text_input.rs b/pure/src/widget/text_input.rs new file mode 100644 index 00000000..d6041d7f --- /dev/null +++ b/pure/src/widget/text_input.rs @@ -0,0 +1,241 @@ +use crate::widget::tree::{self, Tree}; +use crate::{Element, Widget}; + +use iced_native::event::{self, Event}; +use iced_native::layout::{self, Layout}; +use iced_native::mouse; +use iced_native::renderer; +use iced_native::text; +use iced_native::widget::text_input; +use iced_native::{Clipboard, Length, Padding, Point, Rectangle, Shell}; + +pub use iced_style::text_input::{Style, StyleSheet}; + +/// A field that can be filled with text. +/// +/// # Example +/// ``` +/// # use iced_native::renderer::Null; +/// # use iced_native::widget::text_input; +/// # +/// # pub type TextInput<'a, Message> = iced_native::widget::TextInput<'a, Message, Null>; +/// #[derive(Debug, Clone)] +/// enum Message { +/// TextInputChanged(String), +/// } +/// +/// let mut state = text_input::State::new(); +/// let value = "Some text"; +/// +/// let input = TextInput::new( +/// &mut state, +/// "This is the placeholder...", +/// value, +/// Message::TextInputChanged, +/// ) +/// .padding(10); +/// ``` +///  +#[allow(missing_debug_implementations)] +pub struct TextInput<'a, Message, Renderer: text::Renderer> { + placeholder: String, + value: text_input::Value, + is_secure: bool, + font: Renderer::Font, + width: Length, + padding: Padding, + size: Option<u16>, + on_change: Box<dyn Fn(String) -> Message + 'a>, + on_submit: Option<Message>, + style_sheet: Box<dyn StyleSheet + 'a>, +} + +impl<'a, Message, Renderer> TextInput<'a, Message, Renderer> +where + Message: Clone, + Renderer: text::Renderer, +{ + /// Creates a new [`TextInput`]. + /// + /// It expects: + /// - some [`State`] + /// - a placeholder + /// - the current value + /// - a function that produces a message when the [`TextInput`] changes + pub fn new<F>(placeholder: &str, value: &str, on_change: F) -> Self + where + F: 'a + Fn(String) -> Message, + { + TextInput { + placeholder: String::from(placeholder), + value: text_input::Value::new(value), + is_secure: false, + font: Default::default(), + width: Length::Fill, + padding: Padding::ZERO, + size: None, + on_change: Box::new(on_change), + on_submit: None, + style_sheet: Default::default(), + } + } + + /// Converts the [`TextInput`] into a secure password input. + pub fn password(mut self) -> Self { + self.is_secure = true; + self + } + + /// Sets the [`Font`] of the [`Text`]. + /// + /// [`Font`]: crate::widget::text::Renderer::Font + /// [`Text`]: crate::widget::Text + pub fn font(mut self, font: Renderer::Font) -> Self { + self.font = font; + self + } + /// Sets the width of the [`TextInput`]. + pub fn width(mut self, width: Length) -> Self { + self.width = width; + self + } + + /// Sets the [`Padding`] of the [`TextInput`]. + pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self { + self.padding = padding.into(); + self + } + + /// Sets the text size of the [`TextInput`]. + pub fn size(mut self, size: u16) -> Self { + self.size = Some(size); + self + } + + /// Sets the message that should be produced when the [`TextInput`] is + /// focused and the enter key is pressed. + pub fn on_submit(mut self, message: Message) -> Self { + self.on_submit = Some(message); + self + } + + /// Sets the style of the [`TextInput`]. + pub fn style( + mut self, + style_sheet: impl Into<Box<dyn StyleSheet + 'a>>, + ) -> Self { + self.style_sheet = style_sheet.into(); + self + } +} + +impl<'a, Message, Renderer> Widget<Message, Renderer> + for TextInput<'a, Message, Renderer> +where + Message: Clone, + Renderer: iced_native::text::Renderer, +{ + fn tag(&self) -> tree::Tag { + tree::Tag::of::<text_input::State>() + } + + fn state(&self) -> tree::State { + tree::State::new(text_input::State::new()) + } + + fn width(&self) -> Length { + self.width + } + + fn height(&self) -> Length { + Length::Shrink + } + + fn layout( + &self, + renderer: &Renderer, + limits: &layout::Limits, + ) -> layout::Node { + text_input::layout( + renderer, + limits, + self.width, + self.padding, + self.size, + ) + } + + fn on_event( + &mut self, + tree: &mut Tree, + event: Event, + layout: Layout<'_>, + cursor_position: Point, + renderer: &Renderer, + clipboard: &mut dyn Clipboard, + shell: &mut Shell<'_, Message>, + ) -> event::Status { + text_input::update( + event, + layout, + cursor_position, + renderer, + clipboard, + shell, + &mut self.value, + self.size, + &self.font, + self.is_secure, + self.on_change.as_ref(), + &self.on_submit, + || tree.state.downcast_mut::<text_input::State>(), + ) + } + + fn draw( + &self, + tree: &Tree, + renderer: &mut Renderer, + _style: &renderer::Style, + layout: Layout<'_>, + cursor_position: Point, + _viewport: &Rectangle, + ) { + text_input::draw( + renderer, + layout, + cursor_position, + tree.state.downcast_ref::<text_input::State>(), + &self.value, + &self.placeholder, + self.size, + &self.font, + self.is_secure, + self.style_sheet.as_ref(), + ) + } + + fn mouse_interaction( + &self, + _state: &Tree, + layout: Layout<'_>, + cursor_position: Point, + _viewport: &Rectangle, + _renderer: &Renderer, + ) -> mouse::Interaction { + text_input::mouse_interaction(layout, cursor_position) + } +} + +impl<'a, Message, Renderer> From<TextInput<'a, Message, Renderer>> + for Element<'a, Message, Renderer> +where + Message: 'a + Clone, + Renderer: 'a + text::Renderer, +{ + fn from( + text_input: TextInput<'a, Message, Renderer>, + ) -> Element<'a, Message, Renderer> { + Element::new(text_input) + } +} |