scissor stack fixes, proper render & event transformations

This commit is contained in:
Aleksander
2025-09-29 22:04:16 +02:00
parent b73870236f
commit a1edc2f0b8
24 changed files with 361 additions and 218 deletions
+71 -16
View File
@@ -1,21 +1,22 @@
use std::{
cell::{RefCell, RefMut},
collections::VecDeque,
rc::Rc,
rc::{Rc, Weak},
};
use crate::{
animation::Animations,
components::{Component, InitData},
drawing::{self, Boundary, has_overflow_clip},
event::{self, CallbackDataCommon, EventAlterables, EventListenerCollection},
globals::WguiGlobals,
stack::Transform,
stack::{self, ScissorBoundary, Transform},
widget::{self, EventParams, WidgetObj, WidgetState, div::WidgetDiv},
};
use glam::{Vec2, vec2};
use slotmap::{HopSlotMap, SecondaryMap, new_key_type};
use taffy::{TaffyTree, TraversePartialTree};
use taffy::{NodeId, TaffyTree, TraversePartialTree};
new_key_type! {
pub struct WidgetID;
@@ -23,6 +24,7 @@ new_key_type! {
#[derive(Clone)]
pub struct Widget(Rc<RefCell<WidgetState>>);
pub struct WeakWidget(Weak<RefCell<WidgetState>>);
impl Widget {
pub fn new(widget_state: WidgetState) -> Self {
@@ -33,11 +35,21 @@ impl Widget {
RefMut::filter_map(self.0.borrow_mut(), |w| w.obj.get_as_mut::<T>()).ok()
}
pub fn downgrade(&self) -> WeakWidget {
WeakWidget(Rc::downgrade(&self.0))
}
pub fn state(&self) -> RefMut<'_, WidgetState> {
self.0.borrow_mut()
}
}
impl WeakWidget {
pub fn upgrade(&self) -> Option<Widget> {
self.0.upgrade().map(Widget)
}
}
pub struct WidgetMap(HopSlotMap<WidgetID, Widget>);
pub type WidgetNodeMap = SecondaryMap<WidgetID, taffy::NodeId>;
@@ -128,9 +140,10 @@ fn add_child_internal(
parent_node: Option<taffy::NodeId>,
widget_state: WidgetState,
style: taffy::Style,
) -> anyhow::Result<(WidgetID, taffy::NodeId)> {
#[allow(clippy::arc_with_non_send_sync)]
let child_id = widgets.insert(Widget::new(widget_state));
) -> anyhow::Result<(WidgetPair, taffy::NodeId)> {
let new_widget = Widget::new(widget_state);
let child_id = widgets.insert(new_widget.clone());
let child_node = tree.new_leaf_with_context(style, child_id)?;
if let Some(parent_node) = parent_node {
@@ -139,7 +152,13 @@ fn add_child_internal(
nodes.insert(child_id, child_node);
Ok((child_id, child_node))
Ok((
WidgetPair {
id: child_id,
widget: new_widget,
},
child_node,
))
}
impl Layout {
@@ -152,7 +171,7 @@ impl Layout {
parent_widget_id: WidgetID,
widget: WidgetState,
style: taffy::Style,
) -> anyhow::Result<(WidgetID, taffy::NodeId)> {
) -> anyhow::Result<(WidgetPair, taffy::NodeId)> {
let parent_node = *self.state.nodes.get(parent_widget_id).unwrap();
self.mark_redraw();
@@ -255,13 +274,26 @@ impl Layout {
anyhow::bail!("invalid widget");
};
let transform = Transform {
pos: Vec2::new(l.location.x, l.location.y),
dim: Vec2::new(l.size.width, l.size.height),
transform: glam::Mat4::IDENTITY, // TODO: event transformations? Not needed for now
let mut widget = widget.0.borrow_mut();
let (scroll_shift, info) = match widget::get_scrollbar_info(l) {
Some(info) => (widget.get_scroll_shift(&info, l), Some(info)),
None => (Vec2::default(), None),
};
alterables.transform_stack.push(transform);
alterables.transform_stack.push(stack::Transform {
rel_pos: Vec2::new(l.location.x, l.location.y) - scroll_shift,
transform: widget.data.transform,
dim: Vec2::new(l.size.width, l.size.height),
..Default::default()
});
// see drawing.rs too
let scissor_pushed = info.is_some() && has_overflow_clip(style);
if scissor_pushed {
let mut boundary_absolute = drawing::Boundary::construct_absolute(&alterables.transform_stack);
boundary_absolute.pos += scroll_shift;
alterables.scissor_stack.push(ScissorBoundary(boundary_absolute));
}
let mut iter_children = true;
@@ -275,8 +307,6 @@ impl Layout {
let listeners_vec = listeners.get(widget_id);
let mut widget = widget.0.borrow_mut();
match widget.process_event(widget_id, listeners_vec, node_id, event, user_data, &mut params)? {
widget::EventResult::Pass => {
// go on
@@ -292,6 +322,10 @@ impl Layout {
self.push_event_children(listeners, node_id, event, alterables, user_data)?;
}
if scissor_pushed {
alterables.scissor_stack.pop();
}
alterables.transform_stack.pop();
Ok(())
@@ -361,7 +395,7 @@ impl Layout {
prev_size: Vec2::default(),
content_size: Vec2::default(),
root_node,
root_widget,
root_widget: root_widget.id,
needs_redraw: true,
haptics_triggered: false,
animations: Animations::default(),
@@ -468,3 +502,24 @@ impl Layout {
Ok(())
}
}
impl LayoutState {
pub fn get_widget_boundary(&self, id: NodeId) -> Boundary {
let Ok(layout) = self.tree.layout(id) else {
return Boundary::default();
};
Boundary {
pos: Vec2::new(layout.location.x, layout.location.y),
size: Vec2::new(layout.size.width, layout.size.height),
}
}
pub fn get_widget_size(&self, id: NodeId) -> Vec2 {
let Ok(layout) = self.tree.layout(id) else {
return Vec2::ZERO;
};
Vec2::new(layout.size.width, layout.size.height)
}
}