From 21cb3ca1a9e6d03862e4e287b7d52dd05242d33a Mon Sep 17 00:00:00 2001 From: Kayshen-X Date: Thu, 14 May 2026 17:57:55 +0800 Subject: [PATCH] fix(geometry): canvas_region shrinks for VariablesPanel too (codex BLOCK) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Codex stop-gate flagged: with no selection, the right-rail `VariablesPanel` was painted (commit 0bd98ae2 wired the paint step) but `canvas_region` still returned the full viewport width because its `has_property` gate only checked `property_panel_ visible()` — which is false without a selection. The canvas paint pass (Step 5) then extended over the right rail and overpainted the Variables panel, defeating the visibility fix the previous commit was supposed to deliver. `crates/openpencil-shell-core/src/document/mutators.rs`: - New `Document::right_rail_visible() -> bool` is the unified gate: true when either `property_panel_visible()` is true or `var_table.variables` is non-empty. Future right-rail widgets (Components, Themes header, etc.) extend this method instead of patching every caller. `crates/openpencil-shell-native/src/widget_host/geometry.rs`: - `canvas_region` swapped from `property_panel_visible()` to `right_rail_visible()`. The shrunk-canvas branch no longer requires a selection — any rail-occupying widget reserves the column. Test (1 added, 275 shell-core total): - `right_rail_visible_tracks_property_panel_and_variables` covers the four state combinations: empty doc → rail hidden var-table-only (no selection) → rail shown (codex repro) selection-only (no vars) → rail shown (legacy gate) cleared selection + cleared vars→ rail hidden again 20 shell-native + 54 desktop + 275 shell-core tests pass. --- .../src/document/mutators.rs | 12 ++++++++ .../src/document/tests_geometry.rs | 28 +++++++++++++++++++ .../src/widget_host/geometry.rs | 8 ++++-- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/crates/openpencil-shell-core/src/document/mutators.rs b/crates/openpencil-shell-core/src/document/mutators.rs index fe7adc49d..6fd62b0c1 100644 --- a/crates/openpencil-shell-core/src/document/mutators.rs +++ b/crates/openpencil-shell-core/src/document/mutators.rs @@ -387,6 +387,18 @@ impl Document { } } + /// True when ANY widget occupies the right rail today — + /// PropertyPanel (gated on selection) or VariablesPanel + /// (gated on a non-empty var table). `canvas_region` uses + /// this to size the canvas so it doesn't paint over the + /// rail content (codex BLOCK: `no-selection VariablesPanel + /// is painted under the canvas` — without this gate the + /// canvas extended full-width when nothing was selected, + /// hiding the Variables panel). + pub fn right_rail_visible(&self) -> bool { + self.property_panel_visible() || !self.var_table.variables.is_empty() + } + /// Union of `aggregate_bounds` across selected nodes on the /// active page. Backs the multi-select panel's X/Y/W/H. pub fn selection_bounds(&self) -> Option { diff --git a/crates/openpencil-shell-core/src/document/tests_geometry.rs b/crates/openpencil-shell-core/src/document/tests_geometry.rs index e428befb6..7c16f7ecd 100644 --- a/crates/openpencil-shell-core/src/document/tests_geometry.rs +++ b/crates/openpencil-shell-core/src/document/tests_geometry.rs @@ -238,6 +238,34 @@ fn property_panel_visible_for_single_and_multi_selection() { assert!(doc.property_panel_visible()); } +#[test] +fn right_rail_visible_tracks_property_panel_and_variables() { + use crate::document::{Variable, VariableKind, VariableScalar, VariableValue}; + // No selection + empty var table → no right rail. + let mut doc = Document::empty(); + assert!(!doc.right_rail_visible()); + + // Variables-only document (typical for `.op` files with themes + // loaded but nothing selected on first paint) — rail occupied, + // canvas_region must shrink so the panel isn't painted over. + // Codex BLOCK: canvas previously extended full-width here. + doc.var_table.variables.push(Variable { + name: "color-1".into(), + kind: VariableKind::Color, + value: VariableValue::Scalar(VariableScalar::Str("#ff0000".into())), + }); + assert!(doc.right_rail_visible()); + + // Selection-only document → rail occupied (legacy gate path). + let mut doc2 = Document::sample(); + assert!(doc2.right_rail_visible()); + + // Clearing both selection + vars hides the rail again. + doc2.clear_selection(); + doc2.var_table.variables.clear(); + assert!(!doc2.right_rail_visible()); +} + #[test] fn property_panel_visible_hides_stale_single_anchor() { // Codex stop-hook BLOCK guard: the panel paint gate diff --git a/crates/openpencil-shell-native/src/widget_host/geometry.rs b/crates/openpencil-shell-native/src/widget_host/geometry.rs index 4991cc278..abaab2a74 100644 --- a/crates/openpencil-shell-native/src/widget_host/geometry.rs +++ b/crates/openpencil-shell-native/src/widget_host/geometry.rs @@ -257,8 +257,12 @@ impl WidgetHostNative { } else { 0.0 }; - let has_property = self.document.property_panel_visible(); - let canvas_right = if has_property { + // Any right-rail widget (PropertyPanel OR VariablesPanel) + // claims the rail width. Using `right_rail_visible` keeps + // canvas + rail mutually exclusive so the canvas never paints + // over an open Variables panel (codex BLOCK fix). + let rail_occupied = self.document.right_rail_visible(); + let canvas_right = if rail_occupied { viewport_w - self.document.ui.property_panel_width } else { viewport_w