Use Task chaining to simplify multi_window example
This commit is contained in:
parent
b21e4567dc
commit
88b9384402
4 changed files with 107 additions and 96 deletions
|
|
@ -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,48 +58,36 @@ 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;
|
||||
Message::OpenWindow => {
|
||||
let Some(last_window) = self.windows.keys().last() else {
|
||||
return Task::none();
|
||||
};
|
||||
|
||||
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::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::TitleChanged(id, title) => {
|
||||
let window =
|
||||
self.windows.get_mut(&id).expect("Window not found.");
|
||||
|
||||
window.title = title;
|
||||
|
||||
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::WindowOpened(id) => {
|
||||
self.windows.insert(id, Window::new(self.windows.len() + 1));
|
||||
|
||||
if let Some(window) = self.windows.get(&id) {
|
||||
text_input::focus(window.input_id.clone())
|
||||
|
|
@ -111,30 +95,52 @@ impl multi_window::Application for Example {
|
|||
Task::none()
|
||||
}
|
||||
}
|
||||
Message::NewWindow => {
|
||||
let count = self.windows.len() + 1;
|
||||
Message::WindowClosed(id) => {
|
||||
self.windows.remove(&id);
|
||||
|
||||
let (id, spawn_window) = window::open(window::Settings {
|
||||
position: self.next_window_pos,
|
||||
exit_on_close_request: count % 2 == 0,
|
||||
..Default::default()
|
||||
});
|
||||
Task::none()
|
||||
}
|
||||
Message::ScaleInputChanged(id, scale) => {
|
||||
if let Some(window) = self.windows.get_mut(&id) {
|
||||
window.scale_input = scale;
|
||||
}
|
||||
|
||||
self.windows.insert(id, Window::new(count));
|
||||
Task::none()
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
spawn_window
|
||||
Task::none()
|
||||
}
|
||||
Message::TitleChanged(id, title) => {
|
||||
if let Some(window) = self.windows.get_mut(&id) {
|
||||
window.title = title;
|
||||
}
|
||||
|
||||
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]
|
||||
|
|
|
|||
|
|
@ -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 => {
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue