fix(viewport): preserve tiled pane controls
This commit is contained in:
parent
8e2b67bfa5
commit
cd1378e6b2
4 changed files with 40 additions and 7 deletions
|
|
@ -218,6 +218,7 @@ impl OpenCADStudio {
|
||||||
)
|
)
|
||||||
.width(Fill)
|
.width(Fill)
|
||||||
.height(Fill)
|
.height(Fill)
|
||||||
|
.min_size(scene.model_pane_min_px())
|
||||||
.spacing(crate::scene::TILE_DIVIDER_PX);
|
.spacing(crate::scene::TILE_DIVIDER_PX);
|
||||||
stack![size_probe, shaders].width(Fill).height(Fill).into()
|
stack![size_probe, shaders].width(Fill).height(Fill).into()
|
||||||
};
|
};
|
||||||
|
|
@ -236,6 +237,7 @@ impl OpenCADStudio {
|
||||||
})
|
})
|
||||||
.width(Fill)
|
.width(Fill)
|
||||||
.height(Fill)
|
.height(Fill)
|
||||||
|
.min_size(scene.model_pane_min_px())
|
||||||
.spacing(crate::scene::TILE_DIVIDER_PX)
|
.spacing(crate::scene::TILE_DIVIDER_PX)
|
||||||
.on_resize(6.0, Message::PaneResized)
|
.on_resize(6.0, Message::PaneResized)
|
||||||
.into(),
|
.into(),
|
||||||
|
|
@ -782,6 +784,7 @@ impl OpenCADStudio {
|
||||||
.into(),
|
.into(),
|
||||||
])
|
])
|
||||||
.report_width0(self.render_bar_w.clone())
|
.report_width0(self.render_bar_w.clone())
|
||||||
|
.report_width0(tab.scene.model_pane_min_reporter())
|
||||||
.into();
|
.into();
|
||||||
// Pin the bar to the active model tile's top-left corner so it
|
// Pin the bar to the active model tile's top-left corner so it
|
||||||
// follows the active panel in a tiled layout.
|
// follows the active panel in a tiled layout.
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,24 @@ use super::*;
|
||||||
impl Scene {
|
impl Scene {
|
||||||
// ── Layout management ─────────────────────────────────────────────────
|
// ── Layout management ─────────────────────────────────────────────────
|
||||||
|
|
||||||
|
pub(crate) fn model_pane_min_px(&self) -> f32 {
|
||||||
|
let measured = f32::from_bits(
|
||||||
|
self.model_pane_min_px
|
||||||
|
.load(std::sync::atomic::Ordering::Relaxed),
|
||||||
|
);
|
||||||
|
if measured.is_finite() && measured > 1.0 {
|
||||||
|
measured
|
||||||
|
} else {
|
||||||
|
MODEL_PANE_MIN_FALLBACK_PX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn model_pane_min_reporter(
|
||||||
|
&self,
|
||||||
|
) -> std::sync::Arc<std::sync::atomic::AtomicU32> {
|
||||||
|
self.model_pane_min_px.clone()
|
||||||
|
}
|
||||||
|
|
||||||
/// Rename a paper-space layout. Updates the Layout object name in the document.
|
/// Rename a paper-space layout. Updates the Layout object name in the document.
|
||||||
pub fn rename_layout(&mut self, old_name: &str, new_name: &str) {
|
pub fn rename_layout(&mut self, old_name: &str, new_name: &str) {
|
||||||
for obj in self.document.objects.values_mut() {
|
for obj in self.document.objects.values_mut() {
|
||||||
|
|
@ -361,7 +379,11 @@ impl Scene {
|
||||||
let half = TILE_DIVIDER_PX * 0.5;
|
let half = TILE_DIVIDER_PX * 0.5;
|
||||||
self.model_panes
|
self.model_panes
|
||||||
.layout()
|
.layout()
|
||||||
.split_regions(TILE_DIVIDER_PX, 0.0, iced::Size::new(vw, vh))
|
.split_regions(
|
||||||
|
TILE_DIVIDER_PX,
|
||||||
|
self.model_pane_min_px(),
|
||||||
|
iced::Size::new(vw, vh),
|
||||||
|
)
|
||||||
.values()
|
.values()
|
||||||
.map(|(axis, region, ratio)| match axis {
|
.map(|(axis, region, ratio)| match axis {
|
||||||
Axis::Vertical => {
|
Axis::Vertical => {
|
||||||
|
|
@ -394,7 +416,7 @@ impl Scene {
|
||||||
}
|
}
|
||||||
let regions = self.model_panes.layout().pane_regions(
|
let regions = self.model_panes.layout().pane_regions(
|
||||||
TILE_DIVIDER_PX,
|
TILE_DIVIDER_PX,
|
||||||
0.0,
|
self.model_pane_min_px(),
|
||||||
iced::Size::new(vw, vh),
|
iced::Size::new(vw, vh),
|
||||||
);
|
);
|
||||||
self.model_panes
|
self.model_panes
|
||||||
|
|
@ -421,7 +443,7 @@ impl Scene {
|
||||||
}
|
}
|
||||||
let regions = self.model_panes.layout().pane_regions(
|
let regions = self.model_panes.layout().pane_regions(
|
||||||
TILE_DIVIDER_PX,
|
TILE_DIVIDER_PX,
|
||||||
0.0,
|
self.model_pane_min_px(),
|
||||||
iced::Size::new(canvas_w, canvas_h),
|
iced::Size::new(canvas_w, canvas_h),
|
||||||
);
|
);
|
||||||
let mut tiles = self.model_tiles.borrow_mut();
|
let mut tiles = self.model_tiles.borrow_mut();
|
||||||
|
|
|
||||||
|
|
@ -1110,6 +1110,9 @@ pub(crate) struct ModelTile {
|
||||||
/// the drawn viewports line up exactly with the pane_grid layout.
|
/// the drawn viewports line up exactly with the pane_grid layout.
|
||||||
pub const TILE_DIVIDER_PX: f32 = 2.0;
|
pub const TILE_DIVIDER_PX: f32 = 2.0;
|
||||||
|
|
||||||
|
/// Minimum used until the viewport render-mode bar reports its natural width.
|
||||||
|
pub const MODEL_PANE_MIN_FALLBACK_PX: f32 = 50.0;
|
||||||
|
|
||||||
/// Shift every vertex of a freshly tessellated `MeshLodSet` into the
|
/// Shift every vertex of a freshly tessellated `MeshLodSet` into the
|
||||||
/// scene's local f32 space by subtracting `world_offset`. ACIS / SAT
|
/// scene's local f32 space by subtracting `world_offset`. ACIS / SAT
|
||||||
/// tessellation hands us WCS coordinates; the wire / hatch / face3d
|
/// tessellation hands us WCS coordinates; the wire / hatch / face3d
|
||||||
|
|
@ -1502,6 +1505,10 @@ pub struct Scene {
|
||||||
/// Plain field (not a `RefCell`) so the view can borrow it for the
|
/// Plain field (not a `RefCell`) so the view can borrow it for the
|
||||||
/// `PaneGrid` widget's lifetime; mutated through `&mut Scene` in update.
|
/// `PaneGrid` widget's lifetime; mutated through `&mut Scene` in update.
|
||||||
pub(crate) model_panes: iced::widget::pane_grid::State<usize>,
|
pub(crate) model_panes: iced::widget::pane_grid::State<usize>,
|
||||||
|
/// Natural width of the Model viewport control bar. `DensitySwap` updates
|
||||||
|
/// it during layout; every pane-grid geometry calculation reads it on the
|
||||||
|
/// next frame so a pane cannot become narrower than its controls.
|
||||||
|
model_pane_min_px: std::sync::Arc<std::sync::atomic::AtomicU32>,
|
||||||
pub selection: Rc<RefCell<SelectionState>>,
|
pub selection: Rc<RefCell<SelectionState>>,
|
||||||
/// The CAD document — single source of truth for all entities.
|
/// The CAD document — single source of truth for all entities.
|
||||||
pub document: CadDocument,
|
pub document: CadDocument,
|
||||||
|
|
@ -1903,6 +1910,7 @@ impl Scene {
|
||||||
last_sdf_text: RefCell::new(HashMap::default()),
|
last_sdf_text: RefCell::new(HashMap::default()),
|
||||||
// One pane mapped to tile 0 — matches the single default tile above.
|
// One pane mapped to tile 0 — matches the single default tile above.
|
||||||
model_panes: iced::widget::pane_grid::State::new(0).0,
|
model_panes: iced::widget::pane_grid::State::new(0).0,
|
||||||
|
model_pane_min_px: std::sync::Arc::new(std::sync::atomic::AtomicU32::new(0)),
|
||||||
selection: Rc::new(RefCell::new(SelectionState::default())),
|
selection: Rc::new(RefCell::new(SelectionState::default())),
|
||||||
document: CadDocument::new(),
|
document: CadDocument::new(),
|
||||||
object_data_cache: crate::entities::object_data::ObjectDataCache::default(),
|
object_data_cache: crate::entities::object_data::ObjectDataCache::default(),
|
||||||
|
|
|
||||||
|
|
@ -761,7 +761,7 @@ pub struct DensitySwap<'a> {
|
||||||
/// measured every layout regardless of which variant is shown — so a caller
|
/// measured every layout regardless of which variant is shown — so a caller
|
||||||
/// can place a neighbouring widget relative to the full-size content even
|
/// can place a neighbouring widget relative to the full-size content even
|
||||||
/// while a narrower variant is on screen.
|
/// while a narrower variant is on screen.
|
||||||
width0_out: Option<Arc<AtomicU32>>,
|
width0_out: Vec<Arc<AtomicU32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DensitySwap<'a> {
|
impl<'a> DensitySwap<'a> {
|
||||||
|
|
@ -770,7 +770,7 @@ impl<'a> DensitySwap<'a> {
|
||||||
variants,
|
variants,
|
||||||
chosen: Cell::new(0),
|
chosen: Cell::new(0),
|
||||||
height_out: None,
|
height_out: None,
|
||||||
width0_out: None,
|
width0_out: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -783,7 +783,7 @@ impl<'a> DensitySwap<'a> {
|
||||||
|
|
||||||
/// Report the first variant's natural (unconstrained) width — see `width0_out`.
|
/// Report the first variant's natural (unconstrained) width — see `width0_out`.
|
||||||
pub fn report_width0(mut self, out: Arc<AtomicU32>) -> Self {
|
pub fn report_width0(mut self, out: Arc<AtomicU32>) -> Self {
|
||||||
self.width0_out = Some(out);
|
self.width0_out.push(out);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -818,7 +818,7 @@ impl<'a> Widget<Message, Theme, Renderer> for DensitySwap<'a> {
|
||||||
for (i, v) in self.variants.iter_mut().enumerate() {
|
for (i, v) in self.variants.iter_mut().enumerate() {
|
||||||
let n = v.as_widget_mut().layout(&mut tree.children[i], renderer, &natural);
|
let n = v.as_widget_mut().layout(&mut tree.children[i], renderer, &natural);
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
if let Some(out) = &self.width0_out {
|
for out in &self.width0_out {
|
||||||
out.store(n.size().width.to_bits(), Ordering::Relaxed);
|
out.store(n.size().width.to_bits(), Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue