diff options
Diffstat (limited to 'examples/multi_window/src')
| -rw-r--r-- | examples/multi_window/src/main.rs | 654 | 
1 files changed, 101 insertions, 553 deletions
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()  }  | 
