use iced::widget::{ button, center, column, container, horizontal_space, scrollable, text, text_input, }; use iced::window; use iced::{Alignment, Element, Length, Subscription, Task, Theme, Vector}; use std::collections::BTreeMap; fn main() -> iced::Result { iced::daemon(Example::title, Example::update, Example::view) .load(|| { window::open(window::Settings::default()).map(Message::WindowOpened) }) .subscription(Example::subscription) .theme(Example::theme) .scale_factor(Example::scale_factor) .run() } #[derive(Default)] struct Example { windows: BTreeMap, } #[derive(Debug)] struct Window { title: String, scale_input: String, current_scale: f64, theme: Theme, input_id: iced::widget::text_input::Id, } #[derive(Debug, Clone)] enum Message { OpenWindow, WindowOpened(window::Id), WindowClosed(window::Id), ScaleInputChanged(window::Id, String), ScaleChanged(window::Id, String), TitleChanged(window::Id, String), } impl Example { fn title(&self, window: window::Id) -> String { self.windows .get(&window) .map(|window| window.title.clone()) .unwrap_or_default() } fn update(&mut self, message: Message) -> Task { match message { 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::WindowOpened(id) => { let window = Window::new(self.windows.len() + 1); let focus_input = text_input::focus(window.input_id.clone()); self.windows.insert(id, window); focus_input } Message::WindowClosed(id) => { self.windows.remove(&id); if self.windows.is_empty() { iced::exit() } else { Task::none() } } Message::ScaleInputChanged(id, scale) => { if let Some(window) = self.windows.get_mut(&id) { window.scale_input = scale; } Task::none() } Message::ScaleChanged(id, scale) => { if let Some(window) = self.windows.get_mut(&id) { window.current_scale = scale .parse::() .unwrap_or(window.current_scale) .clamp(0.5, 5.0); } Task::none() } Message::TitleChanged(id, title) => { if let Some(window) = self.windows.get_mut(&id) { window.title = title; } Task::none() } } } fn view(&self, window_id: window::Id) -> Element { 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) -> Theme { if let Some(window) = self.windows.get(&window) { window.theme.clone() } else { Theme::default() } } fn scale_factor(&self, window: window::Id) -> f64 { self.windows .get(&window) .map(|window| window.current_scale) .unwrap_or(1.0) } fn subscription(&self) -> Subscription { window::close_events().map(Message::WindowClosed) } } impl Window { fn new(count: usize) -> Self { Self { title: format!("Window_{}", count), scale_input: "1.0".to_string(), current_scale: 1.0, theme: Theme::ALL[count % Theme::ALL.len()].clone(), input_id: text_input::Id::unique(), } } fn view(&self, id: window::Id) -> Element { let scale_input = column![ text("Window scale factor:"), text_input("Window Scale", &self.scale_input) .on_input(move |msg| { Message::ScaleInputChanged(id, msg) }) .on_submit(Message::ScaleChanged( id, self.scale_input.to_string() )) ]; let title_input = column![ text("Window title:"), text_input("Window Title", &self.title) .on_input(move |msg| { Message::TitleChanged(id, msg) }) .id(self.input_id.clone()) ]; let new_window_button = button(text("New Window")).on_press(Message::OpenWindow); let content = scrollable( column![scale_input, title_input, new_window_button] .spacing(50) .width(Length::Fill) .align_items(Alignment::Center), ); container(content).center_x(200).into() } }