This commit is contained in:
iris committed 2026-01-12 18:40:27 -05:00
1 parent a9c76e4326
commit 79813db3ba
35 files changed
+378 -403

No files matched your search

+116
View File
@@ -0,0 +1,116 @@
use crate::{
ActiveData, EventsLike, IdLike, PixelRegion, PrimitiveLayers, StrongWidget, WidgetId, Widgets,
ui::{cache::Cache, draw_state::Drawer},
util::{HashMap, Vec2},
};
pub struct UiRenderState {
pub active: HashMap<WidgetId, ActiveData>,
pub layers: PrimitiveLayers,
pub(super) output_size: Vec2,
pub cache: Cache,
old_root: Option<WidgetId>,
resized: bool,
}
impl UiRenderState {
pub fn new() -> Self {
Self {
active: Default::default(),
layers: Default::default(),
cache: Default::default(),
output_size: Vec2::ZERO,
old_root: None,
resized: false,
}
}
pub fn resize(&mut self, size: impl Into<Vec2>) {
self.output_size = size.into();
self.resized = true;
}
pub fn update<'a>(
&mut self,
root: impl Into<Option<&'a StrongWidget>>,
widgets: &mut Widgets,
events: &mut dyn EventsLike,
) {
// safety mechanism for memory leaks; might wanna return a result instead so user can
// decide whether to panic or not
if !widgets.waiting.is_empty() {
let len = widgets.waiting.len();
let all: Vec<_> = widgets
.waiting
.iter()
.map(|&w| format!("'{}' ({w:?})", widgets.label(w)))
.collect();
panic!(
"{len} widget(s) were never upgraded\n\
this is likely a memory leak; consider upgrading to strong if you plan on using it later\n\
weak widgets: {all:#?}"
);
}
if self.root_changed(root) {
Drawer::new(self, events).redraw_all();
self.old_root = root.into().map(|r| r.id());
} else if widgets.has_updates() {
Drawer::new(self, events).redraw_updates();
}
if self.resized {
self.resized = false;
Drawer::new(self, events).redraw_all();
}
}
pub fn root_changed<'a>(&self, root: impl Into<Option<&'a StrongWidget>>) -> bool {
root.into().map(|r| r.id()) != self.old_root
}
pub fn needs_redraw<'a>(
&self,
root: impl Into<Option<&'a StrongWidget>>,
widgets: &Widgets,
) -> bool {
self.root_changed(root) || widgets.has_updates()
}
pub fn active_widgets(&self) -> usize {
self.active.len()
}
pub fn debug(&self, widgets: &Widgets, label: &str) -> impl Iterator<Item = &ActiveData> {
self.active.iter().filter_map(move |(&id, inst)| {
let l = widgets.label(id);
if l == label { Some(inst) } else { None }
})
}
pub fn debug_layers(&self) {
for ((idx, depth), primitives) in self.layers.iter_depth() {
let indent = " ".repeat(depth * 2);
let len = primitives.instances().len();
print!("{indent}{idx}: {len} primitives");
if len >= 1 {
print!(" ({})", primitives.instances()[0].binding);
}
println!();
}
}
pub fn window_region(&self, id: &impl IdLike) -> Option<PixelRegion> {
let region = self.active.get(&id.id())?.region;
Some(region.to_px(self.output_size))
}
}
pub trait HasRoot {
fn set_root(&mut self, root: StrongWidget);
}
impl Default for UiRenderState {
fn default() -> Self {
Self::new()
}
}