use iced::widget::{ button, center, center_x, column, horizontal_space, scrollable, text, text_input, }; use iced::window; use iced::{ Center, Element, Fill, Function, Subscription, Task, Theme, Vector, }; use std::collections::BTreeMap; fn main() -> iced::Result { iced::daemon(Example::title, Example::update, Example::view) .subscription(Example::subscription) .theme(Example::theme) .scale_factor(Example::scale_factor) .run_with(Example::new) } struct Example { windows: BTreeMap, } #[derive(Debug)] struct Window { title: String, scale_input: String, current_scale: f64, theme: Theme, } #[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 new() -> (Self, Task) { let (_id, open) = window::open(window::Settings::default()); ( Self { windows: BTreeMap::new(), }, open.map(Message::WindowOpened), ) } 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::get_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), ) }, ); let (_id, open) = window::open(window::Settings { position, ..window::Settings::default() }); open }) .map(Message::WindowOpened) } Message::WindowOpened(id) => { let window = Window::new(self.windows.len() + 1); let focus_input = text_input::focus(format!("input-{id}")); 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(), } } fn view(&self, id: window::Id) -> Element { let scale_input = column![ text("Window scale factor:"), text_input("Window Scale", &self.scale_input) .on_input(Message::ScaleInputChanged.with(id)) .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(Message::TitleChanged.with(id)) .id(format!("input-{id}")) ]; 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(Fill) .align_x(Center), ); center_x(content).width(200).into() } }