fix(geometry): canvas_region shrinks for VariablesPanel too (codex BLOCK)

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.
This commit is contained in:
Kayshen-X 2026-05-14 17:57:55 +08:00
parent 048d53d71d
commit 21cb3ca1a9
3 changed files with 46 additions and 2 deletions

View file

@ -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<crate::Rect> {

View file

@ -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

View file

@ -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