From 0a291c877bc2c2ad962299c563681ac86b32057b Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Thu, 23 Apr 2026 14:05:07 +0300 Subject: [PATCH] feat: A4 landscape default paper, white paper area on dark desk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - paper_limits() falls back to A4 landscape (297×210mm) even when no Layout object exists in the document - paper_bg_color default changed to white [1,1,1,1] (paper surface color) - PaperCanvas::draw() fills canvas with dark desk color first, then draws the paper area rectangle in paper_bg_color so the sheet is clearly visible against the desk background - view.rs container background uses the fixed desk color instead of paper_bg_color so it no longer conflicts with the paper-surface color - BACKGROUND RESET for paper space now resets to white instead of dark gray - Removed unused PaperSheet variant, paper_sheet() constructor, build_paper_sheet_primitive() and associated match arms (dead code after 2D canvas replacement) Co-Authored-By: Claude Sonnet 4.6 --- src/app/commands.rs | 2 +- src/app/view.rs | 5 ++--- src/scene/mod.rs | 6 +++--- src/scene/paper_canvas.rs | 18 +++++++++++++++--- src/scene/render.rs | 33 --------------------------------- src/scene/viewport_pane.rs | 15 ++------------- 6 files changed, 23 insertions(+), 56 deletions(-) diff --git a/src/app/commands.rs b/src/app/commands.rs index 1f3c26d6..dc51e284 100644 --- a/src/app/commands.rs +++ b/src/app/commands.rs @@ -41,7 +41,7 @@ impl H7CAD { if args.first().map(|s| s.eq_ignore_ascii_case("RESET")).unwrap_or(false) { if is_paper { self.tabs[i].paper_bg_color = None; - self.tabs[i].scene.paper_bg_color = [0.22, 0.24, 0.28, 1.0]; + self.tabs[i].scene.paper_bg_color = [1.0, 1.0, 1.0, 1.0]; } else { self.tabs[i].bg_color = None; self.tabs[i].scene.bg_color = [0.11, 0.11, 0.11, 1.0]; diff --git a/src/app/view.rs b/src/app/view.rs index 366abe50..2c031748 100644 --- a/src/app/view.rs +++ b/src/app/view.rs @@ -232,9 +232,8 @@ impl H7CAD { .height(Fill); let bg_color = if is_paper { - tab.paper_bg_color - .map(|[r, g, b, a]| Color { r, g, b, a }) - .unwrap_or(Color { r: 0.22, g: 0.24, b: 0.28, a: 1.0 }) + // Desk color — matches the DESK constant in paper_canvas.rs. + Color { r: 0.22, g: 0.24, b: 0.28, a: 1.0 } } else { tab.bg_color .map(|[r, g, b, a]| Color { r, g, b, a }) diff --git a/src/scene/mod.rs b/src/scene/mod.rs index 2f75fe80..a94fba23 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -95,7 +95,7 @@ impl Scene { images: HashMap::new(), active_viewport: None, bg_color: [0.11, 0.11, 0.11, 1.0], - paper_bg_color: [0.22, 0.24, 0.28, 1.0], + paper_bg_color: [1.0, 1.0, 1.0, 1.0], } } @@ -201,11 +201,9 @@ impl Scene { if let ObjectType::Layout(l) = obj { if l.name == self.current_layout { let (min, max) = (l.min_limits, l.max_limits); - // Guard against degenerate limits. let w = (max.0 - min.0).abs(); let h = (max.1 - min.1).abs(); if w < 1e-6 || h < 1e-6 { - // Default to A4 landscape (mm). return Some(((0.0, 0.0), (297.0, 210.0))); } return Some((min, max)); @@ -213,6 +211,8 @@ impl Scene { } None }) + // No Layout object found for the current layout — default to A4 landscape. + .or(Some(((0.0, 0.0), (297.0, 210.0)))) } /// Scale of the first user viewport (id > 1) in the current paper layout, diff --git a/src/scene/paper_canvas.rs b/src/scene/paper_canvas.rs index 7b0ab9c9..5194a863 100644 --- a/src/scene/paper_canvas.rs +++ b/src/scene/paper_canvas.rs @@ -64,9 +64,21 @@ impl<'a> canvas::Program for PaperCanvas<'a> { let mut frame = canvas::Frame::new(renderer, bounds.size()); - // ── Background ──────────────────────────────────────────────────────── - let [r, g, b, a] = self.scene.paper_bg_color; - frame.fill_rectangle(Point::ORIGIN, bounds.size(), Color { r, g, b, a }); + // ── Desk background (area outside the paper sheet) ──────────────────── + const DESK: Color = Color { r: 0.22, g: 0.24, b: 0.28, a: 1.0 }; + frame.fill_rectangle(Point::ORIGIN, bounds.size(), DESK); + + // ── White paper area ────────────────────────────────────────────────── + if let Some(((px0, py0), (px1, py1))) = self.scene.paper_limits() { + let tl = to_px(px0 as f32, py1 as f32); + let br = to_px(px1 as f32, py0 as f32); + let pw = br.x - tl.x; + let ph = br.y - tl.y; + if pw > 0.0 && ph > 0.0 { + let [r, g, b, a] = self.scene.paper_bg_color; + frame.fill_rectangle(tl, iced::Size::new(pw, ph), Color { r, g, b, a }); + } + } // ── Wipeout fills (rendered before wires, cover background) ────────── for hatch in &self.scene.paper_canvas_wipeouts() { diff --git a/src/scene/render.rs b/src/scene/render.rs index 62544ccf..e0b7bb1a 100644 --- a/src/scene/render.rs +++ b/src/scene/render.rs @@ -246,39 +246,6 @@ impl Scene { } } - /// Build a Primitive for the full paper canvas: paper-space entities - /// (title blocks, frames, borders) plus model-space content projected - /// through each viewport's view matrix into paper-space coordinates. - pub(super) fn build_paper_sheet_primitive( - &self, - hover_region: Option, - bounds: Rectangle, - ) -> Primitive { - let cam = self.camera.borrow(); - self.selection.borrow_mut().vp_size = (bounds.width, bounds.height); - - let layout_block = self.current_layout_block_handle(); - let mut wires = self.paper_sheet_wires(); - // When MSPACE is active, exclude that viewport from the CPU projection — - // it is rendered in 3D by the separate PaperViewportPane widget. - wires.extend(self.viewport_content_wires(layout_block, None, self.active_viewport)); - if let Some(iw) = &self.interim_wire { - wires.push(iw.clone()); - } - wires.extend(self.preview_wires.iter().cloned()); - - Primitive { - wires, - hatches: self.synced_hatch_models(), - wipeout_hatches: self.wipeout_models(), - images: self.images.values().cloned().collect(), - meshes: self.meshes.values().cloned().collect(), - uniforms: Uniforms::new(&cam, bounds), - cam_rotation: cam.view_rotation_mat(), - hover_region, - bg_color: self.paper_bg_color, - } - } /// Build a Primitive that renders model-space content through a specific /// paper-space viewport's camera, applying its layer-freeze list. diff --git a/src/scene/viewport_pane.rs b/src/scene/viewport_pane.rs index add192fe..af50f44a 100644 --- a/src/scene/viewport_pane.rs +++ b/src/scene/viewport_pane.rs @@ -9,9 +9,6 @@ use iced::{mouse, Event, Rectangle}; pub enum ViewportPaneMode { /// Full model space — fills whatever bounds Iced assigns. Model, - /// Paper-space entities plus model content projected through viewports. - /// Used for the full paper canvas (single widget, no per-viewport widgets). - PaperSheet, /// Model-space content rendered through a specific viewport's 3-D camera. /// /// NOTE: Currently unused because Iced 0.14 batches all shader `prepare()` @@ -35,11 +32,6 @@ impl<'a> ViewportPane<'a> { Self { scene, mode: ViewportPaneMode::Model } } - /// Paper-sheet layer: paper-space entities rendered with the paper camera. - pub fn paper_sheet(scene: &'a Scene) -> Self { - Self { scene, mode: ViewportPaneMode::PaperSheet } - } - /// One paper-space viewport: model content rendered through its own camera. /// See [`ViewportPaneMode::Paper`] for why this is currently unused. #[allow(dead_code)] @@ -116,9 +108,6 @@ impl<'a, Msg: std::fmt::Debug + Clone> shader::Program for ViewportPane<'a> ViewportPaneMode::Model => { self.scene.build_primitive(state.hover_region, bounds) } - ViewportPaneMode::PaperSheet => { - self.scene.build_paper_sheet_primitive(state.hover_region, bounds) - } ViewportPaneMode::Paper { handle } => { self.scene.build_viewport_primitive(*handle, state.hover_region, bounds) } @@ -133,7 +122,7 @@ impl<'a, Msg: std::fmt::Debug + Clone> shader::Program for ViewportPane<'a> cursor: mouse::Cursor, ) -> Option> { // ViewCube hover only makes sense in the full model-space view. - if matches!(self.mode, ViewportPaneMode::Model | ViewportPaneMode::PaperSheet) { + if matches!(self.mode, ViewportPaneMode::Model) { self.scene.update_viewcube_state(state, bounds, cursor); } let _ = event; @@ -146,7 +135,7 @@ impl<'a, Msg: std::fmt::Debug + Clone> shader::Program for ViewportPane<'a> _b: Rectangle, _c: mouse::Cursor, ) -> mouse::Interaction { - if matches!(self.mode, ViewportPaneMode::Model | ViewportPaneMode::PaperSheet) { + if matches!(self.mode, ViewportPaneMode::Model) { self.scene.viewcube_mouse_interaction(state) } else { mouse::Interaction::default()