feat(viewport): hide ViewCube then render bar as the viewport narrows

When the viewport got too narrow the top-left render-mode bar and the
top-right ViewCube overlapped. Hide them adaptively, measuring the render
bar's real width rather than guessing:

- Wrap the render bar in DensitySwap, which measures its natural width every
  frame and swaps it for an empty spacer once it no longer fits the tile. Add
  report_width0 so it publishes that measured width to render_bar_w.
- Compute viewcube_visible from that measured width: the cube shows only while
  bar_w + gap + cube region fits. This one flag drives the ViewCube nav/UCS
  widgets, the hover hit-test, and — threaded through build_viewports /
  build_viewport_for_pane / viewport_data_for — the GPU cube itself, which
  previously ignored the pane flag (show_viewcube was inst.active only), so
  the cube stayed while its surrounding widgets vanished.

Result: the ViewCube gives way first, then the render bar once it too has no
room — no overlap, sized to the bar's real width (which varies with the
render-mode label, split buttons and tile count).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-07-10 14:58:48 +03:00
1 parent 07eb9dcb9a
commit 7cba5c8679
5 files changed
+128 -27

No files matched your search

+17
View File
@@ -670,6 +670,11 @@ pub struct DensitySwap<'a> {
variants: Vec<Element<'a, Message>>,
chosen: Cell<usize>,
height_out: Option<Arc<AtomicU32>>,
/// Receives the FIRST (widest) variant's natural width in bits of an `f32`,
/// measured every layout regardless of which variant is shown — so a caller
/// can place a neighbouring widget relative to the full-size content even
/// while a narrower variant is on screen.
width0_out: Option<Arc<AtomicU32>>,
}
impl<'a> DensitySwap<'a> {
@@ -678,6 +683,7 @@ impl<'a> DensitySwap<'a> {
variants,
chosen: Cell::new(0),
height_out: None,
width0_out: None,
}
}
@@ -687,6 +693,12 @@ impl<'a> DensitySwap<'a> {
self.height_out = Some(out);
self
}
/// Report the first variant's natural (unconstrained) width — see `width0_out`.
pub fn report_width0(mut self, out: Arc<AtomicU32>) -> Self {
self.width0_out = Some(out);
self
}
}
impl<'a> Widget<Message, Theme, Renderer> for DensitySwap<'a> {
@@ -718,6 +730,11 @@ impl<'a> Widget<Message, Theme, Renderer> for DensitySwap<'a> {
let mut pick = self.variants.len().saturating_sub(1);
for (i, v) in self.variants.iter_mut().enumerate() {
let n = v.as_widget_mut().layout(&mut tree.children[i], renderer, &natural);
if i == 0 {
if let Some(out) = &self.width0_out {
out.store(n.size().width.to_bits(), Ordering::Relaxed);
}
}
if n.size().width <= max_w {
pick = i;
break;