From d5ffd4a1fb5ec62245765e0914c75b5158642c71 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Fri, 6 Oct 2023 18:37:28 -0400 Subject: [PATCH] Add `Pane` and `PaneGroup` components --- crates/storybook2/src/storybook2.rs | 2 +- crates/ui2/src/components.rs | 2 + crates/ui2/src/components/panes.rs | 131 ++++++++++++++++++++++++ crates/ui2/src/components/workspace.rs | 133 ++++++++++++++----------- 4 files changed, 211 insertions(+), 57 deletions(-) create mode 100644 crates/ui2/src/components/panes.rs diff --git a/crates/storybook2/src/storybook2.rs b/crates/storybook2/src/storybook2.rs index e371001d2df7671e0c14fff2c67406982b682a96..348d8268097c80a43b59d0b8426f314075983760 100644 --- a/crates/storybook2/src/storybook2.rs +++ b/crates/storybook2/src/storybook2.rs @@ -104,7 +104,7 @@ impl StoryWrapper { div() .flex() .flex_col() - .h_full() + .size_full() .child_any(self.selector.story()) }) } diff --git a/crates/ui2/src/components.rs b/crates/ui2/src/components.rs index 86fe7bcfb37a9479411574799aaa93460f17176e..7ff6453cb8e8eb15fa12d110fbcb3026d25c348e 100644 --- a/crates/ui2/src/components.rs +++ b/crates/ui2/src/components.rs @@ -3,6 +3,7 @@ mod buffer; mod icon_button; mod list; mod panel; +mod panes; mod project_panel; mod status_bar; mod workspace; @@ -12,6 +13,7 @@ pub use buffer::*; pub use icon_button::*; pub use list::*; pub use panel::*; +pub use panes::*; pub use project_panel::*; pub use status_bar::*; pub use workspace::*; diff --git a/crates/ui2/src/components/panes.rs b/crates/ui2/src/components/panes.rs new file mode 100644 index 0000000000000000000000000000000000000000..4c1ec66099c91bed38ef98505052861b654001f6 --- /dev/null +++ b/crates/ui2/src/components/panes.rs @@ -0,0 +1,131 @@ +use std::marker::PhantomData; + +use gpui3::{hsla, Hsla, Length, Size}; + +use crate::prelude::*; +use crate::theme; + +#[derive(Default, PartialEq)] +pub enum SplitDirection { + #[default] + Horizontal, + Vertical, +} + +#[derive(Element)] +pub struct Pane { + state_type: PhantomData, + scroll_state: ScrollState, + size: Size, + fill: Hsla, + children: HackyChildren, + payload: HackyChildrenPayload, +} + +impl Pane { + pub fn new( + scroll_state: ScrollState, + size: Size, + children: HackyChildren, + payload: HackyChildrenPayload, + ) -> Self { + // Fill is only here for debugging purposes, remove before release + let system_color = SystemColor::new(); + + Self { + state_type: PhantomData, + scroll_state, + size, + fill: hsla(0.3, 0.3, 0.3, 1.), + // fill: system_color.transparent, + children, + payload, + } + } + + pub fn fill(mut self, fill: Hsla) -> Self { + self.fill = fill; + self + } + + fn render(&mut self, cx: &mut ViewContext) -> impl Element { + let theme = theme(cx); + + div() + .flex() + .flex_initial() + .fill(self.fill) + .w(self.size.width) + .h(self.size.height) + .overflow_y_scroll(self.scroll_state.clone()) + .children_any((self.children)(cx, self.payload.as_ref())) + } +} + +#[derive(Element)] +pub struct PaneGroup { + state_type: PhantomData, + groups: Vec>, + panes: Vec>, + split_direction: SplitDirection, +} + +impl PaneGroup { + pub fn new_groups(groups: Vec>, split_direction: SplitDirection) -> Self { + Self { + state_type: PhantomData, + groups, + panes: Vec::new(), + split_direction, + } + } + + pub fn new_panes(panes: Vec>, split_direction: SplitDirection) -> Self { + Self { + state_type: PhantomData, + groups: Vec::new(), + panes, + split_direction, + } + } + + fn render(&mut self, cx: &mut ViewContext) -> impl Element { + let theme = theme(cx); + + if !self.panes.is_empty() { + let el = div() + .flex() + .flex_1() + .gap_px() + .w_full() + .h_full() + .fill(theme.lowest.base.default.background) + .children(self.panes.iter_mut().map(|pane| pane.render(cx))); + + if self.split_direction == SplitDirection::Horizontal { + return el; + } else { + return el.flex_col(); + } + } + + if !self.groups.is_empty() { + let el = div() + .flex() + .flex_1() + .gap_px() + .w_full() + .h_full() + .fill(theme.lowest.base.default.background) + .children(self.groups.iter_mut().map(|group| group.render(cx))); + + if self.split_direction == SplitDirection::Horizontal { + return el; + } else { + return el.flex_col(); + } + } + + unreachable!() + } +} diff --git a/crates/ui2/src/components/workspace.rs b/crates/ui2/src/components/workspace.rs index fd4ab72101972300c616bc669583fd988543ca43..ba390074315e5ee1258cd830a8c85da1d26b8a00 100644 --- a/crates/ui2/src/components/workspace.rs +++ b/crates/ui2/src/components/workspace.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use chrono::DateTime; use gpui3::{relative, rems, Size}; -use crate::prelude::*; +use crate::{prelude::*, Pane, PaneGroup, SplitDirection}; use crate::{theme, v_stack, Panel, PanelAllowedSides, PanelSide, ProjectPanel, StatusBar}; #[derive(Element)] @@ -30,62 +30,81 @@ impl WorkspaceElement { pub fn render(&mut self, cx: &mut ViewContext) -> impl Element { let theme = theme(cx).clone(); - // let temp_size = rems(36.).into(); + let temp_size = rems(36.).into(); - // let root_group = PaneGroup::new_groups( - // vec![ - // PaneGroup::new_panes( - // vec![ - // Pane::new( - // ScrollState::default(), - // Size { - // width: relative(1.).into(), - // height: temp_size, - // }, - // |_, payload| { - // let theme = payload.downcast_ref::>().unwrap(); + let root_group = PaneGroup::new_groups( + vec![ + PaneGroup::new_panes( + vec![ + Pane::new( + ScrollState::default(), + Size { + width: relative(1.).into(), + height: temp_size, + }, + |_, payload| { + let theme = payload.downcast_ref::>().unwrap(); - // vec![EditorPane::new(hello_world_rust_editor_with_status_example( - // &theme, - // )) - // .into_any()] - // }, - // Box::new(theme.clone()), - // ), - // Pane::new( - // ScrollState::default(), - // Size { - // width: relative(1.).into(), - // height: temp_size, - // }, - // |_, _| vec![Terminal::new().into_any()], - // Box::new(()), - // ), - // ], - // SplitDirection::Vertical, - // ), - // PaneGroup::new_panes( - // vec![Pane::new( - // ScrollState::default(), - // Size { - // width: relative(1.).into(), - // height: relative(1.).into(), - // }, - // |_, payload| { - // let theme = payload.downcast_ref::>().unwrap(); + vec![ + div() + .w_full() + .fill(gpui3::rgb::(0xff0000)) + .into_any(), // EditorPane::new(hello_world_rust_editor_with_status_example( + // &theme, + // )) + // .into_any() + ] + }, + Box::new(theme.clone()), + ), + Pane::new( + ScrollState::default(), + Size { + width: relative(1.).into(), + height: temp_size, + }, + |_, _| { + vec![ + div() + .w_full() + .fill(gpui3::rgb::(0x00ff00)) + .into_any(), + // Terminal::new().into_any() + ] + }, + Box::new(()), + ), + ], + SplitDirection::Vertical, + ), + PaneGroup::new_panes( + vec![Pane::new( + ScrollState::default(), + Size { + width: relative(1.).into(), + height: relative(1.).into(), + }, + |_, payload| { + let theme = payload.downcast_ref::>().unwrap(); - // vec![EditorPane::new(hello_world_rust_editor_with_status_example( - // &theme, - // )) - // .into_any()] - // }, - // Box::new(theme.clone()), - // )], - // SplitDirection::Vertical, - // ), - // ], - // SplitDirection::Horizontal, - // ); + vec![ + div() + .w_full() + .fill(gpui3::rgb::(0x0000ff)) + .into_any(), + // EditorPane::new(hello_world_rust_editor_with_status_example( + // &theme, + // )) + // .into_any() + ] + }, + Box::new(theme.clone()), + )], + SplitDirection::Vertical, + ), + ], + SplitDirection::Horizontal, + ); div() .relative() @@ -130,7 +149,8 @@ impl WorkspaceElement { .flex_1() // CSS Hack: Flex 1 has to have a set height to properly fill the space // Or it will give you a height of 0 - .h_px(), // .child(root_group), + .h_px() + .child(root_group), ) .child( Panel::new( @@ -153,7 +173,8 @@ impl WorkspaceElement { Box::new(()), ) .side(PanelSide::Right), - ), // .child( + ), + // .child( // Panel::new( // self.right_panel_scroll_state.clone(), // |_, payload| {