diff options
author | 2023-03-13 18:19:16 -0700 | |
---|---|---|
committer | 2023-03-14 11:05:41 -0700 | |
commit | ce4b2c93d9802dfb8cd3fc9033d76651d4bbc75b (patch) | |
tree | a690bb94262b7a898a608d11e18960db81e7ef0c /examples/multi_window | |
parent | 8ba18430800142965549077373e2a45d0a3429a1 (diff) | |
download | iced-ce4b2c93d9802dfb8cd3fc9033d76651d4bbc75b.tar.gz iced-ce4b2c93d9802dfb8cd3fc9033d76651d4bbc75b.tar.bz2 iced-ce4b2c93d9802dfb8cd3fc9033d76651d4bbc75b.zip |
Added simpler MW example
Diffstat (limited to 'examples/multi_window')
-rw-r--r-- | examples/multi_window/Cargo.toml | 8 | ||||
-rw-r--r-- | examples/multi_window/src/main.rs | 654 |
2 files changed, 103 insertions, 559 deletions
diff --git a/examples/multi_window/Cargo.toml b/examples/multi_window/Cargo.toml index a59a0e68..0cb5d546 100644 --- a/examples/multi_window/Cargo.toml +++ b/examples/multi_window/Cargo.toml @@ -1,13 +1,9 @@ [package] name = "multi_window" version = "0.1.0" -authors = ["Richard Custodio <richardsoncusto@gmail.com>"] +authors = ["Bingus <shankern@protonmail.com>"] edition = "2021" publish = false -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -iced = { path = "../..", features = ["debug", "multi-window", "tokio"] } -env_logger = "0.10.0" -iced_native = { path = "../../native" } -iced_lazy = { path = "../../lazy" } +iced = { path = "../..", features = ["debug", "multi-window"] }
\ No newline at end of file diff --git a/examples/multi_window/src/main.rs b/examples/multi_window/src/main.rs index 60f32a7d..5699ece0 100644 --- a/examples/multi_window/src/main.rs +++ b/examples/multi_window/src/main.rs @@ -1,90 +1,50 @@ -use iced::alignment::{self, Alignment}; -use iced::{executor, time}; -use iced::keyboard; -use iced::multi_window::Application; -use iced::theme::{self, Theme}; -use iced::widget::pane_grid::{self, PaneGrid}; -use iced::widget::{ - button, column, container, pick_list, row, scrollable, text, text_input, +use iced::multi_window::{self, Application}; +use iced::widget::{button, column, container, scrollable, text, text_input}; +use iced::{ + executor, window, Alignment, Command, Element, Length, Settings, Theme, }; -use iced::window; -use iced::{Color, Command, Element, Length, Settings, Size, Subscription}; -use iced_lazy::responsive; -use iced_native::{event, subscription, Event}; - -use iced_native::widget::scrollable::{Properties, RelativeOffset}; -use iced_native::window::Id; use std::collections::HashMap; -use std::time::{Duration, Instant}; - -pub fn main() -> iced::Result { - env_logger::init(); +fn main() -> iced::Result { Example::run(Settings::default()) } +#[derive(Default)] struct Example { + windows_count: usize, windows: HashMap<window::Id, Window>, - panes_created: usize, - count: usize, - _focused: window::Id, } -#[derive(Debug)] struct Window { + id: window::Id, title: String, - scale: f64, - panes: pane_grid::State<Pane>, - focus: Option<pane_grid::Pane>, + scale_input: String, + current_scale: f64, } #[derive(Debug, Clone)] enum Message { - Window(window::Id, WindowMessage), - CountIncremented(Instant), -} - -#[derive(Debug, Clone)] -enum WindowMessage { - Split(pane_grid::Axis, pane_grid::Pane), - SplitFocused(pane_grid::Axis), - FocusAdjacent(pane_grid::Direction), - Clicked(pane_grid::Pane), - Dragged(pane_grid::DragEvent), - PopOut(pane_grid::Pane), - Resized(pane_grid::ResizeEvent), - TitleChanged(String), - ToggleMoving(pane_grid::Pane), - TogglePin(pane_grid::Pane), - Close(pane_grid::Pane), - CloseFocused, - SelectedWindow(pane_grid::Pane, SelectableWindow), - CloseWindow, - SnapToggle, + ScaleInputChanged(window::Id, String), + ScaleChanged(window::Id, String), + TitleChanged(window::Id, String), + CloseWindow(window::Id), + NewWindow, } -impl Application for Example { +impl multi_window::Application for Example { type Executor = executor::Default; type Message = Message; type Theme = Theme; type Flags = (); fn new(_flags: ()) -> (Self, Command<Message>) { - let (panes, _) = - pane_grid::State::new(Pane::new(0, pane_grid::Axis::Horizontal)); - let window = Window { - panes, - focus: None, - title: String::from("Default window"), - scale: 1.0, - }; - ( Example { - windows: HashMap::from([(window::Id::MAIN, window)]), - panes_created: 1, - count: 0, - _focused: window::Id::MAIN, + windows_count: 0, + windows: HashMap::from([( + window::Id::MAIN, + Window::new(window::Id::MAIN), + )]), }, Command::none(), ) @@ -93,530 +53,118 @@ impl Application for Example { fn title(&self, window: window::Id) -> String { self.windows .get(&window) - .map(|w| w.title.clone()) - .unwrap_or(String::from("New Window")) + .map(|window| window.title.clone()) + .unwrap_or("Example".to_string()) } fn update(&mut self, message: Message) -> Command<Message> { match message { - Message::Window(id, message) => match message { - WindowMessage::SnapToggle => { - let window = self.windows.get_mut(&id).unwrap(); - - if let Some(focused) = &window.focus { - let pane = window.panes.get_mut(focused).unwrap(); - - let cmd = scrollable::snap_to( - pane.scrollable_id.clone(), - if pane.snapped { - RelativeOffset::START - } else { - RelativeOffset::END - }, - ); - - pane.snapped = !pane.snapped; - return cmd; - } - } - WindowMessage::Split(axis, pane) => { - let window = self.windows.get_mut(&id).unwrap(); - let result = window.panes.split( - axis, - &pane, - Pane::new(self.panes_created, axis), - ); - - if let Some((pane, _)) = result { - window.focus = Some(pane); - } - - self.panes_created += 1; - } - WindowMessage::SplitFocused(axis) => { - let window = self.windows.get_mut(&id).unwrap(); - if let Some(pane) = window.focus { - let result = window.panes.split( - axis, - &pane, - Pane::new(self.panes_created, axis), - ); - - if let Some((pane, _)) = result { - window.focus = Some(pane); - } - - self.panes_created += 1; - } - } - WindowMessage::FocusAdjacent(direction) => { - let window = self.windows.get_mut(&id).unwrap(); - if let Some(pane) = window.focus { - if let Some(adjacent) = - window.panes.adjacent(&pane, direction) - { - window.focus = Some(adjacent); - } - } - } - WindowMessage::Clicked(pane) => { - let window = self.windows.get_mut(&id).unwrap(); - window.focus = Some(pane); - } - WindowMessage::CloseWindow => { - let _ = self.windows.remove(&id); - return window::close(id); - } - WindowMessage::Resized(pane_grid::ResizeEvent { split, ratio }) => { - let window = self.windows.get_mut(&id).unwrap(); - window.panes.resize(&split, ratio); - } - WindowMessage::SelectedWindow(pane, selected) => { - let window = self.windows.get_mut(&id).unwrap(); - let (mut pane, _) = window.panes.close(&pane).unwrap(); - pane.is_moving = false; - - if let Some(window) = self.windows.get_mut(&selected.0) { - let (&first_pane, _) = window.panes.iter().next().unwrap(); - let result = - window.panes.split(pane.axis, &first_pane, pane); - - if let Some((pane, _)) = result { - window.focus = Some(pane); - } - } - } - WindowMessage::ToggleMoving(pane) => { - let window = self.windows.get_mut(&id).unwrap(); - if let Some(pane) = window.panes.get_mut(&pane) { - pane.is_moving = !pane.is_moving; - } - } - WindowMessage::TitleChanged(title) => { - let window = self.windows.get_mut(&id).unwrap(); - window.title = title; - } - WindowMessage::PopOut(pane) => { - let window = self.windows.get_mut(&id).unwrap(); - if let Some((popped, sibling)) = window.panes.close(&pane) { - window.focus = Some(sibling); + Message::ScaleInputChanged(id, scale) => { + let window = + self.windows.get_mut(&id).expect("Window not found!"); + window.scale_input = scale; + } + 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); + } + Message::TitleChanged(id, title) => { + let window = + self.windows.get_mut(&id).expect("Window not found."); - let (panes, _) = pane_grid::State::new(popped); - let window = Window { - panes, - focus: None, - title: format!("New window ({})", self.windows.len()), - scale: 1.0 + (self.windows.len() as f64 / 10.0), - }; + window.title = title; + } + Message::CloseWindow(id) => { + return window::close(id); + } + Message::NewWindow => { + self.windows_count += 1; + let id = window::Id::new(self.windows_count); + self.windows.insert(id, Window::new(id)); - let window_id = window::Id::new(self.windows.len()); - self.windows.insert(window_id, window); - return window::spawn(window_id, Default::default()); - } - } - WindowMessage::Dragged(pane_grid::DragEvent::Dropped { - pane, - target, - }) => { - let window = self.windows.get_mut(&id).unwrap(); - window.panes.swap(&pane, &target); - } - // WindowMessage::Dragged(pane_grid::DragEvent::Picked { pane }) => { - // println!("Picked {pane:?}"); - // } - WindowMessage::Dragged(_) => {} - WindowMessage::TogglePin(pane) => { - let window = self.windows.get_mut(&id).unwrap(); - if let Some(Pane { is_pinned, .. }) = - window.panes.get_mut(&pane) - { - *is_pinned = !*is_pinned; - } - } - WindowMessage::Close(pane) => { - let window = self.windows.get_mut(&id).unwrap(); - if let Some((_, sibling)) = window.panes.close(&pane) { - window.focus = Some(sibling); - } - } - WindowMessage::CloseFocused => { - let window = self.windows.get_mut(&id).unwrap(); - if let Some(pane) = window.focus { - if let Some(Pane { is_pinned, .. }) = - window.panes.get(&pane) - { - if !is_pinned { - if let Some((_, sibling)) = - window.panes.close(&pane) - { - window.focus = Some(sibling); - } - } - } - } - } - }, - Message::CountIncremented(_) => { - self.count += 1; + return window::spawn(id, window::Settings::default()); } } Command::none() } - fn subscription(&self) -> Subscription<Message> { - Subscription::batch(vec![ - subscription::events_with(|event, status| { - if let event::Status::Captured = status { - return None; - } - - match event { - Event::Keyboard(keyboard::Event::KeyPressed { - modifiers, - key_code, - }) if modifiers.command() => { - handle_hotkey(key_code).map(|message| { - Message::Window(window::Id::new(0usize), message) - }) - } // TODO(derezzedex) - _ => None, - } - }), - time::every(Duration::from_secs(1)).map(Message::CountIncremented), - ]) - } - - fn view(&self, window_id: window::Id) -> Element<Message> { - if let Some(window) = self.windows.get(&window_id) { - let focus = window.focus; - let total_panes = window.panes.len(); - - let window_controls = row![ - text_input( - "Window title", - &window.title, - WindowMessage::TitleChanged, - ), - button(text("Close")) - .on_press(WindowMessage::CloseWindow) - .style(theme::Button::Destructive), - ] - .spacing(5) - .align_items(Alignment::Center); - - let pane_grid = PaneGrid::new(&window.panes, |id, pane, _| { - let is_focused = focus == Some(id); - - let pin_button = button( - text(if pane.is_pinned { "Unpin" } else { "Pin" }).size(14), - ) - .on_press(WindowMessage::TogglePin(id)) - .padding(3); - - let title = row![ - pin_button, - "Pane", - text(pane.id.to_string()).style(if is_focused { - PANE_ID_COLOR_FOCUSED - } else { - PANE_ID_COLOR_UNFOCUSED - }), - ] - .spacing(5); - - let title_bar = pane_grid::TitleBar::new(title) - .controls(view_controls( - id, - total_panes, - pane.is_pinned, - pane.is_moving, - &window.title, - window_id, - &self.windows, - )) - .padding(10) - .style(if is_focused { - style::title_bar_focused - } else { - style::title_bar_active - }); + fn view(&self, window: window::Id) -> Element<Message> { + let window = self + .windows + .get(&window) + .map(|window| window.view()) + .unwrap(); - pane_grid::Content::new(responsive(move |size| { - view_content( - id, - pane.scrollable_id.clone(), - self.count, - total_panes, - pane.is_pinned, - size, - ) - })) - .title_bar(title_bar) - .style(if is_focused { - style::pane_focused - } else { - style::pane_active - }) - }) + container(window) .width(Length::Fill) .height(Length::Fill) - .spacing(10) - .on_click(WindowMessage::Clicked) - .on_drag(WindowMessage::Dragged) - .on_resize(10, WindowMessage::Resized); - - let content: Element<_> = column![window_controls, pane_grid] - .width(Length::Fill) - .height(Length::Fill) - .padding(10) - .into(); - - return content - .map(move |message| Message::Window(window_id, message)); - } - - container(text("This shouldn't be possible!").size(20)) .center_x() .center_y() .into() } - fn close_requested(&self, window: window::Id) -> Self::Message { - Message::Window(window, WindowMessage::CloseWindow) - } - - fn scale_factor(&self, window: Id) -> f64 { - self.windows.get(&window).map(|w| w.scale).unwrap_or(1.0) - } -} - -const PANE_ID_COLOR_UNFOCUSED: Color = Color::from_rgb( - 0xFF as f32 / 255.0, - 0xC7 as f32 / 255.0, - 0xC7 as f32 / 255.0, -); -const PANE_ID_COLOR_FOCUSED: Color = Color::from_rgb( - 0xFF as f32 / 255.0, - 0x47 as f32 / 255.0, - 0x47 as f32 / 255.0, -); - -fn handle_hotkey(key_code: keyboard::KeyCode) -> Option<WindowMessage> { - use keyboard::KeyCode; - use pane_grid::{Axis, Direction}; - - let direction = match key_code { - KeyCode::Up => Some(Direction::Up), - KeyCode::Down => Some(Direction::Down), - KeyCode::Left => Some(Direction::Left), - KeyCode::Right => Some(Direction::Right), - _ => None, - }; - - match key_code { - KeyCode::V => Some(WindowMessage::SplitFocused(Axis::Vertical)), - KeyCode::H => Some(WindowMessage::SplitFocused(Axis::Horizontal)), - KeyCode::W => Some(WindowMessage::CloseFocused), - _ => direction.map(WindowMessage::FocusAdjacent), - } -} - -#[derive(Debug, Clone)] -struct SelectableWindow(window::Id, String); - -impl PartialEq for SelectableWindow { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 + fn scale_factor(&self, window: window::Id) -> f64 { + self.windows + .get(&window) + .map(|window| window.current_scale) + .unwrap_or(1.0) } -} - -impl Eq for SelectableWindow {} -impl std::fmt::Display for SelectableWindow { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.1.fmt(f) + fn close_requested(&self, window: window::Id) -> Self::Message { + Message::CloseWindow(window) } } -#[derive(Debug)] -struct Pane { - id: usize, - pub scrollable_id: scrollable::Id, - pub axis: pane_grid::Axis, - pub is_pinned: bool, - pub is_moving: bool, - pub snapped: bool, -} - -impl Pane { - fn new(id: usize, axis: pane_grid::Axis) -> Self { +impl Window { + fn new(id: window::Id) -> Self { Self { id, - scrollable_id: scrollable::Id::unique(), - axis, - is_pinned: false, - is_moving: false, - snapped: false, + title: "Window".to_string(), + scale_input: "1.0".to_string(), + current_scale: 1.0, } } -} - -fn view_content<'a>( - pane: pane_grid::Pane, - scrollable_id: scrollable::Id, - count: usize, - total_panes: usize, - is_pinned: bool, - size: Size, -) -> Element<'a, WindowMessage> { - let button = |label, message| { - button( - text(label) - .width(Length::Fill) - .horizontal_alignment(alignment::Horizontal::Center) - .size(16), - ) - .width(Length::Fill) - .padding(8) - .on_press(message) - }; - let mut controls = column![ - button( - "Split horizontally", - WindowMessage::Split(pane_grid::Axis::Horizontal, pane), - ), - button( - "Split vertically", - WindowMessage::Split(pane_grid::Axis::Vertical, pane), - ), - button("Snap", WindowMessage::SnapToggle,) - ] - .spacing(5) - .max_width(150); - - if total_panes > 1 && !is_pinned { - controls = controls.push( - button("Close", WindowMessage::Close(pane)) - .style(theme::Button::Destructive), - ); + fn view(&self) -> Element<Message> { + window_view(self.id, &self.scale_input, &self.title) } - - let content = column![ - text(format!("{}x{}", size.width, size.height)).size(24), - controls, - text(format!("{count}")).size(48), - ] - .width(Length::Fill) - .height(800) - .spacing(10) - .align_items(Alignment::Center); - - container( - scrollable(content) - .height(Length::Fill) - .vertical_scroll(Properties::new()) - .id(scrollable_id), - ) - .width(Length::Fill) - .height(Length::Fill) - .padding(5) - .center_y() - .into() } -fn view_controls<'a>( - pane: pane_grid::Pane, - total_panes: usize, - is_pinned: bool, - is_moving: bool, - window_title: &'a str, - window_id: window::Id, - windows: &HashMap<window::Id, Window>, -) -> Element<'a, WindowMessage> { - let window_selector = { - let options: Vec<_> = windows - .iter() - .map(|(id, window)| SelectableWindow(*id, window.title.clone())) - .collect(); - pick_list( - options, - Some(SelectableWindow(window_id, window_title.to_string())), - move |window| WindowMessage::SelectedWindow(pane, window), - ) - }; - - let mut move_to = button(text("Move to").size(14)).padding(3); - - let mut pop_out = button(text("Pop Out").size(14)).padding(3); - - let mut close = button(text("Close").size(14)) - .style(theme::Button::Destructive) - .padding(3); - - if total_panes > 1 && !is_pinned { - close = close.on_press(WindowMessage::Close(pane)); - pop_out = pop_out.on_press(WindowMessage::PopOut(pane)); - } - - if windows.len() > 1 && total_panes > 1 && !is_pinned { - move_to = move_to.on_press(WindowMessage::ToggleMoving(pane)); - } - - let mut content = row![].spacing(10); - if is_moving { - content = content.push(pop_out).push(window_selector).push(close); - } else { - content = content.push(pop_out).push(move_to).push(close); - } - - content.into() -} - -mod style { - use iced::widget::container; - use iced::Theme; - - pub fn title_bar_active(theme: &Theme) -> container::Appearance { - let palette = theme.extended_palette(); - - container::Appearance { - text_color: Some(palette.background.strong.text), - background: Some(palette.background.strong.color.into()), - ..Default::default() - } - } - - pub fn title_bar_focused(theme: &Theme) -> container::Appearance { - let palette = theme.extended_palette(); - - container::Appearance { - text_color: Some(palette.primary.strong.text), - background: Some(palette.primary.strong.color.into()), - ..Default::default() - } - } - - pub fn pane_active(theme: &Theme) -> container::Appearance { - let palette = theme.extended_palette(); - - container::Appearance { - background: Some(palette.background.weak.color.into()), - border_width: 2.0, - border_color: palette.background.strong.color, - ..Default::default() - } - } - - pub fn pane_focused(theme: &Theme) -> container::Appearance { - let palette = theme.extended_palette(); +fn window_view<'a>( + id: window::Id, + scale_input: &'a str, + title: &'a str, +) -> Element<'a, Message> { + let scale_input = column![ + text("Window scale factor:"), + text_input("Window Scale", scale_input, move |msg| { + Message::ScaleInputChanged(id, msg) + }) + .on_submit(Message::ScaleChanged(id, scale_input.to_string())) + ]; + + let title_input = column![ + text("Window title:"), + text_input("Window Title", title, move |msg| { + Message::TitleChanged(id, msg) + }) + ]; + + let new_window_button = + button(text("New Window")).on_press(Message::NewWindow); + + let content = scrollable( + column![scale_input, title_input, new_window_button] + .spacing(50) + .width(Length::Fill) + .align_items(Alignment::Center), + ); - container::Appearance { - background: Some(palette.background.weak.color.into()), - border_width: 2.0, - border_color: palette.primary.strong.color, - ..Default::default() - } - } + container(content).width(200).center_x().into() } |