fix: NAVVCUBE and UCSICON commands now properly toggle visibility

NAVVCUBE: propagate show_viewcube flag through ViewportPane and the wgpu
Primitive so the ViewCube pipeline skips upload/render when hidden.
UCSICON: bare command (no subcommand) now toggles current state instead
of printing usage info.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-04-24 01:31:52 +03:00
commit 5f3182fa9a
4 changed files with 41 additions and 16 deletions

View file

@ -3700,6 +3700,20 @@ impl H7CAD {
"UCSICON {sub}: updated {count} viewport(s) + model space." "UCSICON {sub}: updated {count} viewport(s) + model space."
)); ));
} }
"" => {
// Bare UCSICON toggles visibility.
self.push_undo_snapshot(i, "UCSICON");
let visible = !self.show_ucs_icon;
self.show_ucs_icon = visible;
for entity in self.tabs[i].scene.document.entities_mut() {
if let acadrust::EntityType::Viewport(vp) = entity {
vp.status.ucs_icon_visible = visible;
}
}
self.tabs[i].dirty = true;
let state = if visible { "ON" } else { "OFF" };
self.command_line.push_output(&format!("UCSICON {state}"));
}
_ => { _ => {
self.command_line.push_info("Usage: UCSICON ON | OFF | NOORIGIN | ORIGIN"); self.command_line.push_info("Usage: UCSICON ON | OFF | NOORIGIN | ORIGIN");
} }

View file

@ -108,7 +108,7 @@ impl H7CAD {
let viewport_3d: Element<'_, Message> = if is_paper { let viewport_3d: Element<'_, Message> = if is_paper {
paper_canvas_view(tab) paper_canvas_view(tab)
} else { } else {
shader(ViewportPane::model(&tab.scene)) shader(ViewportPane::model(&tab.scene, self.show_viewcube))
.width(Fill) .width(Fill)
.height(Fill) .height(Fill)
.into() .into()

View file

@ -88,6 +88,7 @@ pub struct Primitive {
pub(super) hover_region: Option<usize>, pub(super) hover_region: Option<usize>,
/// Background color used to clear the MSAA buffer at the start of each frame. /// Background color used to clear the MSAA buffer at the start of each frame.
pub(super) bg_color: [f32; 4], pub(super) bg_color: [f32; 4],
pub(super) show_viewcube: bool,
} }
// ── shader::Primitive impl ──────────────────────────────────────────────── // ── shader::Primitive impl ────────────────────────────────────────────────
@ -120,6 +121,7 @@ impl shader::Primitive for Primitive {
pipeline.upload_images(device, queue, &self.images); pipeline.upload_images(device, queue, &self.images);
pipeline.upload_meshes(device, &self.meshes); pipeline.upload_meshes(device, &self.meshes);
pipeline.upload_wires(device, &self.wires); pipeline.upload_wires(device, &self.wires);
if self.show_viewcube {
pipeline.viewcube.upload( pipeline.viewcube.upload(
queue, queue,
self.cam_rotation, self.cam_rotation,
@ -128,6 +130,7 @@ impl shader::Primitive for Primitive {
self.hover_region, self.hover_region,
); );
} }
}
fn render( fn render(
&self, &self,
@ -137,8 +140,10 @@ impl shader::Primitive for Primitive {
clip: &Rectangle<u32>, clip: &Rectangle<u32>,
) { ) {
pipeline.render(encoder, target, *clip, self.bg_color); pipeline.render(encoder, target, *clip, self.bg_color);
if self.show_viewcube {
pipeline.viewcube.render(encoder, target, *clip); pipeline.viewcube.render(encoder, target, *clip);
} }
}
} }
// ── Render-style helpers (impl Scene) ──────────────────────────────────── // ── Render-style helpers (impl Scene) ────────────────────────────────────
@ -216,6 +221,7 @@ impl Scene {
&self, &self,
hover_region: Option<usize>, hover_region: Option<usize>,
bounds: Rectangle, bounds: Rectangle,
show_viewcube: bool,
) -> Primitive { ) -> Primitive {
let cam = self.camera.borrow(); let cam = self.camera.borrow();
self.selection.borrow_mut().vp_size = (bounds.width, bounds.height); self.selection.borrow_mut().vp_size = (bounds.width, bounds.height);
@ -242,6 +248,7 @@ impl Scene {
cam_rotation: cam.view_rotation_mat(), cam_rotation: cam.view_rotation_mat(),
hover_region, hover_region,
bg_color, bg_color,
show_viewcube,
} }
} }
@ -256,7 +263,7 @@ impl Scene {
) -> Primitive { ) -> Primitive {
let cam = match self.camera_for_viewport(vp_handle) { let cam = match self.camera_for_viewport(vp_handle) {
Some(c) => c, Some(c) => c,
None => return self.build_primitive(hover_region, bounds), None => return self.build_primitive(hover_region, bounds, false),
}; };
let mut all_wires = self.model_wires_for_viewport(vp_handle); let mut all_wires = self.model_wires_for_viewport(vp_handle);
@ -275,6 +282,7 @@ impl Scene {
cam_rotation: cam.view_rotation_mat(), cam_rotation: cam.view_rotation_mat(),
hover_region, hover_region,
bg_color: self.bg_color, bg_color: self.bg_color,
show_viewcube: false,
} }
} }

