From 63cd0fd8eb1eebae8de7d5141c846fc4ea55d702 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 30 Oct 2019 03:31:07 +0100 Subject: Draft `TextInput` widget structure Also started a `todos` example to showcase it! --- examples/todos.rs | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 examples/todos.rs (limited to 'examples') diff --git a/examples/todos.rs b/examples/todos.rs new file mode 100644 index 00000000..6a5d5e85 --- /dev/null +++ b/examples/todos.rs @@ -0,0 +1,69 @@ +use iced::{ + text::HorizontalAlignment, text_input, Align, Application, Color, Column, + Element, Justify, Length, Text, TextInput, +}; + +pub fn main() { + Todos::default().run() +} + +#[derive(Default)] +struct Todos { + input: text_input::State, + input_value: String, +} + +#[derive(Debug, Clone)] +pub enum Message { + InputChanged(String), + CreateTask, +} + +impl Application for Todos { + type Message = Message; + + fn update(&mut self, message: Message) { + match message { + Message::InputChanged(value) => { + self.input_value = value; + } + Message::CreateTask => {} + } + } + + fn view(&mut self) -> Element { + let title = Text::new("todos") + .size(100) + .color(GRAY) + .horizontal_alignment(HorizontalAlignment::Center); + + let input = TextInput::new( + &mut self.input, + "What needs to be done?", + &self.input_value, + Message::InputChanged, + ) + .padding(15) + .size(30) + .on_submit(Message::CreateTask); + + Column::new() + .max_width(Length::Units(800)) + .height(Length::Fill) + .align_self(Align::Center) + .justify_content(Justify::Center) + .spacing(20) + .padding(20) + .push(title) + .push(input) + .into() + } +} + +// Colors +const GRAY: Color = Color { + r: 0.5, + g: 0.5, + b: 0.5, + a: 1.0, +}; -- cgit From 1505d8f9413c3b0371b9735c3e2a465c1ec0ae92 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 30 Oct 2019 05:00:59 +0100 Subject: Implement task addition in `todos` example --- examples/todos.rs | 63 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 8 deletions(-) (limited to 'examples') diff --git a/examples/todos.rs b/examples/todos.rs index 6a5d5e85..6189c8db 100644 --- a/examples/todos.rs +++ b/examples/todos.rs @@ -1,22 +1,45 @@ use iced::{ - text::HorizontalAlignment, text_input, Align, Application, Color, Column, - Element, Justify, Length, Text, TextInput, + scrollable, text::HorizontalAlignment, text_input, Align, Application, + Checkbox, Color, Column, Element, Length, Scrollable, Text, TextInput, }; pub fn main() { Todos::default().run() } -#[derive(Default)] +#[derive(Debug, Default)] struct Todos { + scroll: scrollable::State, input: text_input::State, input_value: String, + tasks: Vec, +} + +#[derive(Debug)] +struct Task { + description: String, + completed: bool, +} + +impl Task { + fn new(description: String) -> Self { + Task { + description, + completed: false, + } + } + + fn view(&mut self) -> Element { + Checkbox::new(self.completed, &self.description, |checked| checked) + .into() + } } #[derive(Debug, Clone)] pub enum Message { InputChanged(String), CreateTask, + TaskChanged(usize, bool), } impl Application for Todos { @@ -27,8 +50,20 @@ impl Application for Todos { Message::InputChanged(value) => { self.input_value = value; } - Message::CreateTask => {} + Message::CreateTask => { + if !self.input_value.is_empty() { + self.tasks.push(Task::new(self.input_value.clone())); + self.input_value = String::new(); + } + } + Message::TaskChanged(i, completed) => { + if let Some(task) = self.tasks.get_mut(i) { + task.completed = completed; + } + } } + + dbg!(self); } fn view(&mut self) -> Element { @@ -47,15 +82,27 @@ impl Application for Todos { .size(30) .on_submit(Message::CreateTask); - Column::new() + let tasks = self.tasks.iter_mut().enumerate().fold( + Column::new().spacing(20), + |column, (i, task)| { + column.push( + task.view() + .map(move |state| Message::TaskChanged(i, state)), + ) + }, + ); + + let content = Column::new() .max_width(Length::Units(800)) - .height(Length::Fill) .align_self(Align::Center) - .justify_content(Justify::Center) .spacing(20) - .padding(20) .push(title) .push(input) + .push(tasks); + + Scrollable::new(&mut self.scroll) + .padding(40) + .push(content) .into() } } -- cgit From 51a0e99097f9ecb63eeb7f2ea7c38089977eb4d0 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 31 Oct 2019 03:50:40 +0100 Subject: Implement cursor movement in `TextInput` --- examples/todos.rs | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'examples') diff --git a/examples/todos.rs b/examples/todos.rs index 6189c8db..9581262a 100644 --- a/examples/todos.rs +++ b/examples/todos.rs @@ -15,26 +15,6 @@ struct Todos { tasks: Vec, } -#[derive(Debug)] -struct Task { - description: String, - completed: bool, -} - -impl Task { - fn new(description: String) -> Self { - Task { - description, - completed: false, - } - } - - fn view(&mut self) -> Element { - Checkbox::new(self.completed, &self.description, |checked| checked) - .into() - } -} - #[derive(Debug, Clone)] pub enum Message { InputChanged(String), @@ -107,6 +87,26 @@ impl Application for Todos { } } +#[derive(Debug)] +struct Task { + description: String, + completed: bool, +} + +impl Task { + fn new(description: String) -> Self { + Task { + description, + completed: false, + } + } + + fn view(&mut self) -> Element { + Checkbox::new(self.completed, &self.description, |checked| checked) + .into() + } +} + // Colors const GRAY: Color = Color { r: 0.5, -- cgit From f3baae92282566ccb6ff3689a08fcaa907430ef7 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 2 Nov 2019 02:17:00 +0100 Subject: Add text input section to `tour` --- examples/tour.rs | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/tour.rs b/examples/tour.rs index 7d8e4e3e..c2b3e645 100644 --- a/examples/tour.rs +++ b/examples/tour.rs @@ -1,7 +1,7 @@ use iced::{ - button, scrollable, slider, text::HorizontalAlignment, Align, Application, - Background, Button, Checkbox, Color, Column, Element, Image, Justify, - Length, Radio, Row, Scrollable, Slider, Text, + button, scrollable, slider, text::HorizontalAlignment, text_input, Align, + Application, Background, Button, Checkbox, Color, Column, Element, Image, + Justify, Length, Radio, Row, Scrollable, Slider, Text, TextInput, }; pub fn main() { @@ -101,7 +101,7 @@ impl Application for Tour { } } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone)] pub enum Message { BackPressed, NextPressed, @@ -139,6 +139,10 @@ impl Steps { slider: slider::State::new(), }, Step::Scrollable, + Step::TextInput { + value: String::new(), + state: text_input::State::new(), + }, Step::Debugger, Step::End, ], @@ -201,11 +205,15 @@ enum Step { slider: slider::State, }, Scrollable, + TextInput { + value: String, + state: text_input::State, + }, Debugger, End, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone)] pub enum StepMessage { SliderChanged(f32), LayoutChanged(Layout), @@ -214,6 +222,7 @@ pub enum StepMessage { TextColorChanged(Color), LanguageSelected(Language), ImageWidthChanged(f32), + InputChanged(String), DebugToggled(bool), } @@ -260,6 +269,11 @@ impl<'a> Step { *width = new_width.round() as u16; } } + StepMessage::InputChanged(new_value) => { + if let Step::TextInput { value, .. } = self { + *value = new_value; + } + } }; } @@ -272,6 +286,7 @@ impl<'a> Step { Step::Image { .. } => true, Step::RowsAndColumns { .. } => true, Step::Scrollable => true, + Step::TextInput { value, .. } => !value.is_empty(), Step::Debugger => true, Step::End => false, } @@ -297,6 +312,9 @@ impl<'a> Step { Self::rows_and_columns(*layout, spacing_slider, *spacing).into() } Step::Scrollable => Self::scrollable().into(), + Step::TextInput { value, state } => { + Self::text_input(value, state).into() + } Step::Debugger => Self::debugger(debug).into(), Step::End => Self::end().into(), } @@ -562,6 +580,38 @@ impl<'a> Step { ) } + fn text_input( + value: &str, + state: &'a mut text_input::State, + ) -> Column<'a, StepMessage> { + Self::container("Text input") + .push(Text::new( + "Use a text input to ask for different kinds of information.", + )) + .push( + TextInput::new( + state, + "Type something to continue...", + value, + StepMessage::InputChanged, + ) + .padding(10) + .size(30), + ) + .push(Text::new( + "A text input produces a message every time it changes. It is \ + very easy to keep track of its contents:", + )) + .push( + Text::new(if value.is_empty() { + "You have not typed anything yet..." + } else { + value + }) + .horizontal_alignment(HorizontalAlignment::Center), + ) + } + fn debugger(debug: bool) -> Column<'a, StepMessage> { Self::container("Debugger") .push(Text::new( -- cgit