diff options
Diffstat (limited to 'examples/pane_grid')
-rw-r--r-- | examples/pane_grid/Cargo.toml | 3 | ||||
-rw-r--r-- | examples/pane_grid/src/main.rs | 246 |
2 files changed, 200 insertions, 49 deletions
diff --git a/examples/pane_grid/Cargo.toml b/examples/pane_grid/Cargo.toml index 3ed912ac..e489f210 100644 --- a/examples/pane_grid/Cargo.toml +++ b/examples/pane_grid/Cargo.toml @@ -6,4 +6,5 @@ edition = "2018" publish = false [dependencies] -iced = { path = "../.." } +iced = { path = "../..", features = ["debug"] } +iced_native = { path = "../../native" } diff --git a/examples/pane_grid/src/main.rs b/examples/pane_grid/src/main.rs index c4946645..3bd8aa25 100644 --- a/examples/pane_grid/src/main.rs +++ b/examples/pane_grid/src/main.rs @@ -1,16 +1,19 @@ use iced::{ - button, keyboard, pane_grid, scrollable, Align, Button, Column, Container, - Element, HorizontalAlignment, Length, PaneGrid, Sandbox, Scrollable, - Settings, Text, + button, executor, keyboard, pane_grid, scrollable, Align, Application, + Button, Clipboard, Color, Column, Command, Container, Element, + HorizontalAlignment, Length, PaneGrid, Row, Scrollable, Settings, + Subscription, Text, }; +use iced_native::{event, subscription, Event}; pub fn main() -> iced::Result { Example::run(Settings::default()) } struct Example { - panes: pane_grid::State<Content>, + panes: pane_grid::State<Pane>, panes_created: usize, + focus: Option<pane_grid::Pane>, } #[derive(Debug, Clone, Copy)] @@ -18,59 +21,82 @@ enum Message { 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 Sandbox for Example { +impl Application for Example { type Message = Message; - - fn new() -> Self { - let (panes, _) = pane_grid::State::new(Content::new(0)); - - Example { - panes, - panes_created: 1, - } + type Executor = executor::Default; + type Flags = (); + + fn new(_flags: ()) -> (Self, Command<Message>) { + let (panes, _) = pane_grid::State::new(Pane::new(0)); + + ( + Example { + panes, + panes_created: 1, + focus: None, + }, + Command::none(), + ) } fn title(&self) -> String { String::from("Pane grid - Iced") } - fn update(&mut self, message: Message) { + fn update( + &mut self, + message: Message, + _clipboard: &mut Clipboard, + ) -> Command<Message> { match message { Message::Split(axis, pane) => { - let _ = self.panes.split( + let result = self.panes.split( axis, &pane, - Content::new(self.panes_created), + 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.panes.active() { - let _ = self.panes.split( + if let Some(pane) = self.focus { + let result = self.panes.split( axis, &pane, - Content::new(self.panes_created), + 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.panes.active() { + if let Some(pane) = self.focus { if let Some(adjacent) = self.panes.adjacent(&pane, direction) { - self.panes.focus(&adjacent); + self.focus = Some(adjacent); } } } + Message::Clicked(pane) => { + self.focus = Some(pane); + } Message::Resized(pane_grid::ResizeEvent { split, ratio }) => { self.panes.resize(&split, ratio); } @@ -81,38 +107,97 @@ impl Sandbox for Example { self.panes.swap(&pane, &target); } Message::Dragged(_) => {} + Message::TogglePin(pane) => { + if let Some(Pane { is_pinned, .. }) = self.panes.get_mut(&pane) + { + *is_pinned = !*is_pinned; + } + } Message::Close(pane) => { - let _ = self.panes.close(&pane); + if let Some((_, sibling)) = self.panes.close(&pane) { + self.focus = Some(sibling); + } } Message::CloseFocused => { - if let Some(pane) = self.panes.active() { - let _ = self.panes.close(&pane); + 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(&mut self) -> Element<Message> { + let focus = self.focus; let total_panes = self.panes.len(); - let pane_grid = - PaneGrid::new(&mut self.panes, |pane, content, focus| { - let is_focused = focus.is_some(); - let title_bar = - pane_grid::TitleBar::new(format!("Pane {}", content.id)) - .padding(10) - .style(style::TitleBar { is_focused }); - - pane_grid::Content::new(content.view(pane, total_panes)) - .title_bar(title_bar) - .style(style::Pane { is_focused }) - }) - .width(Length::Fill) - .height(Length::Fill) - .spacing(10) - .on_drag(Message::Dragged) - .on_resize(10, Message::Resized) - .on_key_press(handle_hotkey); + let pane_grid = PaneGrid::new(&mut self.panes, |id, pane| { + let is_focused = focus == Some(id); + + let text = if pane.is_pinned { "Unpin" } else { "Pin" }; + let pin_button = + Button::new(&mut pane.pin_button, Text::new(text).size(14)) + .on_press(Message::TogglePin(id)) + .style(style::Button::Pin) + .padding(3); + + let title = Row::with_children(vec![ + pin_button.into(), + Text::new("Pane").into(), + Text::new(pane.content.id.to_string()) + .color(if is_focused { + PANE_ID_COLOR_FOCUSED + } else { + PANE_ID_COLOR_UNFOCUSED + }) + .into(), + ]) + .spacing(5); + + let title_bar = pane_grid::TitleBar::new(title) + .controls(pane.controls.view(id, total_panes, pane.is_pinned)) + .padding(10) + .style(style::TitleBar { is_focused }); + + pane_grid::Content::new(pane.content.view( + id, + total_panes, + pane.is_pinned, + )) + .title_bar(title_bar) + .style(style::Pane { is_focused }) + }) + .width(Length::Fill) + .height(Length::Fill) + .spacing(10) + .on_click(Message::Clicked) + .on_drag(Message::Dragged) + .on_resize(10, Message::Resized); Container::new(pane_grid) .width(Length::Fill) @@ -122,11 +207,22 @@ impl Sandbox for Example { } } -fn handle_hotkey(event: pane_grid::KeyPressEvent) -> Option<Message> { +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 event.key_code { + let direction = match key_code { KeyCode::Up => Some(Direction::Up), KeyCode::Down => Some(Direction::Down), KeyCode::Left => Some(Direction::Left), @@ -134,7 +230,7 @@ fn handle_hotkey(event: pane_grid::KeyPressEvent) -> Option<Message> { _ => None, }; - match event.key_code { + match key_code { KeyCode::V => Some(Message::SplitFocused(Axis::Vertical)), KeyCode::H => Some(Message::SplitFocused(Axis::Horizontal)), KeyCode::W => Some(Message::CloseFocused), @@ -142,6 +238,13 @@ fn handle_hotkey(event: pane_grid::KeyPressEvent) -> Option<Message> { } } +struct Pane { + pub is_pinned: bool, + pub pin_button: button::State, + pub content: Content, + pub controls: Controls, +} + struct Content { id: usize, scroll: scrollable::State, @@ -150,6 +253,21 @@ struct Content { close: button::State, } +struct Controls { + close: button::State, +} + +impl Pane { + fn new(id: usize) -> Self { + Self { + is_pinned: false, + pin_button: button::State::new(), + content: Content::new(id), + controls: Controls::new(), + } + } +} + impl Content { fn new(id: usize) -> Self { Content { @@ -164,6 +282,7 @@ impl Content { &mut self, pane: pane_grid::Pane, total_panes: usize, + is_pinned: bool, ) -> Element<Message> { let Content { scroll, @@ -203,7 +322,7 @@ impl Content { style::Button::Primary, )); - if total_panes > 1 { + if total_panes > 1 && !is_pinned { controls = controls.push(button( close, "Close", @@ -227,7 +346,32 @@ impl Content { } } +impl Controls { + fn new() -> Self { + Self { + close: button::State::new(), + } + } + + pub fn view( + &mut self, + pane: pane_grid::Pane, + total_panes: usize, + is_pinned: bool, + ) -> Element<Message> { + let mut button = + Button::new(&mut self.close, Text::new("Close").size(14)) + .style(style::Button::Control) + .padding(3); + if total_panes > 1 && !is_pinned { + button = button.on_press(Message::Close(pane)); + } + button.into() + } +} + mod style { + use crate::PANE_ID_COLOR_FOCUSED; use iced::{button, container, Background, Color, Vector}; const SURFACE: Color = Color::from_rgb( @@ -275,7 +419,7 @@ mod style { fn style(&self) -> container::Style { container::Style { background: Some(Background::Color(SURFACE)), - border_width: 2, + border_width: 2.0, border_color: if self.is_focused { Color::BLACK } else { @@ -289,6 +433,8 @@ mod style { pub enum Button { Primary, Destructive, + Control, + Pin, } impl button::StyleSheet for Button { @@ -298,12 +444,14 @@ mod style { Button::Destructive => { (None, Color::from_rgb8(0xFF, 0x47, 0x47)) } + Button::Control => (Some(PANE_ID_COLOR_FOCUSED), Color::WHITE), + Button::Pin => (Some(ACTIVE), Color::WHITE), }; button::Style { text_color, background: background.map(Background::Color), - border_radius: 5, + border_radius: 5.0, shadow_offset: Vector::new(0.0, 0.0), ..button::Style::default() } @@ -318,6 +466,8 @@ mod style { a: 0.2, ..active.text_color }), + Button::Control => Some(PANE_ID_COLOR_FOCUSED), + Button::Pin => Some(HOVERED), }; button::Style { |