Files
Ely-GPUI-Components/examples/gallery/pages/layout/systems.rs
T

272 lines
8.9 KiB
Rust

use ely_gpui_component::{
buttons::{Button, ButtonVariant},
layout::{Dock, DockPanel, DockSide, FloatingPanel, PaneGroup, Transform, Viewport, Workspace},
primitives::IconName,
theme::{ActiveTheme, Radius, TextSize},
typography::{Caption, Paragraph},
};
use gpui::{
AnyElement, App, Axis, Entity, IntoElement, ParentElement, SharedString, Styled, Window, div,
point, prelude::*, px,
};
use super::{basics::tile, shells::frame};
use crate::{
probe::probe,
ui::{code, row, section},
};
fn demo_dock(cx: &mut App) -> Dock {
let panel = |id: &str, title: &str, icon| DockPanel {
id: SharedString::from(id.to_string()),
title: SharedString::from(title.to_string()),
icon,
};
let mut dock = Dock::new(
|_, cx| {
div()
.size_full()
.flex()
.items_center()
.justify_center()
.text_color(cx.theme().colors.fg_subtle)
.child("Center. Drag a tab onto a zone.")
.into_any_element()
},
|id, _, cx| {
div()
.p_3()
.text_size(cx.theme().text_size(TextSize::Sm))
.text_color(cx.theme().colors.fg_muted)
.child(SharedString::from(format!("{id} panel")))
.into_any_element()
},
cx,
);
dock.add(panel("files", "Files", IconName::Folder), DockSide::Left);
dock.add(
panel("outline", "Outline", IconName::Layers),
DockSide::Left,
);
dock.add(panel("search", "Search", IconName::Search), DockSide::Right);
dock.add(
panel("terminal", "Terminal", IconName::Terminal),
DockSide::Bottom,
);
dock
}
fn demo_panes(cx: &mut Context<PaneGroup>) -> PaneGroup {
let mut group = PaneGroup::new(|id, _, cx| {
div()
.size_full()
.p_3()
.text_color(cx.theme().colors.fg_subtle)
.child(SharedString::from(format!("buffer {id}")))
.into_any_element()
});
group.split(1, Axis::Horizontal, cx);
group
}
/// The dock and pane group shared by the demos and the workspace section.
fn systems(window: &mut Window, cx: &mut App) -> (Entity<Dock>, Entity<PaneGroup>) {
let dock = window.use_keyed_state("demo-dock", cx, |_, cx| demo_dock(cx));
let panes = window.use_keyed_state("demo-panes", cx, |_, cx| demo_panes(cx));
(dock, panes)
}
pub fn dock(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let (dock, _) = systems(window, cx);
section(
"Dock / DockPanel",
"Panels dock on any edge, tab together, and float.",
cx,
)
.child(probe("dock", frame(760.0, 380.0, cx).child(dock)))
}
pub fn dock_zones(cx: &App) -> impl IntoElement + use<> {
section(
"DockZone / DropIndicator",
"While a tab drags, the drop zones appear and the one below lights.",
cx,
)
.child(Caption::new(
"Drag a tab across the dock above to see them.",
))
}
pub fn floating(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let open = window.use_keyed_state("floating-open", cx, |_, _| false);
let shown = *open.read(cx);
section(
"FloatingPanel",
"Drag the title bar. It stays inside the window.",
cx,
)
.child(
row()
.child(probe(
"floating-open",
Button::new(
"floating-open",
if shown { "Hide panel" } else { "Show panel" },
)
.on_click(move |_, _, cx| {
open.update(cx, |open, cx| {
*open = !*open;
cx.notify();
})
}),
))
.when(shown, |row| {
row.child(
FloatingPanel::new("demo-float", "Inspector", point(px(720.0), px(160.0)))
.w(px(240.0))
.child(Caption::new("Floating panels sit above the page."))
.child(tile("Opacity 100%", cx)),
)
}),
)
}
pub fn panes(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let (_, panes) = systems(window, cx);
section(
"Pane / PaneGroup",
"Split right or down from any pane; close all but one.",
cx,
)
.child(probe("panes", frame(760.0, 300.0, cx).child(panes)))
}
pub fn workspace(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let (dock, panes) = systems(window, cx);
let saved = window.use_keyed_state("workspace-json", cx, |_, _| None::<String>);
let report = window.use_keyed_state("workspace-report", cx, |_, _| SharedString::from(""));
let preview: Option<String> = saved.read(cx).clone();
let note = report.read(cx).clone();
let (save_dock, save_panes, save_to) = (dock.clone(), panes.clone(), saved.clone());
let (load_from, load_note) = (saved, report.clone());
section(
"Workspace",
"Layout to versioned JSON and back, all or nothing.",
cx,
)
.child(
row()
.child(probe(
"workspace-save",
Button::new("workspace-save", "Save layout")
.icon(IconName::Save)
.on_click(move |_, _, cx| {
let json =
Workspace::capture(save_dock.read(cx), save_panes.read(cx)).to_json();
save_to.update(cx, |saved, cx| {
*saved = Some(json);
cx.notify();
})
}),
))
.child(probe(
"workspace-restore",
Button::new("workspace-restore", "Restore")
.variant(ButtonVariant::Ghost)
.icon(IconName::RotateCcw)
.disabled(preview.is_none())
.on_click(move |_, _, cx| {
let json = load_from
.read(cx)
.clone()
.expect("restore is disabled until a layout is saved");
let outcome = Workspace::from_json(&json)
.and_then(|layout| layout.apply(&dock, &panes, cx));
let text = match outcome {
Ok(()) => "Restored.".to_string(),
Err(error) => format!("Refused: {error:#}"),
};
load_note.update(cx, |note, cx| {
*note = SharedString::from(text);
cx.notify();
})
}),
))
.child(Caption::new(note)),
)
.when_some(preview, |block, json| {
let excerpt: String = json.lines().take(12).collect::<Vec<_>>().join("\n");
block.child(code(excerpt, cx))
})
}
fn blob(
at: gpui::Point<gpui::Pixels>,
size: f32,
transform: Transform,
label: &'static str,
cx: &App,
) -> AnyElement {
let theme = cx.theme();
let local = transform.apply(at);
div()
.absolute()
.left(local.x)
.top(local.y)
.w(px(size) * transform.scale)
.h(px(size * 0.6) * transform.scale)
.rounded(theme.radius(Radius::Lg))
.border_1()
.border_color(theme.colors.border_strong)
.bg(theme.colors.surface)
.flex()
.items_center()
.justify_center()
.text_color(theme.colors.fg_muted)
.child(label)
.into_any_element()
}
pub fn viewport(cx: &App) -> impl IntoElement + use<> {
section(
"Viewport",
"Drag to pan. Hold ⌘ or Ctrl and scroll to zoom at the pointer.",
cx,
)
.child(probe(
"viewport",
frame(640.0, 260.0, cx)
.bg(cx.theme().colors.sunken)
.child(Viewport::new("demo-viewport", |transform, _, cx| {
div()
.size_full()
.child(blob(
point(px(60.0), px(50.0)),
140.0,
transform,
"Idea",
cx,
))
.child(blob(
point(px(260.0), px(110.0)),
140.0,
transform,
"Draft",
cx,
))
.child(blob(
point(px(460.0), px(40.0)),
120.0,
transform,
"Ship",
cx,
))
.into_any_element()
})),
))
.child(
Paragraph::new("Content places itself with the transform; zoom stays between 0.1 and 8.")
.max_w(px(560.0)),
)
}