GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
Demo on the presets; scripts/style-audit, the conformance check
The demo is the reference app, so it lays out by rung — Style::root_column
for the plate, Style::controls_row for the control row — and names no
padding or gap of its own.
scripts/style-audit greps every sibling app crate and prints one row per
app: whether its base is the standard root plate (PLATE / FILL / NONE),
how many spacing-ladder getters it reads, and how many spacing consts of
its own it declares; a crate that is not a plate by design says so with a
'style-audit: opt-out <reason>' comment and is listed as such. --strict
exits non-zero on any off-standard row, for a build to gate on.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
scripts/style-audit | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++
src/main.rs | 17 +++++++----------
2 files changed, 62 insertions(+), 10 deletions(-)
diff --git a/scripts/style-audit b/scripts/style-audit
new file mode 100755
index 0000000..f658fbd
--- /dev/null
+++ b/scripts/style-audit
@@ -0,0 +1,55 @@
+#!/usr/bin/env bash
+# style-audit — does each cce app stand on the standard root plate and take
+# its spacing from the ladder? A conformance check, not a build step: it
+# greps the sibling app crates and prints one row per app.
+#
+# cce-ui/scripts/style-audit # every cce-* app beside cce-ui
+# cce-ui/scripts/style-audit cce-mail # one or more apps
+# cce-ui/scripts/style-audit --strict # exit 1 if any row is off-standard
+#
+# Columns:
+# root PLATE paints PlateSpec::window / root_plate / root_at
+# FILL paints a full-window quad or rounded_rect instead (off)
+# NONE paints no window base at all (off unless opted out)
+# ladder how many spacing-ladder getters the app reads
+# (root_plate_inset/padding/gap, plate_padding/gap, control_gap,
+# the Style::root_/pane_/controls_ presets)
+# literals spacing consts of the app's own (const *PAD*/*GAP*/*MARGIN*),
+# each one a number the ladder should be supplying
+#
+# Opt-outs: a crate that is not a plate by design (a transparent surface,
+# a full-bleed canvas) declares it with a line anywhere in its src:
+# // style-audit: opt-out <reason>
+# and is listed as OPT-OUT rather than off-standard.
+set -u
+here=$(cd "$(dirname "$0")/.." && pwd)
+ws=$(dirname "$here")
+strict=0; apps=()
+for a in "$@"; do case "$a" in --strict) strict=1;; *) apps+=("$a");; esac; done
+if [ ${#apps[@]} -eq 0 ]; then
+ for d in "$ws"/cce-*/; do
+ d=${d%/}; n=$(basename "$d")
+ case "$n" in cce-ui|cce-compositor|cce-window-manager|cce-icons) continue;; esac
+ [ -f "$d/Cargo.toml" ] && grep -q '^cce-ui' "$d/Cargo.toml" 2>/dev/null && apps+=("$n")
+ done
+fi
+printf '%-24s %-8s %-7s %-9s %s\n' app root ladder literals note
+fail=0
+for n in "${apps[@]}"; do
+ src="$ws/$n/src"; [ -d "$src" ] || { printf '%-24s (no src)\n' "$n"; continue; }
+ if grep -rqE 'style-audit: *opt-out' "$src"; then
+ reason=$(grep -rhoE 'style-audit: *opt-out.*' "$src" | head -1 | sed 's/style-audit: *opt-out *//')
+ printf '%-24s %-8s %-7s %-9s %s\n' "$n" OPT-OUT - - "$reason"; continue
+ fi
+ if grep -rqE 'PlateSpec::(window|root_at)\(|\.root_plate\(' "$src"; then root=PLATE
+ elif grep -rqE '(quad|rounded_rect)\([^;]*(0\.0, *0\.0|x: *0\.0, *y: *0\.0)' "$src"; then root=FILL
+ else root=NONE; fi
+ ladder=$(grep -rhoE 'root_plate_(inset|padding|gap)\(\)|plate_(padding|gap)\(\)|control_gap\(\)|Style::(root|pane|controls)_(column|row)\(\)|ColumnLayout::(pane|controls)\(' "$src" | wc -l)
+ literals=$(grep -rhE '^\s*(pub )?const [A-Z_]*(PAD|GAP|MARGIN|INSET)[A-Z_]*: *f32' "$src" | wc -l)
+ note=""
+ [ "$root" != PLATE ] && { note="base is not the standard root plate"; fail=1; }
+ [ "$ladder" -eq 0 ] && { note="${note:+$note; }no ladder getter read"; fail=1; }
+ printf '%-24s %-8s %-7s %-9s %s\n' "$n" "$root" "$ladder" "$literals" "$note"
+done
+[ $strict -eq 1 ] && exit $fail
+exit 0
diff --git a/src/main.rs b/src/main.rs
index 3ee44fa..281b149 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -260,15 +260,12 @@ impl Application for DemoApp {
// ── Layout: a plain LayoutBox tree, solved in one call. Leaves carry their
// intrinsic sizes; `grow` distributes leftover space; the solved rects are
// assigned straight onto the widgets.
- // DE-wide plate spacing: the inset from the window edge (the
- // root plate's roll plus one padding) and the gap between
- // siblings on the plate, both from config.
- let plate_pad = cce_ui::layout::root_plate_inset();
- let plate_gap = cce_ui::layout::root_plate_gap();
+ // DE-wide spacing by rung, never by number: the root preset insets
+ // by the plate's roll plus one padding and spaces siblings by the
+ // root gap; the controls preset puts the control gap between a
+ // form's controls (`Style::root_column` / `Style::controls_row`).
let mut arena: Arena<LayoutBox> = Arena::new();
- let root = arena.insert(LayoutBox::container(
- Style::column().padding(plate_pad).gap(plate_gap).cross_align(CrossAlign::Stretch),
- ));
+ let root = arena.insert(LayoutBox::container(Style::root_column()));
let title = arena.insert(LayoutBox::leaf(
Style::row(),
LSize::new(0.0, text_leaf_height(TITLE_FONT_SIZE)),
@@ -284,7 +281,7 @@ impl Application for DemoApp {
// toggle, and dropdown plates land on the same top and bottom edge.
const CONTROL_H: f32 = 28.0;
let controls = arena.insert(LayoutBox::container(
- Style::row().gap(plate_gap).height(Length::Fixed(CONTROL_H)),
+ Style::controls_row().height(Length::Fixed(CONTROL_H)),
));
// `shrink` lets the fixed leaves give up width when the window is at its
// minimum instead of overflowing the row.
@@ -295,7 +292,7 @@ impl Application for DemoApp {
let name_box = arena.insert(LayoutBox::leaf(Style::row(), LSize::new(0.0, 30.0)));
// ImageView row: same texture through two fit modes side by side.
let images = arena.insert(LayoutBox::container(
- Style::row().gap(plate_gap).height(Length::Fixed(72.0)),
+ Style::row().gap(cce_ui::layout::root_plate_gap()).height(Length::Fixed(72.0)),
));
let image_contain = arena.insert(LayoutBox::leaf(Style::row().grow(1.0), LSize::new(0.0, 72.0)));
let image_stretch = arena.insert(LayoutBox::leaf(Style::row().grow(1.0), LSize::new(0.0, 72.0)));