graphic design tool
git clone https://git.lucas.co/cce-designer.git
feat: the spreadsheet's scrollbars sink behind its plate
The render arm draws the idle copy of cce-ui's new scrollbar cross
before the spreadsheet's plate, as the params pane straddles its bar;
the widget fades the fore copy in over the cells on a scroll.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CLAUDE.md | 12 ++++++++++++
src/render.rs | 17 +++++++++++++----
src/slots.rs | 6 ++++++
3 files changed, 31 insertions(+), 4 deletions(-)
diff --git a/CLAUDE.md b/CLAUDE.md
index dee5689..3150e47 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -2175,6 +2175,18 @@ selected row's marker, stood at the first frame while the scene beside
them played. `rows_selected_inside_a_simnet_follow_the_simulation` is the
test.
+**The spreadsheet's scrollbars are a cross behind its plate** (since
+2026-10-06; cce-ui's CLAUDE.md, "A spreadsheet's scrollbars are a cross
+behind its plate"): the vertical bar down the pane's centre line, the
+horizontal one across the body's, idling behind the frosted plate until a
+scroll raises them, held in front while the pointer is on a raised one.
+It is the params pane's straddle and the dialog's bar, which ride their
+centre lines the same way. The render arm draws the idle copy before the
+plate (`Spreadsheet::paint_scrollbars`, through `WidgetSlots::spreadsheet`);
+the widget paints the fore copy itself. A press on a sunk bar's lane is a
+press on the row under it. Checked in a shadow session: sunk, raised by a
+scroll, held by hover past the hold, sunk again once the pointer left.
+
### An edit is in from the next frame
An edit inside a simnet's chain, or to its seed, does not restart the
diff --git a/src/render.rs b/src/render.rs
index 0c205de..eae13e8 100644
--- a/src/render.rs
+++ b/src/render.rs
@@ -376,11 +376,20 @@ impl State {
} else if idx == SPREADSHEET_IDX {
// Modern-paint pane: the plate from the designer (span-widened
// radii + focus tint), then Spreadsheet::paint authors the grid —
- // header band, zebra rows, separators, dividers, scrollbar. A
- // subtree painter since cce-ui@f1cd939: its text passes through
- // paint_self verbatim, carrying the per-column clamp bounds the
- // own-labels bridge would drop; append_frame_text skips the slot.
+ // header band, zebra rows, separators, dividers, and the fore
+ // copy of its scrollbars. A subtree painter since cce-ui@f1cd939:
+ // its text passes through paint_self verbatim, carrying the
+ // per-column clamp bounds the own-labels bridge would drop;
+ // append_frame_text skips the slot.
let (wx, wy, ww2, wh2) = w.rect();
+ // The scrollbar cross's idle copy, BEHIND the plate — the params
+ // pane's straddle: the frosted plate dims it, and the widget
+ // fades its fore copy in over the cells when a scroll raises it.
+ let sheet = self.slots.spreadsheet();
+ let sheet_rect = rect(wx, wy, ww2, wh2);
+ if sheet.scrollbars_shown(sheet_rect) {
+ sheet.paint_scrollbars(sheet_rect, pc, 1.0);
+ }
append_widget_plate_radii(w, pc, self.plate_focus_tint(idx), self.pane_plate_radii(wx, wy, ww2, wh2));
w.paint_self(&self.ui_context, pc);
} else if idx == VIEWPORT_IDX {
diff --git a/src/slots.rs b/src/slots.rs
index 70b7868..6cdf8dc 100644
--- a/src/slots.rs
+++ b/src/slots.rs
@@ -187,6 +187,12 @@ impl WidgetSlots {
self.param.as_any_mut().downcast_mut::<ParametersBg>().expect("PARAM_IDX must be a ParametersBg")
}
+ /// The spreadsheet as itself, for what its controller trait does not
+ /// carry — the scrollbars the render arm straddles around the plate.
+ pub fn spreadsheet(&self) -> &Spreadsheet {
+ self.spreadsheet.as_any().downcast_ref::<Spreadsheet>().expect("SPREADSHEET_IDX must be a Spreadsheet")
+ }
+
pub fn spreadsheet_mut(&mut self) -> &mut dyn cce_ui::widget::SpreadsheetController {
self.spreadsheet.as_any_mut().downcast_mut::<Spreadsheet>().expect("SPREADSHEET_IDX must be a Spreadsheet")
}