diff options
Diffstat (limited to 'examples/multi_window_panes/src/main.rs')
-rw-r--r-- | examples/multi_window_panes/src/main.rs | 639 |
1 files changed, 0 insertions, 639 deletions
diff --git a/examples/multi_window_panes/src/main.rs b/examples/multi_window_panes/src/main.rs deleted file mode 100644 index b1d0a3bc..00000000 --- a/examples/multi_window_panes/src/main.rs +++ /dev/null @@ -1,639 +0,0 @@ -use iced::alignment::{self, Alignment}; -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::window; -use iced::{executor, time}; -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(); - - Example::run(Settings::default()) -} - -struct Example { - windows: HashMap<window::Id, Window>, - panes_created: usize, - count: usize, - _focused: window::Id, -} - -#[derive(Debug)] -struct Window { - title: String, - scale: f64, - theme: Theme, - panes: pane_grid::State<Pane>, - focus: Option<pane_grid::Pane>, -} - -#[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, -} - -impl 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, - theme: Theme::default(), - }; - - ( - Example { - windows: HashMap::from([(window::Id::MAIN, window)]), - panes_created: 1, - count: 0, - _focused: window::Id::MAIN, - }, - Command::none(), - ) - } - - fn title(&self, window: window::Id) -> String { - self.windows - .get(&window) - .map(|w| w.title.clone()) - .unwrap_or(String::from("New Window")) - } - - 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); - - 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), - theme: if self.windows.len() % 2 == 0 { - Theme::Light - } else { - Theme::Dark - }, - }; - - 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(_) => {} - 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; - } - } - - 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: window::Id) -> Element<Message> { - let window_id = window; - - if let Some(window) = self.windows.get(&window) { - 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 - }); - - 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 - }) - }) - .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) - } - - fn theme(&self, window: Id) -> Theme { - self.windows.get(&window).expect("Window not found!").theme.clone() - } -} - -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 - } -} - -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) - } -} - -#[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 { - Self { - id, - scrollable_id: scrollable::Id::unique(), - axis, - is_pinned: false, - is_moving: false, - snapped: false, - } - } -} - -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), - ); - } - - 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(); - - container::Appearance { - background: Some(palette.background.weak.color.into()), - border_width: 2.0, - border_color: palette.primary.strong.color, - ..Default::default() - } - } -} |