move widgets on draw if region size is same

This commit is contained in:
2025-09-27 16:11:30 -04:00
parent 5f2dffc189
commit 95f049acb4
13 changed files with 204 additions and 176 deletions

View File

@@ -4,7 +4,7 @@ use crate::{
Textures, UiRegion, UiVec2, Vec2, WidgetId, Widgets,
},
render::{Primitive, PrimitiveHandle},
util::{HashMap, HashSet, Id, IdUtil},
util::{HashMap, HashSet, Id},
};
pub struct Painter<'a, 'c> {
@@ -62,13 +62,13 @@ impl<'a> PainterCtx<'a> {
}
}
pub fn redraw(&mut self, id: &Id) {
pub fn redraw(&mut self, id: Id) {
self.drawing.clear();
let Some(active) = self.active.get(id) else {
let Some(active) = self.active.get(&id) else {
return;
};
if let Some((rid, size)) = &active.resize {
if let Some((rid, size)) = active.resize {
let checked = &mut HashMap::default();
let mut ctx = SizeCtx {
checked,
@@ -77,9 +77,9 @@ impl<'a> PainterCtx<'a> {
widgets: self.widgets,
};
let desired = ctx.size_inner(id);
if *size != desired {
self.redraw(&rid.duplicate());
if self.drawing.contains(id) {
if size != desired {
self.redraw(rid);
if self.drawing.contains(&id) {
return;
}
}
@@ -93,13 +93,13 @@ impl<'a> PainterCtx<'a> {
active.layer,
id,
active.region,
active.parent.duplicate(),
active.parent,
Some(active.children),
);
self.active.get_mut(id).unwrap().resize = active.resize;
self.active.get_mut(&id).unwrap().resize = active.resize;
}
pub fn draw(&mut self, id: &Id) {
pub fn draw(&mut self, id: Id) {
self.drawing.clear();
self.layers.clear();
self.draw_inner(0, id, UiRegion::full(), None, None);
@@ -108,7 +108,7 @@ impl<'a> PainterCtx<'a> {
fn draw_inner(
&mut self,
layer: usize,
id: &Id,
id: Id,
region: UiRegion,
parent: Option<Id>,
old_children: Option<Vec<Id>>,
@@ -119,31 +119,32 @@ impl<'a> PainterCtx<'a> {
// but this has a very weird issue where you can't move widgets unless u remove first
// so swapping is impossible rn I think?
// there's definitely better solutions like a counter (>1 = panic) but don't care rn
if self.drawing.contains(id) {
if self.drawing.contains(&id) {
panic!("Cannot draw the same widget twice (1)");
}
let mut old_children = old_children.unwrap_or_default();
let mut resize = None;
if let Some(active) = self.active.get_mut(id) {
if let Some(active) = self.active.get_mut(&id) {
if active.parent != parent {
panic!("Cannot draw the same widget twice (2)");
}
if active.region == region {
return;
} else if active.region.size() == region.size() {
self.mov(id, region);
return;
}
// TODO:
// else if active.region.size() == region.size() { move }
let active = self.remove(id).unwrap();
old_children = active.children;
resize = active.resize;
}
self.drawing.insert(id.duplicate());
self.drawing.insert(id);
let mut painter = Painter {
region,
layer,
id: id.duplicate(),
id,
textures: Vec::new(),
primitives: Vec::new(),
ctx: self,
@@ -158,7 +159,7 @@ impl<'a> PainterCtx<'a> {
// add to active
let instance = WidgetInstance {
id: id.duplicate(),
id,
region,
parent,
textures: painter.textures,
@@ -169,24 +170,43 @@ impl<'a> PainterCtx<'a> {
};
for (cid, size) in sized_children {
if let Some(w) = self.active.get_mut(&cid) {
w.resize = Some((id.duplicate(), size))
w.resize = Some((id, size))
}
}
for c in &old_children {
if !instance.children.contains(c) {
self.remove_rec(c);
self.remove_rec(*c);
}
}
for m in self.modules.iter_mut() {
m.on_draw(&instance);
}
self.active.insert(id.duplicate(), instance);
self.active.insert(id, instance);
}
fn mov(&mut self, id: Id, to: UiRegion) {
let active = self.active.get_mut(&id).unwrap();
// children will not be changed, so this technically should not be needed
// probably need unsafe
let from = active.region;
for h in &active.primitives {
let region = self.layers[h.layer].primitives.region_mut(h);
*region = region.outside(&from).within(&to);
}
active.region = to;
for m in self.modules.iter_mut() {
m.on_move(active);
}
let children = active.children.clone();
for child in children {
self.mov(child, to);
}
}
/// NOTE: instance textures are cleared and self.textures freed
fn remove(&mut self, id: &Id) -> Option<WidgetInstance> {
let mut inst = self.active.remove(id);
fn remove(&mut self, id: Id) -> Option<WidgetInstance> {
let mut inst = self.active.remove(&id);
if let Some(inst) = &mut inst {
for h in &inst.primitives {
self.layers.free(h);
@@ -200,11 +220,11 @@ impl<'a> PainterCtx<'a> {
inst
}
fn remove_rec(&mut self, id: &Id) -> Option<WidgetInstance> {
fn remove_rec(&mut self, id: Id) -> Option<WidgetInstance> {
let inst = self.remove(id);
if let Some(inst) = &inst {
for c in &inst.children {
self.remove_rec(c);
self.remove_rec(*c);
}
}
inst
@@ -216,7 +236,7 @@ impl<'a, 'c> Painter<'a, 'c> {
let h = self
.ctx
.layers
.write(self.layer, self.id.duplicate(), primitive, region);
.write(self.layer, self.id, primitive, region);
self.primitives.push(h);
}
@@ -241,9 +261,9 @@ impl<'a, 'c> Painter<'a, 'c> {
}
fn widget_at<W>(&mut self, id: &WidgetId<W>, region: UiRegion) {
self.children.push(id.id.duplicate());
self.children.push(id.id);
self.ctx
.draw_inner(self.layer, &id.id, region, Some(self.id.duplicate()), None);
.draw_inner(self.layer, id.id, region, Some(self.id), None);
}
pub fn texture_within(&mut self, handle: &TextureHandle, region: UiRegion) {
@@ -308,9 +328,9 @@ pub struct SizeCtx<'a> {
}
impl SizeCtx<'_> {
fn size_inner(&mut self, id: &Id) -> UiVec2 {
fn size_inner(&mut self, id: Id) -> UiVec2 {
let size = self.widgets.get_dyn_dynamic(id).desired_size(self);
self.checked.insert(id.duplicate(), size);
self.checked.insert(id, size);
size
}
pub fn size<W>(&mut self, id: &WidgetId<W>) -> UiVec2 {
@@ -318,7 +338,7 @@ impl SizeCtx<'_> {
// if let Some(size) = self.checked.get(&id.id) {
// return Some(*size);
// }
self.size_inner(&id.id)
self.size_inner(id.id)
}
pub fn draw_text(
&mut self,