From 80688689aa4b15bc23824df899974a9094a77b07 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 28 Jul 2022 02:46:51 +0200 Subject: Draft widget operations --- examples/tour/src/main.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/tour/src/main.rs b/examples/tour/src/main.rs index 75d2ce08..82dac0cd 100644 --- a/examples/tour/src/main.rs +++ b/examples/tour/src/main.rs @@ -452,6 +452,7 @@ impl<'a> Step { .map(Element::from) .collect() ) + .spacing(10) ] .padding(20) .spacing(10); @@ -594,10 +595,7 @@ fn ferris<'a>(width: u16) -> Container<'a, StepMessage> { if cfg!(target_arch = "wasm32") { image("tour/images/ferris.png") } else { - image(format!( - "{}/../../tour/images/ferris.png", - env!("CARGO_MANIFEST_DIR") - )) + image(format!("{}/images/ferris.png", env!("CARGO_MANIFEST_DIR"))) } .width(Length::Units(width)), ) -- cgit From 744edbd6c17c3c9d872992c84e074f14c8e75a47 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 28 Jul 2022 03:54:02 +0200 Subject: Focus text inputs in `todos` example --- examples/todos/Cargo.toml | 1 + examples/todos/src/main.rs | 31 ++++++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/todos/Cargo.toml b/examples/todos/Cargo.toml index 5b068c78..2326ffc6 100644 --- a/examples/todos/Cargo.toml +++ b/examples/todos/Cargo.toml @@ -9,6 +9,7 @@ publish = false iced = { path = "../..", features = ["async-std", "debug"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +lazy_static = "1.4" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] async-std = "1.0" diff --git a/examples/todos/src/main.rs b/examples/todos/src/main.rs index 7dde235a..5cbb6228 100644 --- a/examples/todos/src/main.rs +++ b/examples/todos/src/main.rs @@ -7,8 +7,14 @@ use iced::widget::{ use iced::window; use iced::{Application, Element}; use iced::{Color, Command, Font, Length, Settings}; + +use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; +lazy_static! { + static ref INPUT_ID: text_input::Id = text_input::Id::unique(); +} + pub fn main() -> iced::Result { Todos::run(Settings { window: window::Settings { @@ -84,10 +90,11 @@ impl Application for Todos { _ => {} } - Command::none() + text_input::focus(INPUT_ID.clone()) } Todos::Loaded(state) => { let mut saved = false; + let mut task_command = Command::none(); match message { Message::InputChanged(value) => { @@ -109,6 +116,11 @@ impl Application for Todos { } Message::TaskMessage(i, task_message) => { if let Some(task) = state.tasks.get_mut(i) { + if matches!(task_message, TaskMessage::Edit) { + task_command = + text_input::focus(Task::text_input_id(i)); + } + task.update(task_message); } } @@ -123,7 +135,7 @@ impl Application for Todos { state.dirty = true; } - if state.dirty && !state.saving { + let save = if state.dirty && !state.saving { state.dirty = false; state.saving = true; @@ -138,7 +150,9 @@ impl Application for Todos { ) } else { Command::none() - } + }; + + Command::batch(vec![task_command, save]) } } } @@ -163,6 +177,7 @@ impl Application for Todos { input_value, Message::InputChanged, ) + .id(INPUT_ID.clone()) .padding(15) .size(30) .on_submit(Message::CreateTask); @@ -178,12 +193,13 @@ impl Application for Todos { .enumerate() .filter(|(_, task)| filter.matches(task)) .map(|(i, task)| { - task.view().map(move |message| { + task.view(i).map(move |message| { Message::TaskMessage(i, message) }) }) .collect(), ) + .spacing(10) .into() } else { empty_message(match filter { @@ -242,6 +258,10 @@ pub enum TaskMessage { } impl Task { + fn text_input_id(i: usize) -> text_input::Id { + text_input::Id::new(format!("task-{}", i)) + } + fn new(description: String) -> Self { Task { description, @@ -270,7 +290,7 @@ impl Task { } } - fn view(&self) -> Element { + fn view(&self, i: usize) -> Element { match &self.state { TaskState::Idle => { let checkbox = checkbox( @@ -297,6 +317,7 @@ impl Task { &self.description, TaskMessage::DescriptionEdited, ) + .id(Self::text_input_id(i)) .on_submit(TaskMessage::FinishEdition) .padding(10); -- cgit From 77c6864e7c772c5e228bc09fe40c2c0b8884386d Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 2 Aug 2022 04:20:47 +0200 Subject: Implement `focus_next` operation ... as well as a `count_focusable` composable helper! --- examples/todos/src/main.rs | 57 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 12 deletions(-) (limited to 'examples') diff --git a/examples/todos/src/main.rs b/examples/todos/src/main.rs index 5cbb6228..25d90a0b 100644 --- a/examples/todos/src/main.rs +++ b/examples/todos/src/main.rs @@ -1,12 +1,15 @@ use iced::alignment::{self, Alignment}; +use iced::event::{self, Event}; +use iced::keyboard; +use iced::subscription; use iced::theme::{self, Theme}; use iced::widget::{ - button, checkbox, column, container, row, scrollable, text, text_input, - Text, + self, button, checkbox, column, container, row, scrollable, text, + text_input, Text, }; use iced::window; use iced::{Application, Element}; -use iced::{Color, Command, Font, Length, Settings}; +use iced::{Color, Command, Font, Length, Settings, Subscription}; use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; @@ -48,6 +51,7 @@ enum Message { CreateTask, FilterChanged(Filter), TaskMessage(usize, TaskMessage), + TabPressed, } impl Application for Todos { @@ -94,11 +98,12 @@ impl Application for Todos { } Todos::Loaded(state) => { let mut saved = false; - let mut task_command = Command::none(); - match message { + let command = match message { Message::InputChanged(value) => { state.input_value = value; + + Command::none() } Message::CreateTask => { if !state.input_value.is_empty() { @@ -107,29 +112,44 @@ impl Application for Todos { .push(Task::new(state.input_value.clone())); state.input_value.clear(); } + + Command::none() } Message::FilterChanged(filter) => { state.filter = filter; + + Command::none() } Message::TaskMessage(i, TaskMessage::Delete) => { state.tasks.remove(i); + + Command::none() } Message::TaskMessage(i, task_message) => { if let Some(task) = state.tasks.get_mut(i) { - if matches!(task_message, TaskMessage::Edit) { - task_command = - text_input::focus(Task::text_input_id(i)); - } + let should_focus = + matches!(task_message, TaskMessage::Edit); task.update(task_message); + + if should_focus { + text_input::focus(Task::text_input_id(i)) + } else { + Command::none() + } + } else { + Command::none() } } Message::Saved(_) => { state.saving = false; saved = true; + + Command::none() } - _ => {} - } + Message::TabPressed => widget::focus_next(), + _ => Command::none(), + }; if !saved { state.dirty = true; @@ -152,7 +172,7 @@ impl Application for Todos { Command::none() }; - Command::batch(vec![task_command, save]) + Command::batch(vec![command, save]) } } } @@ -225,6 +245,19 @@ impl Application for Todos { } } } + + fn subscription(&self) -> Subscription { + subscription::events_with(|event, status| match (event, status) { + ( + Event::Keyboard(keyboard::Event::KeyPressed { + key_code: keyboard::KeyCode::Tab, + .. + }), + event::Status::Ignored, + ) => Some(Message::TabPressed), + _ => None, + }) + } } #[derive(Debug, Clone, Serialize, Deserialize)] -- cgit From 6eb3dd7e5edc8847875c288c41d1dec8b1dad06e Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 4 Aug 2022 03:24:44 +0200 Subject: Implement `focus_previous` operation --- examples/todos/src/main.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/todos/src/main.rs b/examples/todos/src/main.rs index 25d90a0b..bb00aac6 100644 --- a/examples/todos/src/main.rs +++ b/examples/todos/src/main.rs @@ -51,7 +51,7 @@ enum Message { CreateTask, FilterChanged(Filter), TaskMessage(usize, TaskMessage), - TabPressed, + TabPressed { shift: bool }, } impl Application for Todos { @@ -147,7 +147,13 @@ impl Application for Todos { Command::none() } - Message::TabPressed => widget::focus_next(), + Message::TabPressed { shift } => { + if shift { + widget::focus_previous() + } else { + widget::focus_next() + } + } _ => Command::none(), }; @@ -251,10 +257,13 @@ impl Application for Todos { ( Event::Keyboard(keyboard::Event::KeyPressed { key_code: keyboard::KeyCode::Tab, + modifiers, .. }), event::Status::Ignored, - ) => Some(Message::TabPressed), + ) => Some(Message::TabPressed { + shift: modifiers.shift(), + }), _ => None, }) } -- cgit From 13dd1ca0a83cc95eea52e2106da9dc1ee1f37958 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 4 Aug 2022 03:55:41 +0200 Subject: Implement `scrollable::snap_to` operation --- examples/scrollable/src/main.rs | 52 ++++++++++++++++++++++++++++------------- examples/websocket/Cargo.toml | 1 + examples/websocket/src/main.rs | 22 ++++++++++++----- 3 files changed, 53 insertions(+), 22 deletions(-) (limited to 'examples') diff --git a/examples/scrollable/src/main.rs b/examples/scrollable/src/main.rs index c9c1be7c..b7b3dedc 100644 --- a/examples/scrollable/src/main.rs +++ b/examples/scrollable/src/main.rs @@ -1,8 +1,9 @@ +use iced::executor; use iced::widget::{ button, column, container, horizontal_rule, progress_bar, radio, scrollable, text, vertical_space, Row, }; -use iced::{Element, Length, Sandbox, Settings, Theme}; +use iced::{Application, Command, Element, Length, Settings, Theme}; pub fn main() -> iced::Result { ScrollableDemo::run(Settings::default()) @@ -21,43 +22,57 @@ enum Message { Scrolled(usize, f32), } -impl Sandbox for ScrollableDemo { +impl Application for ScrollableDemo { type Message = Message; - - fn new() -> Self { - ScrollableDemo { - theme: Default::default(), - variants: Variant::all(), - } + type Theme = Theme; + type Executor = executor::Default; + type Flags = (); + + fn new(_flags: Self::Flags) -> (Self, Command) { + ( + ScrollableDemo { + theme: Default::default(), + variants: Variant::all(), + }, + Command::none(), + ) } fn title(&self) -> String { String::from("Scrollable - Iced") } - fn update(&mut self, message: Message) { + fn update(&mut self, message: Message) -> Command { match message { - Message::ThemeChanged(theme) => self.theme = theme, + Message::ThemeChanged(theme) => { + self.theme = theme; + + Command::none() + } Message::ScrollToTop(i) => { if let Some(variant) = self.variants.get_mut(i) { - // TODO - // variant.scrollable.snap_to(0.0); - variant.latest_offset = 0.0; + + scrollable::snap_to(Variant::id(i), 0.0) + } else { + Command::none() } } Message::ScrollToBottom(i) => { if let Some(variant) = self.variants.get_mut(i) { - // TODO - // variant.scrollable.snap_to(1.0); - variant.latest_offset = 1.0; + + scrollable::snap_to(Variant::id(i), 1.0) + } else { + Command::none() } } Message::Scrolled(i, offset) => { if let Some(variant) = self.variants.get_mut(i) { variant.latest_offset = offset; } + + Command::none() } } } @@ -136,6 +151,7 @@ impl Sandbox for ScrollableDemo { ); let mut scrollable = scrollable(contents) + .id(Variant::id(i)) .height(Length::Fill) .on_scroll(move |offset| Message::Scrolled(i, offset)); @@ -228,4 +244,8 @@ impl Variant { }, ] } + + pub fn id(i: usize) -> scrollable::Id { + scrollable::Id::new(format!("scrollable-{}", i)) + } } diff --git a/examples/websocket/Cargo.toml b/examples/websocket/Cargo.toml index db131dd7..c582733f 100644 --- a/examples/websocket/Cargo.toml +++ b/examples/websocket/Cargo.toml @@ -9,6 +9,7 @@ publish = false iced = { path = "../..", features = ["tokio", "debug"] } iced_native = { path = "../../native" } iced_futures = { path = "../../futures" } +lazy_static = "1.4" [dependencies.async-tungstenite] version = "0.16" diff --git a/examples/websocket/src/main.rs b/examples/websocket/src/main.rs index 28a9de37..3902e04c 100644 --- a/examples/websocket/src/main.rs +++ b/examples/websocket/src/main.rs @@ -49,37 +49,42 @@ impl Application for WebSocket { match message { Message::NewMessageChanged(new_message) => { self.new_message = new_message; + + Command::none() } Message::Send(message) => match &mut self.state { State::Connected(connection) => { self.new_message.clear(); connection.send(message); + + Command::none() } - State::Disconnected => {} + State::Disconnected => Command::none(), }, Message::Echo(event) => match event { echo::Event::Connected(connection) => { self.state = State::Connected(connection); self.messages.push(echo::Message::connected()); + + Command::none() } echo::Event::Disconnected => { self.state = State::Disconnected; self.messages.push(echo::Message::disconnected()); + + Command::none() } echo::Event::MessageReceived(message) => { self.messages.push(message); - // TODO - // self.message_log.snap_to(1.0); + scrollable::snap_to(MESSAGE_LOG.clone(), 1.0) } }, - Message::Server => {} + Message::Server => Command::none(), } - - Command::none() } fn subscription(&self) -> Subscription { @@ -110,6 +115,7 @@ impl Application for WebSocket { .width(Length::Fill) .spacing(10), ) + .id(MESSAGE_LOG.clone()) .height(Length::Fill) .into() }; @@ -158,3 +164,7 @@ impl Default for State { Self::Disconnected } } + +lazy_static::lazy_static! { + static ref MESSAGE_LOG: scrollable::Id = scrollable::Id::unique(); +} -- cgit