git.lucas.co / cce-calendar
calendar
git clone https://git.lucas.co/cce-calendar.git

commit58098f1ce59e0a6c7d47538012904a112c4eacaa
parentda3b01e9ff
authorLucas Galante <lsgalante12@gmail.com>
date2026-10-01 20:33
Carve the day view into the root plate

The sidebar was a pane plate standing on the root plate in its own
colour; it is now a recess at the plate corner radius, carved inside
its rect so the gap to the grid stays the gap, with the root plate as
its floor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

 src/main.rs | 38 +++++++++++++++++---------------------
 1 file changed, 17 insertions(+), 21 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index a9ebd24..e6723c2 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,7 @@
 //! cce-calendar — month-view calendar with per-day events.
 //!
-//! A 6×7 month grid on the left, a day pane on the right. Events live in
+//! A 6×7 month grid on the left, a day pane (a well in the root plate) on
+//! the right. Events live in
 //! `$XDG_DATA_HOME/cce/calendar/events.json` (one flat list of
 //! date/time/title records) and are saved on every mutation. Records with a
 //! `source` are mirrored from a remote calendar by `cce-calendar-sync`
@@ -28,11 +29,11 @@ use wayland_client::QueueHandle;
 
 use cce_ui::engine::{Application, EngineState, LogicalPosition, LogicalSize, WindowSettings};
 use cce_ui::layout::{
-    bevel_width, plate_corner_radius, plate_gap, plate_padding, root_plate_gap, root_plate_inset,
+    bevel_width, carve_inside, plate_corner_radius, plate_gap, plate_padding, root_plate_gap,
+    root_plate_inset,
 };
 use cce_ui::scene::layout::Rect;
-use cce_ui::scene::paint::{AlignH, AlignV, DisplayList, PaintCtx, PlateSpec, TextAttrs, TextLayout};
-use cce_ui::scene::Material;
+use cce_ui::scene::paint::{AlignH, AlignV, DisplayList, PaintCtx, TextAttrs, TextLayout};
 use cce_ui::widget::scroll_motion::{current_scroll_phase, Bounds, ScrollMotion, ScrollPhase};
 use cce_ui::widget::{ElementState, Key, KeyEvent, MouseButton, MouseScrollDelta, NamedKey};
 
@@ -53,7 +54,6 @@ const MONTH_STEP_PX: f32 = 48.0;
 
 const BG: [f32; 4] = [0.075, 0.08, 0.09, 1.0];
 const BG_OTHER_MONTH: [f32; 4] = [0.06, 0.064, 0.072, 1.0];
-const SIDEBAR_BG: [f32; 4] = [0.10, 0.105, 0.12, 1.0];
 const GRID_LINE: [f32; 4] = [1.0, 1.0, 1.0, 0.06];
 /// The grid lines' drawn width. The lines are the grout between rounded
 /// cells, so every crossing carries the cells' corners as concave fillets.
@@ -198,10 +198,10 @@ struct Geom {
     /// A cell face's corner radius — the fillet at every line crossing.
     cell_radius: f32,
     sidebar: Rect,
-    /// The event list's clip inside the sidebar plate: full plate width,
+    /// The event list's clip inside the sidebar well: full well width,
     /// between the heading block and the bottom strip.
     list: Rect,
-    /// The bottom strip inside the sidebar plate — the input field while
+    /// The bottom strip inside the sidebar well — the input field while
     /// typing, else the key hints.
     strip: Rect,
     /// Date of the grid's top-left cell (always a 42-day window).
@@ -274,7 +274,7 @@ impl CalendarApp {
     fn geom(&self) -> Geom {
         let (w, h) = self.win;
         // Everything stands on the root plate `root_plate_inset` in from
-        // the window edge; the grid column and the sidebar plate are
+        // the window edge; the grid column and the sidebar well are
         // siblings on it, `root_plate_gap` apart:
         // [inset][header+grid][gap][sidebar][inset].
         let inset = root_plate_inset();
@@ -295,7 +295,7 @@ impl CalendarApp {
             width: sidebar_w,
             height: (h - 2.0 * inset).max(0.0),
         };
-        // Inside the sidebar plate: `plate_padding` off its rim, the
+        // Inside the sidebar well: `plate_padding` off its rim, the
         // heading block, the list and the bottom strip `plate_gap` apart.
         let pad = plate_padding();
         let strip_h = INPUT_H - 8.0;
@@ -648,18 +648,14 @@ impl CalendarApp {
     }
 
     fn paint_sidebar(&self, pc: &mut PaintCtx, g: &Geom) {
-        // The sidebar is a pane plate standing on the root plate, in the
-        // app's own colour (the DE pane material would swallow this app's
-        // faint text). Inset from every window edge, so no corner is on
-        // the silhouette; the flags are derived anyway so a future
-        // edge-to-edge layout rounds correctly.
-        let (w, h) = self.win;
-        pc.plate_spec(&PlateSpec {
-            rect: g.sidebar,
-            material: Material::opaque(SIDEBAR_BG),
-            window_corners: PlateSpec::window_corner_flags(g.sidebar, w, h),
-            depth: bevel_width(),
-        });
+        // The day view is a well carved into the root plate, not a plate
+        // standing on it: the floor is the root plate showing through, the
+        // wall kept inside the sidebar rect so the gap to the grid is the
+        // gap. Drawn first so the rows and the strip lie on its floor.
+        let r = plate_corner_radius();
+        let depth = bevel_width().min(g.sidebar.height * 0.2);
+        let (well, radii) = carve_inside(g.sidebar, (r, r, r, r), depth);
+        pc.recess(well, radii, depth);
 
         let pad = plate_padding();
         let heading = format!(