graphic design tool
git clone https://git.lucas.co/cce-designer.git
feat: plate children clip at the plate's rounded corners
The graph content and breadcrumb clip to the network plate's rounded
rect, and the params/spreadsheet panes' content (rows, scrollbar,
labels) to their own plates, via the new PaintCtx::clip_rounded — a
plate_rounded_clip helper maps widget slots to their plate rect +
corner radius, applied in both paint_widget and append_frame_text.
Popovers still render unclipped (append_popovers), and the circular
network pane keeps its circle clip. vk-smoke spans gain the new
TextSpan clip_extents field.
Co-Authored-By: Claude Fable 5 <[email protected]>
src/render.rs | 42 ++++++++++++++++++++++++++++++++++++++++++
src/vk_smoke.rs | 3 +++
2 files changed, 45 insertions(+)
diff --git a/src/render.rs b/src/render.rs
index a51c023..99b74af 100644
--- a/src/render.rs
+++ b/src/render.rs
@@ -30,6 +30,30 @@ fn merge_bounds(a: Option<[f32; 4]>, b: Option<[f32; 4]>) -> Option<[f32; 4]> {
}
impl State {
+ /// The rounded-rect clip (plate rect + corner radius) a widget's content must stay
+ /// inside, so children of plates cut off at the plate's rounded corners: the network
+ /// plate for the network pane's parts (graph content, breadcrumb), the pane's own
+ /// plate for the params and spreadsheet panes. `None` with square corners, and for
+ /// the circular network pane (which clips by circle instead).
+ fn plate_rounded_clip(&self, idx: usize) -> Option<(Rect, f32)> {
+ let r = cce_ui::layout::plate_corner_radius();
+ if r <= 0.0 {
+ return None;
+ }
+ let (x, y, w, h) = match idx {
+ CONTENT_IDX | BREADCRUMB_IDX if !self.circular_network_pane => {
+ self.positions[NETWORK_PANEL_IDX]
+ }
+ PARAM_IDX => self.positions[PARAM_IDX],
+ SPREADSHEET_IDX => self.positions[SPREADSHEET_IDX],
+ _ => return None,
+ };
+ if w <= 0.0 || h <= 0.0 {
+ return None;
+ }
+ Some((rect(x, y, w, h), r))
+ }
+
/// The frame's entire 2D content — geometry AND text — as one display list (the
/// engine's single paint path; `Application::display_list_text` opts the designer's
/// text into the engine's shaping/glyph pass, so the app-side FontSystem and buffer
@@ -137,6 +161,13 @@ impl State {
pc.push_clip_circle(c);
}
+ // Children of plates cut off at the plate's rounded corners (the param pane's
+ // popovers escape this: they render later via `append_popovers`).
+ let rounded_clip = self.plate_rounded_clip(idx);
+ if let Some((rc, rr)) = rounded_clip {
+ pc.push_clip_rounded(rc, rr);
+ }
+
if idx == NETWORK_PANEL_IDX && self.circular_network_pane {
let cx = self.circular_network_layout.x;
let cy = self.circular_network_layout.y;
@@ -258,6 +289,9 @@ impl State {
}
}
+ if rounded_clip.is_some() {
+ pc.pop_clip_rounded();
+ }
if active_circle.is_some() {
pc.pop_clip_circle();
}
@@ -392,6 +426,11 @@ impl State {
None
};
+ // Labels are plate children too — clip them at the plate's rounded corners.
+ let rounded_clip = self.plate_rounded_clip(i);
+ if let Some((rc, rr)) = rounded_clip {
+ pc.push_clip_rounded(rc, rr);
+ }
let mut scratch = PaintCtx::new();
append_widget_text(&self.ui_context, w, &mut scratch);
for item in scratch.finish().items {
@@ -407,6 +446,9 @@ impl State {
pc.text_faded(text, x, y, font_size, color, alpha, font, merge_bounds(widget_bounds, label_bounds));
}
}
+ if rounded_clip.is_some() {
+ pc.pop_clip_rounded();
+ }
}
}
diff --git a/src/vk_smoke.rs b/src/vk_smoke.rs
index 660968e..16aacb8 100644
--- a/src/vk_smoke.rs
+++ b/src/vk_smoke.rs
@@ -413,6 +413,7 @@ fn main() {
default_color: [0.92, 0.92, 0.95, 1.0],
rotation: None,
clip_circle: [0.0; 3],
+ clip_extents: [0.0; 2],
},
TextSpan {
buffer: &body_buf,
@@ -424,6 +425,7 @@ fn main() {
default_color: [pulse, 0.80, 0.55, 1.0],
rotation: None,
clip_circle: [0.0; 3],
+ clip_extents: [0.0; 2],
},
TextSpan {
buffer: &clipped_buf,
@@ -439,6 +441,7 @@ fn main() {
default_color: [0.70, 0.85, 1.00, 1.0],
rotation: None,
clip_circle: [0.0; 3],
+ clip_extents: [0.0; 2],
},
];
// build_scene vertex layout: blur plate is the last 6 verts; the image