diff options
author | 2022-07-14 10:37:33 -0300 | |
---|---|---|
committer | 2023-01-09 11:27:04 -0800 | |
commit | 01bad4f89654d65b0d6a65a8df99c387cbadf7fe (patch) | |
tree | 95b5b4ac4f2a828179b2faec580d54120430e856 /examples/multi_window | |
parent | 8f53df560e1bde33e874977e5115cd0f9301640d (diff) | |
download | iced-01bad4f89654d65b0d6a65a8df99c387cbadf7fe.tar.gz iced-01bad4f89654d65b0d6a65a8df99c387cbadf7fe.tar.bz2 iced-01bad4f89654d65b0d6a65a8df99c387cbadf7fe.zip |
duplicate `pane_grid` example to `multi_window`
Diffstat (limited to 'examples/multi_window')
-rw-r--r-- | examples/multi_window/Cargo.toml | 12 | ||||
-rw-r--r-- | examples/multi_window/src/main.rs | 370 |
2 files changed, 355 insertions, 27 deletions
diff --git a/examples/multi_window/Cargo.toml b/examples/multi_window/Cargo.toml new file mode 100644 index 00000000..9c3d0f21 --- /dev/null +++ b/examples/multi_window/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "multi_window" +version = "0.1.0" +authors = ["Richard Custodio <richardsoncusto@gmail.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"] } +iced_native = { path = "../../native" } +iced_lazy = { path = "../../lazy" }
\ No newline at end of file diff --git a/examples/multi_window/src/main.rs b/examples/multi_window/src/main.rs index 0ba6a591..ae8fa22b 100644 --- a/examples/multi_window/src/main.rs +++ b/examples/multi_window/src/main.rs @@ -1,58 +1,374 @@ -use iced::multi_window::Application; -use iced::pure::{button, column, text, Element}; -use iced::{window, Alignment, Command, Settings}; +use iced::alignment::{self, Alignment}; +use iced::executor; +use iced::keyboard; +use iced::theme::{self, Theme}; +use iced::widget::pane_grid::{self, PaneGrid}; +use iced::widget::{button, column, container, row, scrollable, text}; +use iced::{ + Application, Color, Command, Element, Length, Settings, Size, Subscription, +}; +use iced_lazy::responsive; +use iced_native::{event, subscription, Event}; pub fn main() -> iced::Result { - Counter::run(Settings::default()) + Example::run(Settings::default()) } -struct Counter { - value: i32, +struct Example { + panes: pane_grid::State<Pane>, + panes_created: usize, + focus: Option<pane_grid::Pane>, } #[derive(Debug, Clone, Copy)] enum Message { - IncrementPressed, - DecrementPressed, + Split(pane_grid::Axis, pane_grid::Pane), + SplitFocused(pane_grid::Axis), + FocusAdjacent(pane_grid::Direction), + Clicked(pane_grid::Pane), + Dragged(pane_grid::DragEvent), + Resized(pane_grid::ResizeEvent), + TogglePin(pane_grid::Pane), + Close(pane_grid::Pane), + CloseFocused, } -impl Application for Counter { - type Flags = (); - type Executor = iced::executor::Default; +impl Application for Example { type Message = Message; + type Theme = Theme; + type Executor = executor::Default; + type Flags = (); fn new(_flags: ()) -> (Self, Command<Message>) { - (Self { value: 0 }, Command::none()) - } + let (panes, _) = pane_grid::State::new(Pane::new(0)); - fn title(&self) -> String { - String::from("MultiWindow - Iced") + ( + Example { + panes, + panes_created: 1, + focus: None, + }, + Command::none(), + ) } - fn windows(&self) -> Vec<(window::Id, iced::window::Settings)> { - todo!() + fn title(&self) -> String { + String::from("Pane grid - Iced") } fn update(&mut self, message: Message) -> Command<Message> { match message { - Message::IncrementPressed => { - self.value += 1; + Message::Split(axis, pane) => { + let result = self.panes.split( + axis, + &pane, + Pane::new(self.panes_created), + ); + + if let Some((pane, _)) = result { + self.focus = Some(pane); + } + + self.panes_created += 1; + } + Message::SplitFocused(axis) => { + if let Some(pane) = self.focus { + let result = self.panes.split( + axis, + &pane, + Pane::new(self.panes_created), + ); + + if let Some((pane, _)) = result { + self.focus = Some(pane); + } + + self.panes_created += 1; + } + } + Message::FocusAdjacent(direction) => { + if let Some(pane) = self.focus { + if let Some(adjacent) = + self.panes.adjacent(&pane, direction) + { + self.focus = Some(adjacent); + } + } + } + Message::Clicked(pane) => { + self.focus = Some(pane); + } + Message::Resized(pane_grid::ResizeEvent { split, ratio }) => { + self.panes.resize(&split, ratio); + } + Message::Dragged(pane_grid::DragEvent::Dropped { + pane, + target, + }) => { + self.panes.swap(&pane, &target); } - Message::DecrementPressed => { - self.value -= 1; + Message::Dragged(_) => {} + Message::TogglePin(pane) => { + if let Some(Pane { is_pinned, .. }) = self.panes.get_mut(&pane) + { + *is_pinned = !*is_pinned; + } + } + Message::Close(pane) => { + if let Some((_, sibling)) = self.panes.close(&pane) { + self.focus = Some(sibling); + } + } + Message::CloseFocused => { + if let Some(pane) = self.focus { + if let Some(Pane { is_pinned, .. }) = self.panes.get(&pane) + { + if !is_pinned { + if let Some((_, sibling)) = self.panes.close(&pane) + { + self.focus = Some(sibling); + } + } + } + } } } Command::none() } + fn subscription(&self) -> Subscription<Message> { + 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), + _ => None, + } + }) + } + fn view(&self) -> Element<Message> { - column() - .padding(20) - .align_items(Alignment::Center) - .push(button("Increment").on_press(Message::IncrementPressed)) - .push(text(self.value.to_string()).size(50)) - .push(button("Decrement").on_press(Message::DecrementPressed)) + let focus = self.focus; + let total_panes = self.panes.len(); + + let pane_grid = PaneGrid::new(&self.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(Message::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)) + .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, 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(Message::Clicked) + .on_drag(Message::Dragged) + .on_resize(10, Message::Resized); + + container(pane_grid) + .width(Length::Fill) + .height(Length::Fill) + .padding(10) .into() } } + +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<Message> { + 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(Message::SplitFocused(Axis::Vertical)), + KeyCode::H => Some(Message::SplitFocused(Axis::Horizontal)), + KeyCode::W => Some(Message::CloseFocused), + _ => direction.map(Message::FocusAdjacent), + } +} + +struct Pane { + id: usize, + pub is_pinned: bool, +} + +impl Pane { + fn new(id: usize) -> Self { + Self { + id, + is_pinned: false, + } + } +} + +fn view_content<'a>( + pane: pane_grid::Pane, + total_panes: usize, + is_pinned: bool, + size: Size, +) -> Element<'a, Message> { + 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", + Message::Split(pane_grid::Axis::Horizontal, pane), + ), + button( + "Split vertically", + Message::Split(pane_grid::Axis::Vertical, pane), + ) + ] + .spacing(5) + .max_width(150); + + if total_panes > 1 && !is_pinned { + controls = controls.push( + button("Close", Message::Close(pane)) + .style(theme::Button::Destructive), + ); + } + + let content = column![ + text(format!("{}x{}", size.width, size.height)).size(24), + controls, + ] + .width(Length::Fill) + .spacing(10) + .align_items(Alignment::Center); + + container(scrollable(content)) + .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, +) -> Element<'a, Message> { + let mut button = button(text("Close").size(14)) + .style(theme::Button::Destructive) + .padding(3); + + if total_panes > 1 && !is_pinned { + button = button.on_press(Message::Close(pane)); + } + + button.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() + } + } +} |