feat: add tiles from gpui-components

This commit is contained in:
2024-12-18 07:54:40 +07:00
parent 0682612d42
commit 407db7a7d5
13 changed files with 1018 additions and 182 deletions

View File

@@ -5,9 +5,9 @@ mod panel;
mod stack_panel;
mod state;
mod tab_panel;
mod tiles;
use anyhow::Result;
use gpui::{
actions, canvas, div, prelude::FluentBuilder, AnyElement, AnyView, AppContext, Axis, Bounds,
Edges, Entity as _, EntityId, EventEmitter, InteractiveElement as _, IntoElement,
@@ -21,6 +21,7 @@ pub use panel::*;
pub use stack_panel::*;
pub use state::*;
pub use tab_panel::*;
pub use tiles::*;
use crate::theme::ActiveTheme;
@@ -74,7 +75,7 @@ pub struct DockArea {
pub enum DockItem {
/// Split layout
Split {
axis: gpui::Axis,
axis: Axis,
items: Vec<DockItem>,
sizes: Vec<Option<Pixels>>,
view: View<StackPanel>,
@@ -87,6 +88,11 @@ pub enum DockItem {
},
/// Panel layout
Panel { view: Arc<dyn PanelView> },
/// Tiles layout
Tiles {
items: Vec<TileItem>,
view: View<Tiles>,
},
}
impl DockItem {
@@ -153,6 +159,51 @@ impl DockItem {
Self::Panel { view: panel }
}
/// Create DockItem with tiles layout
///
/// This items and metas should have the same length.
pub fn tiles(
items: Vec<DockItem>,
metas: Vec<impl Into<TileMeta> + Copy>,
dock_area: &WeakView<DockArea>,
cx: &mut WindowContext,
) -> Self {
assert!(items.len() == metas.len());
let tile_panel = cx.new_view(|cx| {
let mut tiles = Tiles::new(cx);
for (ix, item) in items.clone().into_iter().enumerate() {
match item {
DockItem::Tabs { view, .. } => {
let meta: TileMeta = metas[ix].into();
let tile_item =
TileItem::new(Arc::new(view), meta.bounds).z_index(meta.z_index);
tiles.add_item(tile_item, dock_area, cx);
}
_ => {
// Ignore non-tabs items
}
}
}
tiles
});
cx.defer({
let tile_panel = tile_panel.clone();
let dock_area = dock_area.clone();
move |cx| {
_ = dock_area.update(cx, |this, cx| {
this.subscribe_panel(&tile_panel, cx);
});
}
});
Self::Tiles {
items: tile_panel.read(cx).panels.clone(),
view: tile_panel,
}
}
/// Create DockItem with tabs layout, items are displayed as tabs.
///
/// The `active_ix` is the index of the active tab, if `None` the first tab is active.
@@ -201,10 +252,11 @@ impl DockItem {
}
/// Returns the views of the dock item.
fn view(&self) -> Arc<dyn PanelView> {
pub fn view(&self) -> Arc<dyn PanelView> {
match self {
Self::Split { view, .. } => Arc::new(view.clone()),
Self::Tabs { view, .. } => Arc::new(view.clone()),
Self::Tiles { view, .. } => Arc::new(view.clone()),
Self::Panel { view, .. } => view.clone(),
}
}
@@ -217,6 +269,14 @@ impl DockItem {
}
Self::Tabs { items, .. } => items.iter().find(|item| *item == &panel).cloned(),
Self::Panel { view } => Some(view.clone()),
Self::Tiles { items, .. } => items.iter().find_map(|item| {
#[allow(clippy::op_ref)]
if &item.panel == &panel {
Some(item.panel.clone())
} else {
None
}
}),
}
}
@@ -252,6 +312,7 @@ impl DockItem {
stack_panel.add_panel(new_item.view(), None, dock_area.clone(), cx);
});
}
Self::Tiles { .. } => {}
Self::Panel { .. } => {}
}
}
@@ -269,6 +330,7 @@ impl DockItem {
item.set_collapsed(collapsed, cx);
}
}
DockItem::Tiles { .. } => {}
DockItem::Panel { .. } => {}
}
}
@@ -278,6 +340,7 @@ impl DockItem {
match self {
DockItem::Tabs { view, .. } => Some(view.clone()),
DockItem::Split { view, .. } => view.read(cx).left_top_tab_panel(true, cx),
DockItem::Tiles { .. } => None,
DockItem::Panel { .. } => None,
}
}
@@ -287,6 +350,7 @@ impl DockItem {
match self {
DockItem::Tabs { view, .. } => Some(view.clone()),
DockItem::Split { view, .. } => view.read(cx).right_top_tab_panel(true, cx),
DockItem::Tiles { .. } => None,
DockItem::Panel { .. } => None,
}
}
@@ -601,7 +665,7 @@ impl DockArea {
Ok(())
}
/// Dump the dock panels layout to DockItemState.
/// Dump the dock panels layout to PanelState.
///
/// See also [DockArea::load].
pub fn dump(&self, cx: &AppContext) -> DockAreaState {
@@ -658,6 +722,9 @@ impl DockArea {
DockItem::Tabs { .. } => {
// We subscribe to the tab panel event in StackPanel's insert_panel
}
DockItem::Tiles { .. } => {
// We subscribe to the tab panel event in Tiles's [`add_item`](Tiles::add_item)
}
DockItem::Panel { .. } => {
// Not supported
}
@@ -727,6 +794,7 @@ impl DockArea {
match &self.items {
DockItem::Split { view, .. } => view.clone().into_any_element(),
DockItem::Tabs { view, .. } => view.clone().into_any_element(),
DockItem::Tiles { view, .. } => view.clone().into_any_element(),
DockItem::Panel { view, .. } => view.clone().view().into_any_element(),
}
}
@@ -774,41 +842,50 @@ impl Render for DockArea {
if let Some(zoom_view) = self.zoom_view.clone() {
this.child(zoom_view)
} else {
this.child(
div()
.flex()
.flex_row()
.h_full()
// Left dock
.when_some(self.left_dock.clone(), |this, dock| {
this.child(div().flex().flex_none().child(dock))
.bg(cx.theme().sidebar)
.text_color(cx.theme().sidebar_foreground)
})
// Center
.child(
match &self.items {
DockItem::Tiles { view, .. } => {
// render tiles
this.child(view.clone())
}
_ => {
// render dock
this.child(
div()
.flex()
.flex_1()
.flex_col()
.overflow_hidden()
// Top center
.flex_row()
.h_full()
// Left dock
.when_some(self.left_dock.clone(), |this, dock| {
this.bg(cx.theme().sidebar)
.text_color(cx.theme().sidebar_foreground)
.child(div().flex().flex_none().child(dock))
})
// Center
.child(
div()
.flex()
.flex_1()
.flex_col()
.overflow_hidden()
.child(self.render_items(cx)),
// Top center
.child(
div()
.flex_1()
.overflow_hidden()
.child(self.render_items(cx)),
)
// Bottom Dock
.when_some(self.bottom_dock.clone(), |this, dock| {
this.child(dock)
}),
)
// Bottom Dock
.when_some(self.bottom_dock.clone(), |this, dock| {
this.child(dock)
// Right Dock
.when_some(self.right_dock.clone(), |this, dock| {
this.child(div().flex().flex_none().child(dock))
}),
)
// Right Dock
.when_some(self.right_dock.clone(), |this, dock| {
this.child(div().flex().flex_none().child(dock))
}),
)
}
}
}
})
}