(BROKEN) start on removing desired size

This commit is contained in:
2025-12-23 23:48:35 -05:00
parent 462c0e6416
commit 93291badc1
8 changed files with 94 additions and 28 deletions

View File

@@ -24,10 +24,23 @@ impl Align {
pub const TOP: CardinalAlign = CardinalAlign::TOP; pub const TOP: CardinalAlign = CardinalAlign::TOP;
pub const V_CENTER: CardinalAlign = CardinalAlign::V_CENTER; pub const V_CENTER: CardinalAlign = CardinalAlign::V_CENTER;
pub const BOT: CardinalAlign = CardinalAlign::BOT; pub const BOT: CardinalAlign = CardinalAlign::BOT;
pub const NONE: Align = Align { x: None, y: None };
pub fn tuple(&self) -> (Option<AxisAlign>, Option<AxisAlign>) { pub fn tuple(&self) -> (Option<AxisAlign>, Option<AxisAlign>) {
(self.x, self.y) (self.x, self.y)
} }
/// naming is a bit inconsistent w option,
/// normally would return Self, but can't see
/// that being needed atm and would wanna do
/// a trait if so, so they can both be named .or
/// (because Self impls From<RegionAlign>)
pub fn or(&self, other: RegionAlign) -> RegionAlign {
RegionAlign {
x: self.x.unwrap_or(other.x),
y: self.y.unwrap_or(other.x),
}
}
} }
#[derive(Clone, Copy, PartialEq, Eq)] #[derive(Clone, Copy, PartialEq, Eq)]
@@ -106,6 +119,7 @@ impl UiVec2 {
} }
} }
/// aligns this as a size within a region
pub fn align(&self, align: RegionAlign) -> UiRegion { pub fn align(&self, align: RegionAlign) -> UiRegion {
UiRegion { UiRegion {
x: self.x.align(align.x), x: self.x.align(align.x),

View File

@@ -140,12 +140,22 @@ where
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, bytemuck::Pod, Default, bytemuck::Zeroable)] #[derive(Debug, Copy, Clone, bytemuck::Pod, Default, bytemuck::Zeroable)]
pub struct UiScalar { pub struct UiScalar {
pub rel: f32, pub rel: f32,
pub abs: f32, pub abs: f32,
} }
// TODO: unknown exactly what these should be
const REL_EPSILON: f32 = 0.00001;
const ABS_EPSILON: f32 = 0.1;
impl PartialEq for UiScalar {
fn eq(&self, other: &Self) -> bool {
(self.rel - other.rel).abs() < REL_EPSILON && (self.abs - other.abs).abs() < ABS_EPSILON
}
}
impl Eq for UiScalar {} impl Eq for UiScalar {}
impl Hash for UiScalar { impl Hash for UiScalar {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { fn hash<H: std::hash::Hasher>(&self, state: &mut H) {

View File

@@ -1,8 +1,9 @@
use crate::{BothAxis, Len, UiVec2, WidgetId, util::HashMap}; use crate::{BothAxis, Len, UiRegion, UiVec2, WidgetId, util::HashMap};
#[derive(Default)] #[derive(Default)]
pub struct Cache { pub struct Cache {
pub size: BothAxis<HashMap<WidgetId, (UiVec2, Len)>>, pub size: BothAxis<HashMap<WidgetId, (UiVec2, Len)>>,
pub moves: HashMap<WidgetId, UiRegion>,
} }
impl Cache { impl Cache {

View File

@@ -1,5 +1,5 @@
use crate::{ use crate::{
ActiveData, Axis, EventsLike, Painter, SizeCtx, Ui, UiRegion, UiVec2, WidgetId, ActiveData, Align, Axis, EventsLike, Painter, SizeCtx, Ui, UiRegion, UiVec2, WidgetId,
render::MaskIdx, render::MaskIdx,
util::{HashSet, forget_ref}, util::{HashSet, forget_ref},
}; };
@@ -25,6 +25,7 @@ impl<'a> DrawState<'a> {
while let Some(&id) = self.widgets.needs_redraw.iter().next() { while let Some(&id) = self.widgets.needs_redraw.iter().next() {
self.redraw(id); self.redraw(id);
} }
self.apply_moves();
self.ui.free(self.events); self.ui.free(self.events);
} }
@@ -89,8 +90,17 @@ impl<'a> DrawState<'a> {
self.widgets.needs_redraw.clear(); self.widgets.needs_redraw.clear();
if let Some(id) = &self.ui.root { if let Some(id) = &self.ui.root {
self.draw_inner(0, id.id(), UiRegion::FULL, None, MaskIdx::NONE, None); self.draw_inner(
0,
id.id(),
UiRegion::FULL,
None,
MaskIdx::NONE,
None,
Align::NONE,
);
} }
self.apply_moves();
} }
pub(super) fn draw_inner( pub(super) fn draw_inner(
@@ -101,19 +111,18 @@ impl<'a> DrawState<'a> {
parent: Option<WidgetId>, parent: Option<WidgetId>,
mask: MaskIdx, mask: MaskIdx,
old_children: Option<Vec<WidgetId>>, old_children: Option<Vec<WidgetId>>,
) { align: Align,
) -> UiRegion {
let mut old_children = old_children.unwrap_or_default(); let mut old_children = old_children.unwrap_or_default();
if let Some(active) = self.ui.active.get_mut(&id) if let Some(active) = self.ui.active.get_mut(&id)
&& !self.ui.widgets.needs_redraw.contains(&id) && !self.ui.widgets.needs_redraw.contains(&id)
{ {
// check to see if we can skip drawing first // check to see if we can skip drawing first, and just need to move
if active.region == region { if active.region == region {
return; return region;
} else if active.region.size() == region.size() { } else if active.region.size() == region.size() {
// TODO: epsilon? self.ui.cache.moves.insert(id, region);
let from = active.region; return region;
self.mov(id, from, region);
return;
} }
// if not, then maintain resize and track old children to remove unneeded // if not, then maintain resize and track old children to remove unneeded
let active = self.remove(id, false).unwrap(); let active = self.remove(id, false).unwrap();
@@ -126,6 +135,7 @@ impl<'a> DrawState<'a> {
let mut painter = Painter { let mut painter = Painter {
state: self, state: self,
region, region,
region_used: region,
mask, mask,
layer, layer,
id, id,
@@ -134,11 +144,13 @@ impl<'a> DrawState<'a> {
children: Vec::new(), children: Vec::new(),
}; };
let mut widget = painter.state.widgets.get_dyn_dynamic(id); let mut widget = painter.state.widgets.get_dyn(id);
widget.draw(&mut painter); widget.draw(&mut painter);
drop(widget); let walign = painter.state.widgets.data(id).unwrap().align;
let align = align.or(walign.into());
let Painter { let Painter {
region_used,
state: _, state: _,
region, region,
mask, mask,
@@ -149,6 +161,14 @@ impl<'a> DrawState<'a> {
id, id,
} = painter; } = painter;
// TODO: unsure if there's a better way, currently using epsilon
// in PartialEq impl for UiScalar
let target = region_used.size().align(align);
if region_used != target {
TODO; // THIS WILL NOT WORK to avoid removing, need to look at children?
self.ui.cache.moves.insert(id, target);
}
// add to active // add to active
let active = ActiveData { let active = ActiveData {
id, id,
@@ -171,6 +191,17 @@ impl<'a> DrawState<'a> {
// update modules // update modules
self.events.draw(&active); self.events.draw(&active);
self.active.insert(id, active); self.active.insert(id, active);
region_used
}
fn apply_moves(&mut self) {
let mut moves = std::mem::take(&mut self.ui.cache.moves);
for (id, to) in moves.drain() {
let from = self.active.get(&id).unwrap().region;
self.mov(id, from, to);
}
self.ui.cache.moves = moves;
} }
fn mov(&mut self, id: WidgetId, from: UiRegion, to: UiRegion) { fn mov(&mut self, id: WidgetId, from: UiRegion, to: UiRegion) {

View File

@@ -10,6 +10,7 @@ use crate::{
pub struct Painter<'a, 'b> { pub struct Painter<'a, 'b> {
pub(super) state: &'a mut DrawState<'b>, pub(super) state: &'a mut DrawState<'b>,
pub region_used: UiRegion,
pub(super) region: UiRegion, pub(super) region: UiRegion,
pub(super) mask: MaskIdx, pub(super) mask: MaskIdx,
pub(super) textures: Vec<TextureHandle>, pub(super) textures: Vec<TextureHandle>,

View File

@@ -30,7 +30,7 @@ impl SizeCtx<'_> {
} }
let len = self let len = self
.widgets .widgets
.get_dyn_dynamic(id) .get_dyn(id)
.desired_len::<A>(&mut SizeCtx { .desired_len::<A>(&mut SizeCtx {
text: self.text, text: self.text,
textures: self.textures, textures: self.textures,

View File

@@ -1,8 +1,11 @@
use crate::Widget; use crate::{RegionAlign, Widget};
pub struct WidgetData { pub struct WidgetData {
pub widget: Box<dyn Widget>, pub widget: Box<dyn Widget>,
pub label: String, pub label: String,
/// alignment used if this does not fill up container
/// and there is no enforced alignment from parent
pub align: RegionAlign,
/// dynamic borrow checking /// dynamic borrow checking
pub borrowed: bool, pub borrowed: bool,
} }
@@ -15,6 +18,7 @@ impl WidgetData {
} }
Self { Self {
widget: Box::new(widget), widget: Box::new(widget),
align: RegionAlign::CENTER,
label, label,
borrowed: false, borrowed: false,
} }

View File

@@ -26,18 +26,9 @@ impl Widgets {
!self.needs_redraw.is_empty() !self.needs_redraw.is_empty()
} }
pub fn get_dyn(&self, id: WidgetId) -> Option<&dyn Widget> {
Some(self.vec.get(id)?.widget.as_ref())
}
pub fn get_dyn_mut(&mut self, id: WidgetId) -> Option<&mut dyn Widget> {
self.needs_redraw.insert(id);
Some(self.vec.get_mut(id)?.widget.as_mut())
}
/// get_dyn but dynamic borrow checking of widgets /// get_dyn but dynamic borrow checking of widgets
/// lets you do recursive (tree) operations, like the painter does /// lets you do recursive (tree) operations, like the painter does
pub(crate) fn get_dyn_dynamic<'a>(&self, id: WidgetId) -> WidgetWrapper<'a> { pub(crate) fn get_dyn<'a>(&self, id: WidgetId) -> WidgetWrapper<'a> {
// SAFETY: must guarantee no other mutable references to this widget exist // SAFETY: must guarantee no other mutable references to this widget exist
// done through the borrow variable // done through the borrow variable
let data = unsafe { forget_mut(to_mut(self.vec.get(id).unwrap())) }; let data = unsafe { forget_mut(to_mut(self.vec.get(id).unwrap())) };
@@ -51,14 +42,26 @@ impl Widgets {
where where
I::Widget: Sized + Widget, I::Widget: Sized + Widget,
{ {
self.get_dyn(id.id())?.as_any().downcast_ref() self.vec
.get(id.id())?
.widget
.as_ref()
.as_any()
.downcast_ref()
} }
pub fn get_mut<I: IdLike>(&mut self, id: &I) -> Option<&mut I::Widget> pub fn get_mut<I: IdLike>(&mut self, id: &I) -> Option<&mut I::Widget>
where where
I::Widget: Sized + Widget, I::Widget: Sized + Widget,
{ {
self.get_dyn_mut(id.id())?.as_any_mut().downcast_mut() let id = id.id();
self.needs_redraw.insert(id);
self.vec
.get_mut(id)?
.widget
.as_mut()
.as_any_mut()
.downcast_mut()
} }
pub fn add_strong<W: Widget>(&mut self, widget: W) -> WidgetHandle<W> { pub fn add_strong<W: Widget>(&mut self, widget: W) -> WidgetHandle<W> {
@@ -77,7 +80,9 @@ impl Widgets {
if !self.waiting.remove(&rf.id()) { if !self.waiting.remove(&rf.id()) {
let label = self.label(rf); let label = self.label(rf);
let id = rf.id(); let id = rf.id();
panic!("widget '{label}' ({id:?}) was already added\ncannot add a widget twice; consider creating two") panic!(
"widget '{label}' ({id:?}) was already added\ncannot add a widget twice; consider creating two"
)
} }
WidgetHandle::new(rf.id(), self.send.clone()) WidgetHandle::new(rf.id(), self.send.clone())
} }