Canvas · Panels: layers, inspector, alignment, assets, style and layout editors
LayerPanel lists the canvas's layers topmost first on lists::Tree: a box shows or hides each, F2 renames, a drag restacks into a new paint order. InspectorPanel edits the one selected shape's frame, fill, visibility and lock. AlignmentToolbar lines up or spreads the selection through `aligned`. AssetPanel finds shapes by name in a picks grid, each drawn to fit its tile. ColorPanel, ShadowEditor, BorderEditor and TypographyPanel edit a look; GradientPanel is forms::GradientEditor. ConstraintsEditor pins a shape to its frame, with `Constraints::placed`; AutoLayoutControls sets flow, gap, padding and a place grid, with `AutoLayout::laid`; ExportPanel names each file once. The panels share `canvas::panel`: editing, pair, caption, heading and color_well.
This commit is contained in:
1 parent
c637347a2a
commit
07b875b0d3
32 files changed
+3118
-18
No files matched your search
@@ -0,0 +1,94 @@
|
||||
use std::{fmt::Debug, rc::Rc};
|
||||
|
||||
use gpui::{
|
||||
App, ElementId, FontWeight, Hsla, IntoElement, ParentElement, SharedString, Styled, Window, div,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
forms::{ColorPicker, ColorSwatch},
|
||||
overlays::Popover,
|
||||
theme::{ActiveTheme, TextSize},
|
||||
};
|
||||
|
||||
/// A panel's handler for its whole value.
|
||||
pub(crate) type OnEdit<V> = Rc<dyn Fn(V, &mut Window, &mut App)>;
|
||||
|
||||
/// A handler that hands `on_change` a copy of `value` changed by `edit`.
|
||||
pub(crate) fn editing<V, T>(
|
||||
what: &'static str,
|
||||
value: &V,
|
||||
on_change: &Option<OnEdit<V>>,
|
||||
edit: impl Fn(&mut V, T) + 'static,
|
||||
) -> impl Fn(T, &mut Window, &mut App) + 'static
|
||||
where
|
||||
V: Clone + Debug + 'static,
|
||||
T: 'static,
|
||||
{
|
||||
let (value, on_change) = (value.clone(), on_change.clone());
|
||||
move |input, window, cx| {
|
||||
let mut next = value.clone();
|
||||
edit(&mut next, input);
|
||||
log::info!("{what}: {next:?}");
|
||||
if let Some(on_change) = &on_change {
|
||||
on_change(next, window, cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Two fields side by side, sharing the width.
|
||||
pub(crate) fn pair(left: impl IntoElement, right: impl IntoElement) -> gpui::Div {
|
||||
div()
|
||||
.flex()
|
||||
.gap_2()
|
||||
.child(div().flex_1().min_w_0().child(left))
|
||||
.child(div().flex_1().min_w_0().child(right))
|
||||
}
|
||||
|
||||
/// A quiet line naming what follows.
|
||||
pub(crate) fn caption(text: impl Into<SharedString>, cx: &App) -> gpui::Div {
|
||||
let theme = cx.theme();
|
||||
div()
|
||||
.text_size(theme.text_size(TextSize::Xs))
|
||||
.text_color(theme.colors.fg_subtle)
|
||||
.child(text.into())
|
||||
}
|
||||
|
||||
/// A panel part's title, with an action at the end of its line.
|
||||
pub(crate) fn heading(
|
||||
title: impl Into<SharedString>,
|
||||
action: impl IntoElement,
|
||||
cx: &App,
|
||||
) -> gpui::Div {
|
||||
let theme = cx.theme();
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.justify_between()
|
||||
.gap_2()
|
||||
.child(
|
||||
div()
|
||||
.text_size(theme.text_size(TextSize::Sm))
|
||||
.font_weight(FontWeight::SEMIBOLD)
|
||||
.text_color(theme.colors.fg)
|
||||
.child(title.into()),
|
||||
)
|
||||
.child(action)
|
||||
}
|
||||
|
||||
/// A swatch that opens a color picker.
|
||||
pub(crate) fn color_well(
|
||||
id: ElementId,
|
||||
color: Hsla,
|
||||
on_pick: impl Fn(Hsla, &mut Window, &mut App) + 'static,
|
||||
) -> Popover {
|
||||
let swatch = (id.clone(), "swatch");
|
||||
Popover::with_opener(
|
||||
id.clone(),
|
||||
move |toggle| {
|
||||
ColorSwatch::new(swatch, color)
|
||||
.tooltip("Change the color")
|
||||
.on_click(move |window, cx| toggle(window, cx))
|
||||
},
|
||||
move |_, _| ColorPicker::new((id, "picker"), color).on_change(on_pick),
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user