diff options
author | 2024-06-14 03:04:51 +0200 | |
---|---|---|
committer | 2024-06-14 03:05:58 +0200 | |
commit | 88b938440285fdb44c9e5bd572fda5c0f94996ca (patch) | |
tree | 76c645af8cf454a8611fe66f75f0a4931dd99383 | |
parent | b21e4567dc32250c90d2ea9c78080cd8bcb66368 (diff) | |
download | iced-88b938440285fdb44c9e5bd572fda5c0f94996ca.tar.gz iced-88b938440285fdb44c9e5bd572fda5c0f94996ca.tar.bz2 iced-88b938440285fdb44c9e5bd572fda5c0f94996ca.zip |
Use `Task` chaining to simplify `multi_window` example
-rw-r--r-- | examples/multi_window/src/main.rs | 155 | ||||
-rw-r--r-- | examples/screenshot/src/main.rs | 6 | ||||
-rw-r--r-- | runtime/src/window.rs | 38 | ||||
-rw-r--r-- | winit/src/multi_window.rs | 4 |
4 files changed, 107 insertions, 96 deletions
diff --git a/examples/multi_window/src/main.rs b/examples/multi_window/src/main.rs index e15f8759..fa9adb87 100644 --- a/examples/multi_window/src/main.rs +++ b/examples/multi_window/src/main.rs @@ -1,16 +1,15 @@ -use iced::event; use iced::executor; use iced::multi_window::{self, Application}; use iced::widget::{ - button, center, column, container, scrollable, text, text_input, + button, center, column, container, horizontal_space, scrollable, text, + text_input, }; use iced::window; use iced::{ - Alignment, Element, Length, Point, Settings, Subscription, Task, Theme, - Vector, + Alignment, Element, Length, Settings, Subscription, Task, Theme, Vector, }; -use std::collections::HashMap; +use std::collections::BTreeMap; fn main() -> iced::Result { Example::run(Settings::default()) @@ -18,8 +17,7 @@ fn main() -> iced::Result { #[derive(Default)] struct Example { - windows: HashMap<window::Id, Window>, - next_window_pos: window::Position, + windows: BTreeMap<window::Id, Window>, } #[derive(Debug)] @@ -33,13 +31,12 @@ struct Window { #[derive(Debug, Clone)] enum Message { + OpenWindow, + WindowOpened(window::Id), + WindowClosed(window::Id), ScaleInputChanged(window::Id, String), ScaleChanged(window::Id, String), TitleChanged(window::Id, String), - CloseWindow(window::Id), - WindowOpened(window::Id, Option<Point>), - WindowClosed(window::Id), - NewWindow, } impl multi_window::Application for Example { @@ -51,8 +48,7 @@ impl multi_window::Application for Example { fn new(_flags: ()) -> (Self, Task<Message>) { ( Example { - windows: HashMap::from([(window::Id::MAIN, Window::new(1))]), - next_window_pos: window::Position::Default, + windows: BTreeMap::from([(window::Id::MAIN, Window::new(1))]), }, Task::none(), ) @@ -62,79 +58,89 @@ impl multi_window::Application for Example { self.windows .get(&window) .map(|window| window.title.clone()) - .unwrap_or("Example".to_string()) + .unwrap_or_default() } fn update(&mut self, message: Message) -> Task<Message> { match message { - Message::ScaleInputChanged(id, scale) => { - let window = - self.windows.get_mut(&id).expect("Window not found!"); - window.scale_input = scale; - - Task::none() - } - Message::ScaleChanged(id, scale) => { - let window = - self.windows.get_mut(&id).expect("Window not found!"); - - window.current_scale = scale - .parse::<f64>() - .unwrap_or(window.current_scale) - .clamp(0.5, 5.0); - - Task::none() + Message::OpenWindow => { + let Some(last_window) = self.windows.keys().last() else { + return Task::none(); + }; + + window::fetch_position(*last_window) + .then(|last_position| { + let position = last_position.map_or( + window::Position::Default, + |last_position| { + window::Position::Specific( + last_position + Vector::new(20.0, 20.0), + ) + }, + ); + + window::open(window::Settings { + position, + ..window::Settings::default() + }) + }) + .map(Message::WindowOpened) } - Message::TitleChanged(id, title) => { - let window = - self.windows.get_mut(&id).expect("Window not found."); - - window.title = title; + Message::WindowOpened(id) => { + self.windows.insert(id, Window::new(self.windows.len() + 1)); - Task::none() + if let Some(window) = self.windows.get(&id) { + text_input::focus(window.input_id.clone()) + } else { + Task::none() + } } - Message::CloseWindow(id) => window::close(id), Message::WindowClosed(id) => { self.windows.remove(&id); + Task::none() } - Message::WindowOpened(id, position) => { - if let Some(position) = position { - self.next_window_pos = window::Position::Specific( - position + Vector::new(20.0, 20.0), - ); + Message::ScaleInputChanged(id, scale) => { + if let Some(window) = self.windows.get_mut(&id) { + window.scale_input = scale; } - if let Some(window) = self.windows.get(&id) { - text_input::focus(window.input_id.clone()) - } else { - Task::none() - } + Task::none() } - Message::NewWindow => { - let count = self.windows.len() + 1; - - let (id, spawn_window) = window::open(window::Settings { - position: self.next_window_pos, - exit_on_close_request: count % 2 == 0, - ..Default::default() - }); + Message::ScaleChanged(id, scale) => { + if let Some(window) = self.windows.get_mut(&id) { + window.current_scale = scale + .parse::<f64>() + .unwrap_or(window.current_scale) + .clamp(0.5, 5.0); + } - self.windows.insert(id, Window::new(count)); + Task::none() + } + Message::TitleChanged(id, title) => { + if let Some(window) = self.windows.get_mut(&id) { + window.title = title; + } - spawn_window + Task::none() } } } - fn view(&self, window: window::Id) -> Element<Message> { - let content = self.windows.get(&window).unwrap().view(window); - - center(content).into() + fn view(&self, window_id: window::Id) -> Element<Message> { + if let Some(window) = self.windows.get(&window_id) { + center(window.view(window_id)).into() + } else { + horizontal_space().into() + } } - fn theme(&self, window: window::Id) -> Self::Theme { - self.windows.get(&window).unwrap().theme.clone() + fn theme(&self, window: window::Id) -> Theme { + if let Some(window) = self.windows.get(&window) { + window.theme.clone() + } else { + Theme::default() + } } fn scale_factor(&self, window: window::Id) -> f64 { @@ -145,24 +151,7 @@ impl multi_window::Application for Example { } fn subscription(&self) -> Subscription<Self::Message> { - event::listen_with(|event, _, window| { - if let iced::Event::Window(window_event) = event { - match window_event { - window::Event::CloseRequested => { - Some(Message::CloseWindow(window)) - } - window::Event::Opened { position, .. } => { - Some(Message::WindowOpened(window, position)) - } - window::Event::Closed => { - Some(Message::WindowClosed(window)) - } - _ => None, - } - } else { - None - } - }) + window::closings().map(Message::WindowClosed) } } @@ -200,7 +189,7 @@ impl Window { ]; let new_window_button = - button(text("New Window")).on_press(Message::NewWindow); + button(text("New Window")).on_press(Message::OpenWindow); let content = scrollable( column![scale_input, title_input, new_window_button] diff --git a/examples/screenshot/src/main.rs b/examples/screenshot/src/main.rs index 9b9162d0..78d3e9ff 100644 --- a/examples/screenshot/src/main.rs +++ b/examples/screenshot/src/main.rs @@ -34,7 +34,7 @@ struct Example { enum Message { Crop, Screenshot, - ScreenshotData(Screenshot), + Screenshotted(Screenshot), Png, PngSaved(Result<String, PngError>), XInputChanged(Option<u32>), @@ -48,9 +48,9 @@ impl Example { match message { Message::Screenshot => { return iced::window::screenshot(window::Id::MAIN) - .map(Message::ScreenshotData); + .map(Message::Screenshotted); } - Message::ScreenshotData(screenshot) => { + Message::Screenshotted(screenshot) => { self.screenshot = Some(screenshot); } Message::Png => { diff --git a/runtime/src/window.rs b/runtime/src/window.rs index 59f285fd..2ba3e796 100644 --- a/runtime/src/window.rs +++ b/runtime/src/window.rs @@ -21,7 +21,7 @@ use raw_window_handle::WindowHandle; #[allow(missing_debug_implementations)] pub enum Action { /// Opens a new window with some [`Settings`]. - Open(Id, Settings), + Open(Id, Settings, oneshot::Sender<Id>), /// Close the window and exits the application. Close(Id), @@ -155,16 +155,36 @@ pub fn frames() -> Subscription<Instant> { }) } -/// Opens a new window with the given `settings`. -/// -/// Returns the new window [`Id`] alongside the [`Task`]. -pub fn open<T>(settings: Settings) -> (Id, Task<T>) { +/// Subscribes to all window close requests of the running application. +pub fn close_requests() -> Subscription<Id> { + event::listen_with(|event, _status, id| { + if let crate::core::Event::Window(Event::CloseRequested) = event { + Some(id) + } else { + None + } + }) +} + +/// Subscribes to all window closings of the running application. +pub fn closings() -> Subscription<Id> { + event::listen_with(|event, _status, id| { + if let crate::core::Event::Window(Event::Closed) = event { + Some(id) + } else { + None + } + }) +} + +/// Opens a new window with the given [`Settings`]; producing the [`Id`] +/// of the new window on completion. +pub fn open(settings: Settings) -> Task<Id> { let id = Id::unique(); - ( - id, - Task::effect(crate::Action::Window(Action::Open(id, settings))), - ) + Task::oneshot(|channel| { + crate::Action::Window(Action::Open(id, settings, channel)) + }) } /// Closes the window with `id`. diff --git a/winit/src/multi_window.rs b/winit/src/multi_window.rs index d56b47eb..8bd8a64d 100644 --- a/winit/src/multi_window.rs +++ b/winit/src/multi_window.rs @@ -1030,7 +1030,7 @@ fn run_action<A, C>( } }, Action::Window(action) => match action { - window::Action::Open(id, settings) => { + window::Action::Open(id, settings, channel) => { let monitor = window_manager.last_monitor(); control_sender @@ -1041,6 +1041,8 @@ fn run_action<A, C>( monitor, }) .expect("Send control action"); + + let _ = channel.send(id); } window::Action::Close(id) => { let _ = window_manager.remove(id); |