From 048d53d71dcdbe52a8c4c6719400d5f6dd83ca1d Mon Sep 17 00:00:00 2001 From: Kayshen-X Date: Thu, 14 May 2026 17:53:16 +0800 Subject: [PATCH] fix(native/paint): wire VariablesPanel into the right-rail paint pass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Codex stop-gate flagged that the previous commit (140d5495) shipped `VariablesPanel` as a widget definition + tests but never wired it into the host's paint composition, so users couldn't actually see it. This commit closes that gap. `crates/openpencil-shell-native/src/widget_host/paint.rs`: - Step 4 (PropertyPanel) now also computes the right-rail x + width as locals so the new VariablesPanel paint step reuses them instead of duplicating the geometry math. - New Step 4b: when `Document.var_table.variables` is non-empty, paint a `VariablesPanel::for_document(...)` rectangle anchored to the right rail. Layout decision: - No selection: panel pinned at the top of the rail (TOP_BAR_HEIGHT + 8 px) so it's the primary chrome there. - Active selection: PropertyPanel owns the rail; Variables anchors to the bottom (above the status bar). Approximate because PropertyPanel paints to fill the rail today; proper stacking lands when the rail grows scrollable regions or tabs. Variables stays hidden when `var_table` is empty — no visual noise for documents that don't use them. - `VariablesPanel` imported via `widgets::variables_panel:: VariablesPanel` (the module is `pub mod` exported in widgets/mod.rs). `crates/openpencil-shell-native/src/widget_host/input.rs`: - Cleaned up the unused imports left over from the input/keyboard split (5caa2eb3): `PropertyFocus`, `AIChatHit`, `AIChatPlaceholder`, `LayerPanel`, `LayoutCx`, `Toolbar`, `Widget`, `TOOLBAR_WIDTH`, `TOP_BAR_HEIGHT` were all moved to keyboard.rs but still listed in input.rs's import list. Down to the actually-used `ChatAnchor` + helpers + Point2D + Rect. Tests: 274 shell-core + 54 desktop + 20 shell-native all pass. Visual verification: opening a `.op` file whose `variables` array is non-empty now shows the panel chrome (header "Variables" label, active-theme chips, one row per variable with name + resolved color swatch / scalar label). Edit interactions still pending — `VariablesPanelHit::Row(idx)` is wired up but the host doesn't dispatch it yet. --- .../src/widget_host/input.rs | 6 +-- .../src/widget_host/paint.rs | 47 +++++++++++++++---- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/crates/openpencil-shell-native/src/widget_host/input.rs b/crates/openpencil-shell-native/src/widget_host/input.rs index 142749bd2..322e93f7b 100644 --- a/crates/openpencil-shell-native/src/widget_host/input.rs +++ b/crates/openpencil-shell-native/src/widget_host/input.rs @@ -5,11 +5,7 @@ use super::helpers::{ TOOLBAR_INSET_Y, }; use super::{PanelResizeKind, WidgetHostNative}; -use openpencil_shell_core::document::{ChatAnchor, PropertyFocus}; -use openpencil_shell_core::widgets::{ - AIChatHit, AIChatPlaceholder, LayerPanel, LayoutCx, Toolbar, Widget, TOOLBAR_WIDTH, - TOP_BAR_HEIGHT, -}; +use openpencil_shell_core::document::ChatAnchor; use openpencil_shell_core::{Point2D, Rect}; impl WidgetHostNative { diff --git a/crates/openpencil-shell-native/src/widget_host/paint.rs b/crates/openpencil-shell-native/src/widget_host/paint.rs index 7d5c88540..a804dd548 100644 --- a/crates/openpencil-shell-native/src/widget_host/paint.rs +++ b/crates/openpencil-shell-native/src/widget_host/paint.rs @@ -6,9 +6,9 @@ use super::frame_backend::NativeFrameBackend; use super::helpers::{STATUS_INSET, TOOLBAR_INSET_X, TOOLBAR_INSET_Y}; use super::WidgetHostNative; use openpencil_shell_core::widgets::{ - AIChatPlaceholder, AlignToolbar, CanvasViewport, LayerPanel, LayoutCx, LocalePicker, PaintCx, - PropertyPanel, ShapePicker, StatusBar, Toolbar, TopBar, Widget, STATUS_BAR_HEIGHT, - STATUS_BAR_WIDTH, TOOLBAR_WIDTH, TOP_BAR_HEIGHT, + variables_panel::VariablesPanel, AIChatPlaceholder, AlignToolbar, CanvasViewport, LayerPanel, + LayoutCx, LocalePicker, PaintCx, PropertyPanel, ShapePicker, StatusBar, Toolbar, TopBar, + Widget, STATUS_BAR_HEIGHT, STATUS_BAR_WIDTH, TOOLBAR_WIDTH, TOP_BAR_HEIGHT, }; use openpencil_shell_core::{Point2D, Rect, RenderBackend}; @@ -92,14 +92,13 @@ impl WidgetHostNative { // 4. PropertyPanel — only when selection. let property_panel = PropertyPanel::for_selection_at(&self.document, self.now_ms); let has_property = property_panel.is_some(); + let property_panel_width = self.document.ui.property_panel_width; + let right_rail_x = viewport_width - property_panel_width; if let Some(panel) = property_panel.as_ref() { let property_rect = Rect { - origin: Point2D::new( - viewport_width - self.document.ui.property_panel_width, - TOP_BAR_HEIGHT, - ), + origin: Point2D::new(right_rail_x, TOP_BAR_HEIGHT), size: Point2D::new( - self.document.ui.property_panel_width, + property_panel_width, (viewport_height - TOP_BAR_HEIGHT).max(0.0), ), }; @@ -109,6 +108,38 @@ impl WidgetHostNative { panel.paint(&mut cx, property_rect); } + // 4b. VariablesPanel — paints whenever the document has + // variables (so users with themed `.op` files see them + // immediately without needing to select a node). Sits in + // the same right-rail column as PropertyPanel. When a + // selection is active, PropertyPanel owns the rail and + // VariablesPanel paints below it; when no selection, the + // Variables panel anchors at the top so it's not hidden. + if !self.document.var_table.variables.is_empty() { + let vars = VariablesPanel::for_document(&self.document); + let intrinsic = vars.intrinsic_height(); + let top_y = if has_property { + // Below PropertyPanel — naive offset uses the + // PropertyPanel's own intrinsic height proxy. The + // property panel paints to fill the rail, so we put + // Variables at the bottom of the rail above the + // status bar; users scroll the property pane + // separately. Approximate: anchor to bottom-of-rail. + let bottom_pad = STATUS_BAR_HEIGHT + 16.0; + (viewport_height - bottom_pad - intrinsic).max(TOP_BAR_HEIGHT + 8.0) + } else { + TOP_BAR_HEIGHT + 8.0 + }; + let vars_rect = Rect { + origin: Point2D::new(right_rail_x, top_y), + size: Point2D::new(property_panel_width, intrinsic), + }; + let mut cx = PaintCx { + backend: &mut *frame, + }; + vars.paint(&mut cx, vars_rect); + } + // 5. CanvasViewport — middle band, respects sidebar // collapse state. let (canvas_left, _canvas_y, canvas_w, canvas_h) =