View file

@ -25,18 +25,19 @@ pub enum ViewportPaneMode {
pub struct ViewportPane<'a> { pub struct ViewportPane<'a> {
pub scene: &'a Scene, pub scene: &'a Scene,
pub mode: ViewportPaneMode, pub mode: ViewportPaneMode,
pub show_viewcube: bool,
} }
impl<'a> ViewportPane<'a> { impl<'a> ViewportPane<'a> {
pub fn model(scene: &'a Scene) -> Self { pub fn model(scene: &'a Scene, show_viewcube: bool) -> Self {
Self { scene, mode: ViewportPaneMode::Model } Self { scene, mode: ViewportPaneMode::Model, show_viewcube }
} }
/// One paper-space viewport: model content rendered through its own camera. /// One paper-space viewport: model content rendered through its own camera.
/// See [`ViewportPaneMode::Paper`] for why this is currently unused. /// See [`ViewportPaneMode::Paper`] for why this is currently unused.
#[allow(dead_code)] #[allow(dead_code)]
pub fn paper(scene: &'a Scene, handle: Handle) -> Self { pub fn paper(scene: &'a Scene, handle: Handle) -> Self {
Self { scene, mode: ViewportPaneMode::Paper { handle } } Self { scene, mode: ViewportPaneMode::Paper { handle }, show_viewcube: false }
} }
} }
@ -106,7 +107,7 @@ impl<'a, Msg: std::fmt::Debug + Clone> shader::Program<Msg> for ViewportPane<'a>
) -> Self::Primitive { ) -> Self::Primitive {
match &self.mode { match &self.mode {
ViewportPaneMode::Model => { ViewportPaneMode::Model => {
self.scene.build_primitive(state.hover_region, bounds) self.scene.build_primitive(state.hover_region, bounds, self.show_viewcube)
} }
ViewportPaneMode::Paper { handle } => { ViewportPaneMode::Paper { handle } => {
self.scene.build_viewport_primitive(*handle, state.hover_region, bounds) self.scene.build_viewport_primitive(*handle, state.hover_region, bounds)
@ -122,8 +123,10 @@ impl<'a, Msg: std::fmt::Debug + Clone> shader::Program<Msg> for ViewportPane<'a>
cursor: mouse::Cursor, cursor: mouse::Cursor,
) -> Option<iced::widget::Action<Msg>> { ) -> Option<iced::widget::Action<Msg>> {
// ViewCube hover only makes sense in the full model-space view. // ViewCube hover only makes sense in the full model-space view.
if matches!(self.mode, ViewportPaneMode::Model) { if matches!(self.mode, ViewportPaneMode::Model) && self.show_viewcube {
self.scene.update_viewcube_state(state, bounds, cursor); self.scene.update_viewcube_state(state, bounds, cursor);
} else {
state.hover_region = None;
} }
let _ = event; let _ = event;
None None
@ -135,7 +138,7 @@ impl<'a, Msg: std::fmt::Debug + Clone> shader::Program<Msg> for ViewportPane<'a>
_b: Rectangle, _b: Rectangle,
_c: mouse::Cursor, _c: mouse::Cursor,
) -> mouse::Interaction { ) -> mouse::Interaction {
if matches!(self.mode, ViewportPaneMode::Model) { if matches!(self.mode, ViewportPaneMode::Model) && self.show_viewcube {
self.scene.viewcube_mouse_interaction(state) self.scene.viewcube_mouse_interaction(state)
} else { } else {
mouse::Interaction::default() mouse::Interaction::default()