Merge PR #353: fix View Cube toggle (highlight follows state, cube clears on hide)

External PR by Karim Jerbi (@KarimJerbi).
- NAVVCUBE is a command toggle so it never set active_tool; add a
  show_viewcube flag to the ribbon and special-case is_active_tool so the
  button highlights only while the cube is on.
- show_viewcube was absent from render_signature, so toggling a cached
  view produced an identical signature and left stale cube pixels; hash
  it into the signature so the toggle invalidates the cache and clears.
This commit is contained in:
Hakan Seven committed 2026-07-11 09:20:32 +03:00
commit 816cb059dd
4 files changed
+31 -3

No files matched your search

+1
View File
@@ -1562,6 +1562,7 @@ impl OpenCADStudio {
}
Message::ToggleViewCube => {
self.show_viewcube ^= true;
self.ribbon.set_viewcube(self.show_viewcube);
Task::none()
}
Message::ToggleProperties => {
+5
View File
@@ -514,6 +514,11 @@ fn render_signature(vp: &ViewportData, clip_w: u32, clip_h: u32) -> u64 {
vp.mesh_fill.hash(&mut h);
vp.show_3d_edges.hash(&mut h);
vp.hidden_line.hash(&mut h);
// ViewCube visibility is excluded from the *scene* signature elsewhere only
// for the live-hover pass; here it MUST invalidate the cache so toggling the
// cube (NAVVCUBE) re-renders and actually clears the last cube frame
// instead of leaving its stale pixels on the cached surface.
vp.show_viewcube.hash(&mut h);
// Interaction-LOD hatch suppression: differs the signature so the settle
// frame (skip_hatch flips false) re-renders with hatches and re-caches.
vp.skip_hatch.hash(&mut h);
+17
View File
@@ -35,6 +35,8 @@ pub struct Ribbon {
active_tool: Option<String>,
pub wireframe: bool,
pub ortho_mode: bool,
/// ViewCube (NAVVCUBE) visibility — drives the View Cube button highlight.
pub show_viewcube: bool,
pub open_dropdown: Option<String>,
/// Title of the collapsed panel whose flyout is currently open, if any.
pub collapsed_open: Option<String>,
@@ -133,6 +135,7 @@ impl Ribbon {
active_tool: None,
wireframe: false,
ortho_mode: true,
show_viewcube: true,
open_dropdown: None,
collapsed_open: None,
last_panel_tool: HashMap::default(),
@@ -274,6 +277,9 @@ impl Ribbon {
pub fn set_ortho(&mut self, ortho: bool) {
self.ortho_mode = ortho;
}
pub fn set_viewcube(&mut self, on: bool) {
self.show_viewcube = on;
}
pub fn toggle_dropdown(&mut self, id: &str) {
if self.open_dropdown.as_deref() == Some(id) {
@@ -536,6 +542,7 @@ impl Ribbon {
&self.last_cmd,
self.wireframe,
self.ortho_mode,
self.show_viewcube,
&self.layer_infos,
&self.active_layer,
self.active_color,
@@ -551,6 +558,7 @@ impl Ribbon {
&self.last_cmd,
self.wireframe,
self.ortho_mode,
self.show_viewcube,
&self.layer_infos,
&self.active_layer,
self.active_color,
@@ -566,6 +574,7 @@ impl Ribbon {
&self.last_cmd,
self.wireframe,
self.ortho_mode,
self.show_viewcube,
&self.layer_infos,
&self.active_layer,
self.active_color,
@@ -582,6 +591,7 @@ impl Ribbon {
&self.last_cmd,
self.wireframe,
self.ortho_mode,
self.show_viewcube,
&self.layer_infos,
&self.active_layer,
self.active_color,
@@ -598,6 +608,7 @@ impl Ribbon {
&self.last_cmd,
self.wireframe,
self.ortho_mode,
self.show_viewcube,
&self.layer_infos,
&self.active_layer,
self.active_color,
@@ -1291,6 +1302,7 @@ fn render_group<'a>(
last_cmd: &HashMap<&'static str, &'static str>,
wireframe: bool,
ortho_mode: bool,
show_viewcube: bool,
layer_infos: &'a [LayerInfo],
active_layer: &'a str,
active_color: AcadColor,
@@ -1319,6 +1331,7 @@ fn render_group<'a>(
last_cmd,
wireframe,
ortho_mode,
show_viewcube,
layer_infos,
active_layer,
active_color,
@@ -1335,6 +1348,7 @@ fn render_group<'a>(
last_cmd,
wireframe,
ortho_mode,
show_viewcube,
));
if small_buf.len() == 3 {
flush_small_col(&mut small_buf, &mut items_row);
@@ -1414,6 +1428,7 @@ fn collapse_button<'a>(
last_cmd: &HashMap<&'static str, &'static str>,
wireframe: bool,
ortho_mode: bool,
show_viewcube: bool,
layer_infos: &'a [LayerInfo],
active_layer: &'a str,
active_color: AcadColor,
@@ -1481,6 +1496,7 @@ fn collapse_button<'a>(
last_cmd,
wireframe,
ortho_mode,
show_viewcube,
layer_infos,
active_layer,
active_color,
@@ -1496,6 +1512,7 @@ fn collapse_button<'a>(
last_cmd,
wireframe,
ortho_mode,
show_viewcube,
layer_infos,
active_layer,
active_color,
+8 -3
View File
@@ -289,12 +289,14 @@ pub(super) fn is_active_tool(
active_tool: &Option<String>,
wireframe: bool,
ortho_mode: bool,
show_viewcube: bool,
) -> bool {
match id {
"WIREFRAME" => wireframe,
"SOLID" => !wireframe,
"ORTHO" => ortho_mode,
"PERSP" => !ortho_mode,
"NAVVCUBE" => show_viewcube,
id => active_tool.as_deref() == Some(id),
}
}
@@ -349,12 +351,13 @@ pub(super) fn render_small<'a>(
last_cmd: &HashMap<&'static str, &'static str>,
wireframe: bool,
ortho_mode: bool,
show_viewcube: bool,
) -> Element<'a, Message> {
match item {
// Large variants render small too, so the ribbon can shrink a panel of
// large buttons to icon-only columns when the width is tight.
RibbonItem::Tool(t) | RibbonItem::LargeTool(t) => {
let active = is_active_tool(t.id, active_tool, wireframe, ortho_mode);
let active = is_active_tool(t.id, active_tool, wireframe, ortho_mode, show_viewcube);
let event = t.event.clone();
let tool_id = t.id.to_string();
let tip_text = format!("{}\nCommand: {}", t.label, t.id);
@@ -584,6 +587,7 @@ pub(super) fn render_large<'a>(
last_cmd: &HashMap<&'static str, &'static str>,
wireframe: bool,
ortho_mode: bool,
show_viewcube: bool,
layer_infos: &'a [LayerInfo],
active_layer: &'a str,
active_color: AcadColor,
@@ -597,7 +601,7 @@ pub(super) fn render_large<'a>(
// A plain Tool renders large too, so a collapsed panel can show its
// representative tool as a big icon.
RibbonItem::LargeTool(t) | RibbonItem::Tool(t) => {
let active = is_active_tool(t.id, active_tool, wireframe, ortho_mode);
let active = is_active_tool(t.id, active_tool, wireframe, ortho_mode, show_viewcube);
let event = t.event.clone();
let tool_id = t.id.to_string();
let tip_text = format!("{}\nCommand: {}", t.label, t.id);
@@ -783,9 +787,10 @@ pub(super) fn render_large<'a>(
last_cmd,
wireframe,
ortho_mode,
show_viewcube,
)
} else {
let mp_active = is_active_tool(match_prop.id, active_tool, wireframe, ortho_mode);
let mp_active = is_active_tool(match_prop.id, active_tool, wireframe, ortho_mode, show_viewcube);
let mp_event = match_prop.event.clone();
let mp_id = match_prop.id.to_string();
let mp_tip = format!("{}\nCommand: {}", match_prop.label, match_prop.id);