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

View File

@@ -36,6 +36,7 @@
flex_wrap="wrap"
justify_content="stretch"
gap="4"
overflow_y="scroll"
/>
</elements>
</layout>

View File

@@ -1,10 +1,9 @@
use std::{collections::HashMap, rc::Rc};
use wgui::{
components::{self, button::ComponentButton},
components::button::ComponentButton,
layout::WidgetPair,
parser::{Fetchable, ParseDocumentParams, ParserData, ParserState},
taffy::{self, Dimension, prelude::length},
};
use crate::{
@@ -16,7 +15,9 @@ pub struct TabApps {
#[allow(dead_code)]
pub state: ParserState,
#[allow(dead_code)]
entries: Vec<DesktopEntry>,
#[allow(dead_code)]
app_list: AppList,
}
@@ -105,7 +106,7 @@ impl AppList {
)?;
let button = data.fetch_component_as::<ComponentButton>("button")?;
button.on_click(Box::new(move |common, evt| {
button.on_click(Box::new(move |_common, _evt| {
log::info!("click");
Ok(())
}));

View File

@@ -1,6 +1,7 @@
use glam::{FloatExt, Vec2};
use glam::FloatExt;
use crate::{
drawing::Boundary,
event::{CallbackDataCommon, EventAlterables},
layout::{LayoutState, WidgetID},
widget::{WidgetData, WidgetObj},
@@ -46,7 +47,7 @@ pub struct CallbackData<'a> {
pub obj: &'a mut dyn WidgetObj,
pub data: &'a mut WidgetData,
pub widget_id: WidgetID,
pub widget_size: Vec2,
pub widget_boundary: Boundary,
pub pos: f32, // 0.0 (start of animation) - 1.0 (end of animation)
}
@@ -98,14 +99,13 @@ impl Animation {
};
let widget_node = *state.nodes.get(self.target_widget).unwrap();
let layout = state.tree.layout(widget_node).unwrap(); // should always succeed
let mut widget_state = widget.state();
let (data, obj) = widget_state.get_data_obj_mut();
let data = &mut CallbackData {
widget_id: self.target_widget,
widget_size: Vec2::new(layout.size.width, layout.size.height),
widget_boundary: state.get_widget_boundary(widget_node),
obj,
data,
pos,

View File

@@ -1,21 +1,25 @@
use std::{cell::RefCell, rc::Rc};
use taffy::{AlignItems, JustifyContent};
use crate::{
animation::{Animation, AnimationEasing},
components::{Component, ComponentBase, ComponentTrait, InitData},
drawing::{self, Color},
drawing::{self, Boundary, Color},
event::{CallbackDataCommon, EventListenerCollection, EventListenerKind, ListenerHandleVec},
globals::Globals,
i18n::Translation,
layout::{Layout, WidgetID},
renderer_vk::text::{FontWeight, TextStyle},
layout::{Layout, WidgetID, WidgetPair},
renderer_vk::{
text::{FontWeight, TextStyle},
util::centered_matrix,
},
widget::{
WidgetData,
label::{WidgetLabel, WidgetLabelParams},
rectangle::{WidgetRectangle, WidgetRectangleParams},
util::WLength,
},
};
use glam::{Mat4, Vec3};
use std::{cell::RefCell, rc::Rc};
use taffy::{AlignItems, JustifyContent};
pub struct Params {
pub text: Option<Translation>, // if unset, label will not be populated
@@ -93,24 +97,43 @@ fn get_color2(color: &drawing::Color) -> drawing::Color {
color.lerp(&Color::new(0.0, 0.0, 0.0, color.a), 0.2)
}
fn anim_hover(rect: &mut WidgetRectangle, data: &Data, pos: f32, pressed: bool) {
fn anim_hover(
rect: &mut WidgetRectangle,
widget_data: &mut WidgetData,
data: &Data,
widget_boundary: Boundary,
pos: f32,
pressed: bool,
) {
let mult = pos * if pressed { 1.5 } else { 1.0 };
let bgcolor = data.initial_color.lerp(&data.initial_hover_color, mult);
//let t = Mat4::from_scale(Vec3::splat(1.0 + pos * 0.5)) * Mat4::from_rotation_z(pos * 1.0);
let t = Mat4::from_scale(Vec3::splat(1.0 + pos * 0.05));
widget_data.transform = centered_matrix(widget_boundary.size, &t);
rect.params.color = bgcolor;
rect.params.color2 = get_color2(&bgcolor);
rect.params.border_color = data.initial_border_color.lerp(&data.initial_hover_border_color, mult);
rect.params.border = 2.0;
}
fn anim_hover_out(data: Rc<Data>, state: Rc<RefCell<State>>, widget_id: WidgetID) -> Animation {
fn anim_hover_create(data: Rc<Data>, state: Rc<RefCell<State>>, widget_id: WidgetID, fade_in: bool) -> Animation {
Animation::new(
widget_id,
15,
if fade_in { 5 } else { 10 },
AnimationEasing::OutCubic,
Box::new(move |common, anim_data| {
let rect = anim_data.obj.get_as_mut::<WidgetRectangle>().unwrap();
anim_hover(rect, &data, 1.0 - anim_data.pos, state.borrow().down);
anim_hover(
rect,
anim_data.data,
&data,
anim_data.widget_boundary,
if fade_in { anim_data.pos } else { 1.0 - anim_data.pos },
state.borrow().down,
);
common.alterables.mark_redraw();
}),
)
@@ -129,10 +152,13 @@ fn register_event_mouse_enter<U1, U2>(
Box::new(move |common, event_data, _, _| {
common.alterables.trigger_haptics();
common.alterables.mark_redraw();
let rect = event_data.obj.get_as_mut::<WidgetRectangle>().unwrap();
let mut state = state.borrow_mut();
anim_hover(rect, &data, 1.0, state.down);
state.hovered = true;
common.alterables.animate(anim_hover_create(
data.clone(),
state.clone(),
event_data.widget_id,
true,
));
state.borrow_mut().hovered = true;
Ok(())
}),
);
@@ -150,9 +176,12 @@ fn register_event_mouse_leave<U1, U2>(
EventListenerKind::MouseLeave,
Box::new(move |common, event_data, _, _| {
common.alterables.trigger_haptics();
common
.alterables
.animate(anim_hover_out(data.clone(), state.clone(), event_data.widget_id));
common.alterables.animate(anim_hover_create(
data.clone(),
state.clone(),
event_data.widget_id,
false,
));
state.borrow_mut().hovered = false;
Ok(())
}),
@@ -173,7 +202,14 @@ fn register_event_mouse_press<U1, U2>(
let mut state = state.borrow_mut();
let rect = event_data.obj.get_as_mut::<WidgetRectangle>().unwrap();
anim_hover(rect, &data, 1.0, true);
anim_hover(
rect,
event_data.widget_data,
&data,
common.state.get_widget_boundary(event_data.node_id),
1.0,
true,
);
if state.hovered {
state.down = true;
@@ -199,7 +235,14 @@ fn register_event_mouse_release<U1, U2>(
EventListenerKind::MouseRelease,
Box::new(move |common, event_data, _, _| {
let rect = event_data.obj.get_as_mut::<WidgetRectangle>().unwrap();
anim_hover(rect, &data, 1.0, false);
anim_hover(
rect,
event_data.widget_data,
&data,
common.state.get_widget_boundary(event_data.node_id),
1.0,
false,
);
let mut state = state.borrow_mut();
if state.down {
@@ -226,7 +269,7 @@ pub fn construct<U1, U2>(
listeners: &mut EventListenerCollection<U1, U2>,
parent: WidgetID,
params: Params,
) -> anyhow::Result<(WidgetID, Rc<ComponentButton>)> {
) -> anyhow::Result<(WidgetPair, Rc<ComponentButton>)> {
let mut style = params.style;
// force-override style
@@ -260,7 +303,7 @@ pub fn construct<U1, U2>(
Color::new(color.r + 0.5, color.g + 0.5, color.g + 0.5, color.a + 0.5)
};
let (id_root, _) = layout.add_child(
let (root, _) = layout.add_child(
parent,
WidgetRectangle::create(WidgetRectangleParams {
color,
@@ -272,12 +315,13 @@ pub fn construct<U1, U2>(
}),
style,
)?;
let id_rect = id_root;
let id_rect = root.id;
let light_text = (color.r + color.g + color.b) < 1.5;
let id_label = if let Some(content) = params.text {
let (id_label, _node_label) = layout.add_child(
let (label, _node_label) = layout.add_child(
id_rect,
WidgetLabel::create(
globals,
@@ -296,7 +340,7 @@ pub fn construct<U1, U2>(
),
Default::default(),
)?;
id_label
label.id
} else {
WidgetID::default()
};
@@ -326,5 +370,5 @@ pub fn construct<U1, U2>(
let button = Rc::new(ComponentButton { base, data, state });
layout.defer_component_init(Component(button.clone()));
Ok((id_root, button))
Ok((root, button))
}

View File

@@ -10,7 +10,7 @@ use crate::{
drawing::Color,
event::{CallbackDataCommon, EventAlterables, EventListenerCollection, EventListenerKind, ListenerHandleVec},
i18n::Translation,
layout::{self, Layout, LayoutState, WidgetID},
layout::{self, Layout, LayoutState, WidgetID, WidgetPair},
renderer_vk::text::{FontWeight, TextStyle},
widget::{
label::{WidgetLabel, WidgetLabelParams},
@@ -249,7 +249,7 @@ pub fn construct<U1, U2>(
listeners: &mut EventListenerCollection<U1, U2>,
parent: WidgetID,
params: Params,
) -> anyhow::Result<(WidgetID, Rc<ComponentCheckbox>)> {
) -> anyhow::Result<(WidgetPair, Rc<ComponentCheckbox>)> {
let mut style = params.style;
// force-override style
@@ -267,7 +267,7 @@ pub fn construct<U1, U2>(
let globals = layout.state.globals.clone();
let (id_root, _) = layout.add_child(
let (root, _) = layout.add_child(
parent,
WidgetRectangle::create(WidgetRectangleParams {
color: Color::new(1.0, 1.0, 1.0, 0.0),
@@ -277,14 +277,15 @@ pub fn construct<U1, U2>(
}),
style,
)?;
let id_container = id_root;
let id_container = root.id;
let box_size = taffy::Size {
width: length(params.box_size),
height: length(params.box_size),
};
let (id_outer_box, _) = layout.add_child(
let (outer_box, _) = layout.add_child(
id_container,
WidgetRectangle::create(WidgetRectangleParams {
border: 2.0,
@@ -302,8 +303,8 @@ pub fn construct<U1, U2>(
},
)?;
let (id_inner_box, _) = layout.add_child(
id_outer_box,
let (inner_box, _) = layout.add_child(
outer_box.id,
WidgetRectangle::create(WidgetRectangleParams {
round: WLength::Units(5.0),
color: if params.checked { COLOR_CHECKED } else { COLOR_UNCHECKED },
@@ -318,7 +319,7 @@ pub fn construct<U1, U2>(
},
)?;
let (id_label, _node_label) = layout.add_child(
let (label, _node_label) = layout.add_child(
id_container,
WidgetLabel::create(
&mut globals.get(),
@@ -335,8 +336,8 @@ pub fn construct<U1, U2>(
let data = Rc::new(Data {
id_container,
id_inner_box,
id_label,
id_inner_box: inner_box.id,
id_label: label.id,
});
let state = Rc::new(RefCell::new(State {
@@ -356,5 +357,5 @@ pub fn construct<U1, U2>(
let checkbox = Rc::new(ComponentCheckbox { base, data, state });
layout.defer_component_init(Component(checkbox.clone()));
Ok((id_root, checkbox))
Ok((root, checkbox))
}

View File

@@ -9,7 +9,7 @@ use crate::{
drawing::{self},
event::{self, CallbackDataCommon, EventListenerCollection, EventListenerKind, ListenerHandleVec},
i18n::Translation,
layout::{Layout, WidgetID},
layout::{Layout, WidgetID, WidgetPair},
renderer_vk::{
text::{FontWeight, HorizontalAlign, TextStyle},
util,
@@ -175,7 +175,7 @@ fn on_enter_anim(common: &mut event::CallbackDataCommon, handle_id: WidgetID) {
AnimationEasing::OutBack,
Box::new(move |common, data| {
let rect = data.obj.get_as_mut::<WidgetRectangle>().unwrap();
data.data.transform = get_anim_transform(data.pos, data.widget_size);
data.data.transform = get_anim_transform(data.pos, data.widget_boundary.size);
anim_rect(rect, data.pos);
common.alterables.mark_redraw();
}),
@@ -189,7 +189,7 @@ fn on_leave_anim(common: &mut event::CallbackDataCommon, handle_id: WidgetID) {
AnimationEasing::OutQuad,
Box::new(move |common, data| {
let rect = data.obj.get_as_mut::<WidgetRectangle>().unwrap();
data.data.transform = get_anim_transform(1.0 - data.pos, data.widget_size);
data.data.transform = get_anim_transform(1.0 - data.pos, data.widget_boundary.size);
anim_rect(rect, 1.0 - data.pos);
common.alterables.mark_redraw();
}),
@@ -308,14 +308,14 @@ pub fn construct<U1, U2>(
listeners: &mut EventListenerCollection<U1, U2>,
parent: WidgetID,
params: Params,
) -> anyhow::Result<(WidgetID, Rc<ComponentSlider>)> {
) -> anyhow::Result<(WidgetPair, Rc<ComponentSlider>)> {
let mut style = params.style;
style.position = taffy::Position::Relative;
style.min_size = style.size;
style.max_size = style.size;
let (root_id, slider_body_node) = layout.add_child(parent, WidgetDiv::create(), style)?;
let body_id = root_id;
let (root, slider_body_node) = layout.add_child(parent, WidgetDiv::create(), style)?;
let body_id = root.id;
let (_background_id, _) = layout.add_child(
body_id,
@@ -350,10 +350,10 @@ pub fn construct<U1, U2>(
};
// invisible outer handle body
let (slider_handle_id, slider_handle_node) = layout.add_child(body_id, WidgetDiv::create(), slider_handle_style)?;
let (slider_handle, slider_handle_node) = layout.add_child(body_id, WidgetDiv::create(), slider_handle_style)?;
let (slider_handle_rect_id, _) = layout.add_child(
slider_handle_id,
let (slider_handle_rect, _) = layout.add_child(
slider_handle.id,
WidgetRectangle::create(WidgetRectangleParams {
color: HANDLE_COLOR,
border_color: HANDLE_BORDER_COLOR,
@@ -379,8 +379,8 @@ pub fn construct<U1, U2>(
let globals = layout.state.globals.clone();
let (slider_text_id, _) = layout.add_child(
slider_handle_id,
let (slider_text, _) = layout.add_child(
slider_handle.id,
WidgetLabel::create(
&mut globals.get(),
WidgetLabelParams {
@@ -399,9 +399,9 @@ pub fn construct<U1, U2>(
let data = Rc::new(Data {
body: body_id,
slider_handle_node,
slider_handle_rect_id,
slider_handle_rect_id: slider_handle_rect.id,
slider_body_node,
slider_text_id,
slider_text_id: slider_text.id,
});
let state = Rc::new(RefCell::new(state));
@@ -418,5 +418,5 @@ pub fn construct<U1, U2>(
let slider = Rc::new(ComponentSlider { base, data, state });
layout.defer_component_init(Component(slider.clone()));
Ok((root_id, slider))
Ok((root, slider))
}

View File

@@ -7,8 +7,8 @@ use taffy::TraversePartialTree;
use crate::{
drawing,
layout::Widget,
renderer_vk::text::{custom_glyph::CustomGlyph, TextShadow},
stack::{self, ScissorStack, TransformStack},
renderer_vk::text::{TextShadow, custom_glyph::CustomGlyph},
stack::{self, ScissorBoundary, ScissorStack, TransformStack},
widget::{self},
};
@@ -29,11 +29,22 @@ impl Boundary {
Self { pos, size }
}
pub const fn construct(transform_stack: &TransformStack) -> Self {
/// top-left is an absolute position
pub const fn construct_absolute(transform_stack: &TransformStack) -> Self {
let transform = transform_stack.get();
Self {
pos: Vec2::new(transform.pos.x, transform.pos.y),
pos: Vec2::new(transform.abs_pos.x, transform.abs_pos.y),
size: Vec2::new(transform.dim.x, transform.dim.y),
}
}
/// top-left is zero
pub const fn construct_relative(transform_stack: &TransformStack) -> Self {
let transform = transform_stack.get();
Self {
pos: Vec2::ZERO,
size: Vec2::new(transform.dim.x, transform.dim.y),
}
}
@@ -137,8 +148,7 @@ pub enum RenderPrimitive {
Rectangle(PrimitiveExtent, Rectangle),
Text(PrimitiveExtent, Rc<RefCell<Buffer>>, Option<TextShadow>),
Sprite(PrimitiveExtent, Option<CustomGlyph>), //option because we want as_slice
ScissorEnable(Boundary),
ScissorDisable,
ScissorSet(ScissorBoundary),
}
pub struct DrawParams<'a> {
@@ -146,7 +156,7 @@ pub struct DrawParams<'a> {
pub debug_draw: bool,
}
fn has_overflow_clip(style: &taffy::Style) -> bool {
pub fn has_overflow_clip(style: &taffy::Style) -> bool {
style.overflow.x != taffy::Overflow::Visible || style.overflow.y != taffy::Overflow::Visible
}
@@ -171,7 +181,6 @@ fn draw_widget(
node_id: taffy::NodeId,
style: &taffy::Style,
widget: &Widget,
parent_transform: &glam::Mat4,
) {
let Ok(l) = params.layout.state.tree.layout(node_id) else {
debug_assert!(false);
@@ -180,24 +189,23 @@ fn draw_widget(
let mut widget_state = widget.state();
let transform = widget_state.data.transform * *parent_transform;
let (shift, info) = match widget::get_scrollbar_info(l) {
let (scroll_shift, info) = match widget::get_scrollbar_info(l) {
Some(info) => (widget_state.get_scroll_shift(&info, l), Some(info)),
None => (Vec2::default(), None),
};
state.transform_stack.push(stack::Transform {
pos: Vec2::new(l.location.x, l.location.y) - shift,
transform,
rel_pos: Vec2::new(l.location.x, l.location.y) - scroll_shift,
transform: widget_state.data.transform,
dim: Vec2::new(l.size.width, l.size.height),
..Default::default()
});
if params.debug_draw {
let boundary = drawing::Boundary::construct(state.transform_stack);
let boundary = drawing::Boundary::construct_relative(state.transform_stack);
state.primitives.push(primitive_debug_rect(
&boundary,
&transform,
&state.transform_stack.get().transform,
Color::new(0.0, 1.0, 1.0, 0.5),
));
}
@@ -205,17 +213,23 @@ fn draw_widget(
let scissor_pushed = info.is_some() && has_overflow_clip(style);
if scissor_pushed {
let boundary = drawing::Boundary::construct(state.transform_stack);
state.scissor_stack.push(boundary);
let mut boundary_absolute = drawing::Boundary::construct_absolute(state.transform_stack);
boundary_absolute.pos += scroll_shift;
state.scissor_stack.push(ScissorBoundary(boundary_absolute));
if params.debug_draw {
let mut boundary_relative = drawing::Boundary::construct_relative(state.transform_stack);
boundary_relative.pos += scroll_shift;
state.primitives.push(primitive_debug_rect(
&boundary,
&transform,
&boundary_relative,
&state.transform_stack.get().transform,
Color::new(1.0, 0.0, 1.0, 1.0),
));
}
state.primitives.push(drawing::RenderPrimitive::ScissorEnable(boundary));
state
.primitives
.push(drawing::RenderPrimitive::ScissorSet(*state.scissor_stack.get()));
}
let draw_params = widget::DrawParams {
@@ -226,11 +240,13 @@ fn draw_widget(
widget_state.draw_all(state, &draw_params);
draw_children(params, state, node_id, &transform);
draw_children(params, state, node_id);
if scissor_pushed {
state.primitives.push(drawing::RenderPrimitive::ScissorDisable);
state.scissor_stack.pop();
state
.primitives
.push(drawing::RenderPrimitive::ScissorSet(*state.scissor_stack.get()));
}
state.transform_stack.pop();
@@ -240,7 +256,7 @@ fn draw_widget(
}
}
fn draw_children(params: &DrawParams, state: &mut DrawState, parent_node_id: taffy::NodeId, model: &glam::Mat4) {
fn draw_children(params: &DrawParams, state: &mut DrawState, parent_node_id: taffy::NodeId) {
let layout = &params.layout;
for node_id in layout.state.tree.child_ids(parent_node_id) {
@@ -259,7 +275,7 @@ fn draw_children(params: &DrawParams, state: &mut DrawState, parent_node_id: taf
continue;
};
draw_widget(params, state, node_id, style, widget, model);
draw_widget(params, state, node_id, style, widget);
}
}
@@ -267,7 +283,6 @@ pub fn draw(params: &DrawParams) -> anyhow::Result<Vec<RenderPrimitive>> {
let mut primitives = Vec::<RenderPrimitive>::new();
let mut transform_stack = TransformStack::new();
let mut scissor_stack = ScissorStack::new();
let model = glam::Mat4::IDENTITY;
let Some(root_widget) = params.layout.state.widgets.get(params.layout.root_widget) else {
panic!();
@@ -277,11 +292,6 @@ pub fn draw(params: &DrawParams) -> anyhow::Result<Vec<RenderPrimitive>> {
panic!();
};
scissor_stack.push(Boundary {
pos: Default::default(),
size: Vec2::splat(1.0e12),
});
let mut state = DrawState {
primitives: &mut primitives,
transform_stack: &mut transform_stack,
@@ -289,7 +299,7 @@ pub fn draw(params: &DrawParams) -> anyhow::Result<Vec<RenderPrimitive>> {
layout: params.layout,
};
draw_widget(params, &mut state, params.layout.root_node, style, root_widget, &model);
draw_widget(params, &mut state, params.layout.root_node, style, root_widget);
Ok(primitives)
}

View File

@@ -10,7 +10,7 @@ use crate::{
animation::{self, Animation},
i18n::I18n,
layout::{LayoutState, WidgetID},
stack::{Transform, TransformStack},
stack::{ScissorStack, Transform, TransformStack},
widget::{WidgetData, WidgetObj},
};
@@ -74,10 +74,10 @@ pub enum Event {
impl Event {
fn test_transform_pos(transform: &Transform, pos: Vec2) -> bool {
pos.x >= transform.pos.x
&& pos.x < transform.pos.x + transform.dim.x
&& pos.y >= transform.pos.y
&& pos.y < transform.pos.y + transform.dim.y
pos.x >= transform.abs_pos.x
&& pos.x < transform.abs_pos.x + transform.dim.x
&& pos.y >= transform.abs_pos.y
&& pos.y < transform.abs_pos.y + transform.dim.y
}
pub fn test_mouse_within_transform(&self, transform: &Transform) -> bool {
@@ -97,6 +97,7 @@ pub struct EventAlterables {
pub style_set_requests: Vec<(taffy::NodeId, taffy::Style)>,
pub animations: Vec<animation::Animation>,
pub transform_stack: TransformStack,
pub scissor_stack: ScissorStack,
pub needs_redraw: bool,
pub trigger_haptics: bool,
}
@@ -170,7 +171,7 @@ impl CallbackMetadata {
pub fn get_mouse_pos_relative(&self, transform_stack: &TransformStack) -> Option<Vec2> {
let mouse_pos_abs = self.get_mouse_pos_absolute()?;
Some(mouse_pos_abs - transform_stack.get().pos)
Some(mouse_pos_abs - transform_stack.get().abs_pos)
}
}

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)
}
}

View File

@@ -1,12 +1,11 @@
use crate::{
components::{button, Component},
components::{Component, button},
drawing::Color,
i18n::Translation,
layout::WidgetID,
parser::{
parse_children, process_component,
AttribPair, ParserContext, ParserFile, parse_children, process_component,
style::{parse_color_opt, parse_round, parse_style, parse_text_style},
AttribPair, ParserContext, ParserFile,
},
widget::util::WLength,
};
@@ -30,27 +29,27 @@ pub fn parse_component_button<'a, U1, U2>(
for pair in attribs {
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
match key.as_ref() {
match key {
"text" => {
translation = Some(Translation::from_raw_text(&value));
translation = Some(Translation::from_raw_text(value));
}
"translation" => {
translation = Some(Translation::from_translation_key(&value));
translation = Some(Translation::from_translation_key(value));
}
"round" => {
parse_round(&value, &mut round);
parse_round(value, &mut round);
}
"color" => {
parse_color_opt(&value, &mut color);
parse_color_opt(value, &mut color);
}
"border_color" => {
parse_color_opt(&value, &mut border_color);
parse_color_opt(value, &mut border_color);
}
"hover_color" => {
parse_color_opt(&value, &mut hover_color);
parse_color_opt(value, &mut hover_color);
}
"hover_border_color" => {
parse_color_opt(&value, &mut hover_border_color);
parse_color_opt(value, &mut hover_border_color);
}
_ => {}
}
@@ -58,7 +57,7 @@ pub fn parse_component_button<'a, U1, U2>(
let globals = ctx.layout.state.globals.clone();
let (new_id, component) = button::construct(
let (widget, component) = button::construct(
&mut globals.get(),
ctx.layout,
ctx.listeners,
@@ -75,8 +74,8 @@ pub fn parse_component_button<'a, U1, U2>(
},
)?;
process_component(ctx, Component(component), new_id, attribs);
parse_children(file, ctx, node, new_id)?;
process_component(ctx, Component(component), widget.id, attribs);
parse_children(file, ctx, node, widget.id)?;
Ok(new_id)
Ok(widget.id)
}

View File

@@ -1,11 +1,11 @@
use crate::{
components::{checkbox, Component},
components::{Component, checkbox},
i18n::Translation,
layout::WidgetID,
parser::{parse_check_f32, parse_check_i32, process_component, style::parse_style, AttribPair, ParserContext},
parser::{AttribPair, ParserContext, parse_check_f32, parse_check_i32, process_component, style::parse_style},
};
pub fn parse_component_checkbox<'a, U1, U2>(
pub fn parse_component_checkbox<U1, U2>(
ctx: &mut ParserContext<U1, U2>,
parent_id: WidgetID,
attribs: &[AttribPair],
@@ -35,7 +35,7 @@ pub fn parse_component_checkbox<'a, U1, U2>(
}
}
let (new_id, component) = checkbox::construct(
let (widget, component) = checkbox::construct(
ctx.layout,
ctx.listeners,
parent_id,
@@ -47,7 +47,7 @@ pub fn parse_component_checkbox<'a, U1, U2>(
},
)?;
process_component(ctx, Component(component), new_id, attribs);
process_component(ctx, Component(component), widget.id, attribs);
Ok(new_id)
Ok(widget.id)
}

View File

@@ -1,10 +1,10 @@
use crate::{
components::{slider, Component},
components::{Component, slider},
layout::WidgetID,
parser::{parse_check_f32, process_component, style::parse_style, AttribPair, ParserContext},
parser::{AttribPair, ParserContext, parse_check_f32, process_component, style::parse_style},
};
pub fn parse_component_slider<'a, U1, U2>(
pub fn parse_component_slider<U1, U2>(
ctx: &mut ParserContext<U1, U2>,
parent_id: WidgetID,
attribs: &[AttribPair],
@@ -31,7 +31,7 @@ pub fn parse_component_slider<'a, U1, U2>(
}
}
let (new_id, component) = slider::construct(
let (widget, component) = slider::construct(
ctx.layout,
ctx.listeners,
parent_id,
@@ -45,7 +45,7 @@ pub fn parse_component_slider<'a, U1, U2>(
},
)?;
process_component(ctx, Component(component), new_id, attribs);
process_component(ctx, Component(component), widget.id, attribs);
Ok(new_id)
Ok(widget.id)
}

View File

@@ -530,9 +530,9 @@ fn parse_widget_other_internal<U1, U2>(
Ok(())
}
fn parse_widget_other<'a, U1, U2>(
fn parse_widget_other<U1, U2>(
xml_tag_name: &str,
file: &'a ParserFile,
file: &ParserFile,
ctx: &mut ParserContext<U1, U2>,
parent_id: WidgetID,
attribs: &[AttribPair],
@@ -548,7 +548,7 @@ fn parse_widget_other<'a, U1, U2>(
parse_widget_other_internal(&template, template_parameters, file, ctx, parent_id)
}
fn parse_tag_include<'a, U1, U2>(
fn parse_tag_include<U1, U2>(
file: &ParserFile,
ctx: &mut ParserContext<U1, U2>,
parent_id: WidgetID,
@@ -641,7 +641,7 @@ fn process_attrib<'a, U1, U2>(
let name = &value[1..];
match ctx.get_var(name) {
Some(name) => AttribPair::new(key, name.clone()),
Some(name) => AttribPair::new(key, name),
None => AttribPair::new(key, "undefined"),
}
} else {
@@ -655,7 +655,7 @@ fn raw_attribs<'a>(node: &'a roxmltree::Node<'a, 'a>) -> Vec<AttribPair> {
let (key, value) = (attrib.name(), attrib.value());
res.push(AttribPair::new(key, value));
}
return res;
res
}
fn process_attribs<'a, U1, U2>(
@@ -761,7 +761,7 @@ fn parse_tag_macro<U1, U2>(file: &ParserFile, ctx: &mut ParserContext<U1, U2>, n
ctx.insert_macro_attrib(name, MacroAttribs { attribs: macro_attribs });
}
fn process_component<'a, U1, U2>(
fn process_component<U1, U2>(
ctx: &mut ParserContext<U1, U2>,
component: Component,
widget_id: WidgetID,
@@ -782,7 +782,7 @@ fn process_component<'a, U1, U2>(
ctx.insert_component(widget_id, component, component_id);
}
fn parse_widget_universal<'a, U1, U2>(ctx: &mut ParserContext<U1, U2>, widget_id: WidgetID, attribs: &[AttribPair]) {
fn parse_widget_universal<U1, U2>(ctx: &mut ParserContext<U1, U2>, widget_id: WidgetID, attribs: &[AttribPair]) {
for pair in attribs {
#[allow(clippy::single_match)]
match pair.attrib.as_ref() {
@@ -957,7 +957,7 @@ impl CustomAttribsInfo<'_> {
CustomAttribsInfoOwned {
parent_id: self.parent_id,
widget_id: self.widget_id,
pairs: self.pairs.iter().cloned().collect(),
pairs: self.pairs.to_vec(),
}
}
}

View File

@@ -6,8 +6,8 @@ use taffy::{
use crate::{
drawing,
parser::{
is_percent, parse_color_hex, parse_f32, parse_percent, parse_size_unit, parse_val, print_invalid_attrib,
print_invalid_value, AttribPair,
AttribPair, is_percent, parse_color_hex, parse_f32, parse_percent, parse_size_unit, parse_val,
print_invalid_attrib, print_invalid_value,
},
renderer_vk::text::{FontWeight, HorizontalAlign, TextStyle},
widget::util::WLength,
@@ -54,7 +54,7 @@ pub fn parse_text_style(attribs: &[AttribPair]) -> TextStyle {
style.color = Some(color);
}
}
"align" => match value.as_ref() {
"align" => match value {
"left" => style.align = Some(HorizontalAlign::Left),
"right" => style.align = Some(HorizontalAlign::Right),
"center" => style.align = Some(HorizontalAlign::Center),
@@ -64,7 +64,7 @@ pub fn parse_text_style(attribs: &[AttribPair]) -> TextStyle {
print_invalid_attrib(key, value);
}
},
"weight" => match value.as_ref() {
"weight" => match value {
"normal" => style.weight = Some(FontWeight::Normal),
"bold" => style.weight = Some(FontWeight::Bold),
_ => {
@@ -111,8 +111,8 @@ pub fn parse_style(attribs: &[AttribPair]) -> taffy::Style {
for pair in attribs {
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
match key.as_ref() {
"display" => match value.as_ref() {
match key {
"display" => match value {
"flex" => style.display = Display::Flex,
"block" => style.display = Display::Block,
"grid" => style.display = Display::Grid,
@@ -176,7 +176,7 @@ pub fn parse_style(attribs: &[AttribPair]) -> taffy::Style {
style.padding.bottom = dim;
}
}
"overflow" => match value.as_ref() {
"overflow" => match value {
"hidden" => {
style.overflow.x = Overflow::Hidden;
style.overflow.y = Overflow::Hidden;
@@ -197,7 +197,7 @@ pub fn parse_style(attribs: &[AttribPair]) -> taffy::Style {
print_invalid_attrib(key, value);
}
},
"overflow_x" => match value.as_ref() {
"overflow_x" => match value {
"hidden" => style.overflow.x = Overflow::Hidden,
"visible" => style.overflow.x = Overflow::Visible,
"clip" => style.overflow.x = Overflow::Clip,
@@ -206,7 +206,7 @@ pub fn parse_style(attribs: &[AttribPair]) -> taffy::Style {
print_invalid_attrib(key, value);
}
},
"overflow_y" => match value.as_ref() {
"overflow_y" => match value {
"hidden" => style.overflow.y = Overflow::Hidden,
"visible" => style.overflow.y = Overflow::Visible,
"clip" => style.overflow.y = Overflow::Clip,
@@ -265,21 +265,21 @@ pub fn parse_style(attribs: &[AttribPair]) -> taffy::Style {
style.flex_shrink = val;
}
}
"position" => match value.as_ref() {
"position" => match value {
"absolute" => style.position = taffy::Position::Absolute,
"relative" => style.position = taffy::Position::Relative,
_ => {
print_invalid_attrib(key, value);
}
},
"box_sizing" => match value.as_ref() {
"box_sizing" => match value {
"border_box" => style.box_sizing = BoxSizing::BorderBox,
"content_box" => style.box_sizing = BoxSizing::ContentBox,
_ => {
print_invalid_attrib(key, value);
}
},
"align_self" => match value.as_ref() {
"align_self" => match value {
"baseline" => style.align_self = Some(AlignSelf::Baseline),
"center" => style.align_self = Some(AlignSelf::Center),
"end" => style.align_self = Some(AlignSelf::End),
@@ -291,7 +291,7 @@ pub fn parse_style(attribs: &[AttribPair]) -> taffy::Style {
print_invalid_attrib(key, value);
}
},
"justify_self" => match value.as_ref() {
"justify_self" => match value {
"center" => style.justify_self = Some(JustifySelf::Center),
"end" => style.justify_self = Some(JustifySelf::End),
"flex_end" => style.justify_self = Some(JustifySelf::FlexEnd),
@@ -302,7 +302,7 @@ pub fn parse_style(attribs: &[AttribPair]) -> taffy::Style {
print_invalid_attrib(key, value);
}
},
"align_items" => match value.as_ref() {
"align_items" => match value {
"baseline" => style.align_items = Some(AlignItems::Baseline),
"center" => style.align_items = Some(AlignItems::Center),
"end" => style.align_items = Some(AlignItems::End),
@@ -314,7 +314,7 @@ pub fn parse_style(attribs: &[AttribPair]) -> taffy::Style {
print_invalid_attrib(key, value);
}
},
"align_content" => match value.as_ref() {
"align_content" => match value {
"center" => style.align_content = Some(AlignContent::Center),
"end" => style.align_content = Some(AlignContent::End),
"flex_end" => style.align_content = Some(AlignContent::FlexEnd),
@@ -328,7 +328,7 @@ pub fn parse_style(attribs: &[AttribPair]) -> taffy::Style {
print_invalid_attrib(key, value);
}
},
"justify_content" => match value.as_ref() {
"justify_content" => match value {
"center" => style.justify_content = Some(JustifyContent::Center),
"end" => style.justify_content = Some(JustifyContent::End),
"flex_end" => style.justify_content = Some(JustifyContent::FlexEnd),
@@ -342,13 +342,13 @@ pub fn parse_style(attribs: &[AttribPair]) -> taffy::Style {
print_invalid_attrib(key, value);
}
},
"flex_wrap" => match value.as_ref() {
"flex_wrap" => match value {
"wrap" => style.flex_wrap = FlexWrap::Wrap,
"no_wrap" => style.flex_wrap = FlexWrap::NoWrap,
"wrap_reverse" => style.flex_wrap = FlexWrap::WrapReverse,
_ => {}
},
"flex_direction" => match value.as_ref() {
"flex_direction" => match value {
"column_reverse" => style.flex_direction = FlexDirection::ColumnReverse,
"column" => style.flex_direction = FlexDirection::Column,
"row_reverse" => style.flex_direction = FlexDirection::RowReverse,

View File

@@ -1,6 +1,6 @@
use crate::{
layout::WidgetID,
parser::{parse_children, parse_widget_universal, style::parse_style, AttribPair, ParserContext, ParserFile},
parser::{AttribPair, ParserContext, ParserFile, parse_children, parse_widget_universal, style::parse_style},
widget::div::WidgetDiv,
};
@@ -13,10 +13,10 @@ pub fn parse_widget_div<'a, U1, U2>(
) -> anyhow::Result<WidgetID> {
let style = parse_style(attribs);
let (new_id, _) = ctx.layout.add_child(parent_id, WidgetDiv::create(), style)?;
let (widget, _) = ctx.layout.add_child(parent_id, WidgetDiv::create(), style)?;
parse_widget_universal(ctx, new_id, attribs);
parse_children(file, ctx, node, new_id)?;
parse_widget_universal(ctx, widget.id, attribs);
parse_children(file, ctx, node, widget.id)?;
Ok(new_id)
Ok(widget.id)
}

View File

@@ -2,9 +2,8 @@ use crate::{
i18n::Translation,
layout::WidgetID,
parser::{
parse_children, parse_widget_universal,
AttribPair, ParserContext, ParserFile, parse_children, parse_widget_universal,
style::{parse_style, parse_text_style},
AttribPair, ParserContext, ParserFile,
},
widget::label::{WidgetLabel, WidgetLabelParams},
};
@@ -40,12 +39,12 @@ pub fn parse_widget_label<'a, U1, U2>(
let globals = ctx.layout.state.globals.clone();
let (new_id, _) = ctx
let (widget, _) = ctx
.layout
.add_child(parent_id, WidgetLabel::create(&mut globals.get(), params), style)?;
parse_widget_universal(ctx, new_id, attribs);
parse_children(file, ctx, node, new_id)?;
parse_widget_universal(ctx, widget.id, attribs);
parse_children(file, ctx, node, widget.id)?;
Ok(new_id)
Ok(widget.id)
}

View File

@@ -2,9 +2,8 @@ use crate::{
drawing::GradientMode,
layout::WidgetID,
parser::{
parse_children, parse_widget_universal, print_invalid_attrib,
AttribPair, ParserContext, ParserFile, parse_children, parse_widget_universal, print_invalid_attrib,
style::{parse_color, parse_round, parse_style},
AttribPair, ParserContext, ParserFile,
},
widget::rectangle::{WidgetRectangle, WidgetRectangleParams},
};
@@ -17,7 +16,7 @@ pub fn parse_widget_rectangle<'a, U1, U2>(
attribs: &[AttribPair],
) -> anyhow::Result<WidgetID> {
let mut params = WidgetRectangleParams::default();
let style = parse_style(&attribs);
let style = parse_style(attribs);
for pair in attribs {
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
@@ -56,12 +55,12 @@ pub fn parse_widget_rectangle<'a, U1, U2>(
}
}
let (new_id, _) = ctx
let (widget, _) = ctx
.layout
.add_child(parent_id, WidgetRectangle::create(params), style)?;
parse_widget_universal(ctx, new_id, attribs);
parse_children(file, ctx, node, new_id)?;
parse_widget_universal(ctx, widget.id, attribs);
parse_children(file, ctx, node, widget.id)?;
Ok(new_id)
Ok(widget.id)
}

View File

@@ -1,6 +1,6 @@
use crate::{
layout::WidgetID,
parser::{parse_children, parse_widget_universal, style::parse_style, AttribPair, ParserContext, ParserFile},
parser::{AttribPair, ParserContext, ParserFile, parse_children, parse_widget_universal, style::parse_style},
renderer_vk::text::custom_glyph::{CustomGlyphContent, CustomGlyphData},
widget::sprite::{WidgetSprite, WidgetSpriteParams},
};
@@ -15,7 +15,7 @@ pub fn parse_widget_sprite<'a, U1, U2>(
attribs: &[AttribPair],
) -> anyhow::Result<WidgetID> {
let mut params = WidgetSpriteParams::default();
let style = parse_style(&attribs);
let style = parse_style(attribs);
let mut glyph = None;
for pair in attribs {
@@ -54,10 +54,10 @@ pub fn parse_widget_sprite<'a, U1, U2>(
log::warn!("No source for sprite node!");
}
let (new_id, _) = ctx.layout.add_child(parent_id, WidgetSprite::create(params), style)?;
let (widget, _) = ctx.layout.add_child(parent_id, WidgetSprite::create(params), style)?;
parse_widget_universal(ctx, new_id, attribs);
parse_children(file, ctx, node, new_id)?;
parse_widget_universal(ctx, widget.id, attribs);
parse_children(file, ctx, node, widget.id)?;
Ok(new_id)
Ok(widget.id)
}

View File

@@ -2,20 +2,20 @@ use std::{cell::RefCell, rc::Rc, sync::Arc};
use cosmic_text::Buffer;
use glam::{Mat4, Vec2, Vec3};
use slotmap::{new_key_type, SlotMap};
use slotmap::{SlotMap, new_key_type};
use vulkano::pipeline::graphics::viewport;
use crate::{
drawing::{self},
gfx::{cmd::GfxCommandBuffer, WGfx},
gfx::{WGfx, cmd::GfxCommandBuffer},
};
use super::{
rect::{RectPipeline, RectRenderer},
text::{
DEFAULT_METRICS, FONT_SYSTEM, SWASH_CACHE, TextArea, TextBounds,
text_atlas::{TextAtlas, TextPipeline},
text_renderer::TextRenderer,
TextArea, TextBounds, DEFAULT_METRICS, FONT_SYSTEM, SWASH_CACHE,
},
viewport::Viewport,
};
@@ -287,12 +287,8 @@ impl Context {
transform: extent.transform,
});
}
drawing::RenderPrimitive::ScissorEnable(boundary) => {
next_scissor = Some(*boundary);
needs_new_pass = true;
}
drawing::RenderPrimitive::ScissorDisable => {
next_scissor = None;
drawing::RenderPrimitive::ScissorSet(boundary) => {
next_scissor = Some(boundary.0);
needs_new_pass = true;
}
}

View File

@@ -1,4 +1,4 @@
use glam::Vec2;
use glam::{Mat4, Vec2, Vec3};
use crate::drawing;
@@ -50,18 +50,40 @@ impl<T: StackItem<T>, const STACK_MAX: usize> Default for GenericStack<T, STACK_
// Transform stack
// ########################################
#[derive(Default, Copy, Clone)]
#[derive(Copy, Clone)]
pub struct Transform {
pub pos: Vec2,
pub transform: glam::Mat4,
pub rel_pos: Vec2,
pub dim: Vec2, // for convenience
pub abs_pos: Vec2, // for convenience, will be set after pushing
pub transform: glam::Mat4,
pub transform_rel: glam::Mat4,
}
impl Default for Transform {
fn default() -> Self {
Self {
abs_pos: Default::default(),
rel_pos: Default::default(),
dim: Default::default(),
transform: Mat4::IDENTITY,
transform_rel: Default::default(),
}
}
}
impl<T> StackItem<T> for Transform where Transform: Pushable<T> {}
impl Pushable<Transform> for Transform {
fn push(&mut self, upper: &Transform) {
self.pos += upper.pos;
// fixme: there is definitely a better way to do these operations
let translation_matrix = Mat4::from_translation(Vec3::new(self.rel_pos.x, self.rel_pos.y, 0.0));
self.abs_pos = upper.abs_pos + self.rel_pos;
let absolute_shift_matrix = Mat4::from_translation(Vec3::new(self.abs_pos.x, self.abs_pos.y, 0.0));
let absolute_shift_matrix_neg = Mat4::from_translation(Vec3::new(-self.abs_pos.x, -self.abs_pos.y, 0.0));
self.transform =
(absolute_shift_matrix * self.transform * absolute_shift_matrix_neg) * upper.transform * translation_matrix;
}
}
@@ -71,12 +93,26 @@ pub type TransformStack = GenericStack<Transform, 64>;
// Scissor stack
// ########################################
impl<T> StackItem<T> for drawing::Boundary where drawing::Boundary: Pushable<T> {}
#[derive(Copy, Clone)]
pub struct ScissorBoundary(pub drawing::Boundary);
impl Pushable<drawing::Boundary> for drawing::Boundary {
fn push(&mut self, upper: &drawing::Boundary) {
let mut display_pos = self.pos;
let mut display_size = self.size;
impl Default for ScissorBoundary {
fn default() -> Self {
Self(drawing::Boundary {
pos: Default::default(),
size: Vec2::splat(1.0e12),
})
}
}
impl<T> StackItem<T> for ScissorBoundary where ScissorBoundary: Pushable<T> {}
impl Pushable<ScissorBoundary> for ScissorBoundary {
fn push(&mut self, upper: &ScissorBoundary) {
let mut display_pos = self.0.pos;
let mut display_size = self.0.size;
let upper = &upper.0;
// limit in x-coord
if display_pos.x < upper.left() {
@@ -100,9 +136,9 @@ impl Pushable<drawing::Boundary> for drawing::Boundary {
display_size.y = upper.bottom() - display_pos.y;
}
self.pos = display_pos;
self.size = display_size;
self.0.pos = display_pos;
self.0.size = display_size;
}
}
pub type ScissorStack = GenericStack<drawing::Boundary, 64>;
pub type ScissorStack = GenericStack<ScissorBoundary, 64>;

View File

@@ -10,7 +10,7 @@ use crate::{
globals::Globals,
i18n::{I18n, Translation},
layout::WidgetID,
renderer_vk::text::{TextStyle, FONT_SYSTEM},
renderer_vk::text::{FONT_SYSTEM, TextStyle},
};
use super::{WidgetObj, WidgetState};
@@ -109,7 +109,7 @@ impl WidgetLabel {
impl WidgetObj for WidgetLabel {
fn draw(&mut self, state: &mut super::DrawState, _params: &super::DrawParams) {
let boundary = drawing::Boundary::construct(state.transform_stack);
let boundary = drawing::Boundary::construct_relative(state.transform_stack);
if self.last_boundary != boundary {
self.last_boundary = boundary;

View File

@@ -11,6 +11,7 @@ use crate::{
},
layout::{Layout, LayoutState, WidgetID},
stack::{ScissorStack, TransformStack},
widget,
};
pub mod div;
@@ -248,8 +249,8 @@ impl WidgetState {
PrimitiveExtent {
boundary: drawing::Boundary::from_pos_size(
Vec2::new(
transform.pos.x + transform.dim.x * (1.0 - info.handle_size.x) * self.data.scrolling.x,
transform.pos.y + transform.dim.y - thickness - margin,
transform.abs_pos.x + transform.dim.x * (1.0 - info.handle_size.x) * self.data.scrolling.x,
transform.abs_pos.y + transform.dim.y - thickness - margin,
),
Vec2::new(transform.dim.x * info.handle_size.x, thickness),
),
@@ -265,8 +266,8 @@ impl WidgetState {
PrimitiveExtent {
boundary: drawing::Boundary::from_pos_size(
Vec2::new(
transform.pos.x + transform.dim.x - thickness - margin,
transform.pos.y + transform.dim.y * (1.0 - info.handle_size.y) * self.data.scrolling.y,
transform.abs_pos.x + transform.dim.x - thickness - margin,
transform.abs_pos.y + transform.dim.y * (1.0 - info.handle_size.y) * self.data.scrolling.y,
),
Vec2::new(thickness, transform.dim.y * info.handle_size.y),
),

View File

@@ -36,7 +36,7 @@ impl WidgetRectangle {
impl WidgetObj for WidgetRectangle {
fn draw(&mut self, state: &mut super::DrawState, _params: &super::DrawParams) {
let boundary = drawing::Boundary::construct(state.transform_stack);
let boundary = drawing::Boundary::construct_relative(state.transform_stack);
let round_units = match self.params.round {
WLength::Units(units) => units as u8,

View File

@@ -7,8 +7,8 @@ use crate::{
drawing::{self, PrimitiveExtent},
layout::WidgetID,
renderer_vk::text::{
custom_glyph::{CustomGlyph, CustomGlyphData},
DEFAULT_METRICS, FONT_SYSTEM,
custom_glyph::{CustomGlyph, CustomGlyphData},
},
};
@@ -37,7 +37,7 @@ impl WidgetSprite {
impl WidgetObj for WidgetSprite {
fn draw(&mut self, state: &mut super::DrawState, _params: &super::DrawParams) {
let boundary = drawing::Boundary::construct(state.transform_stack);
let boundary = drawing::Boundary::construct_relative(state.transform_stack);
if let Some(glyph_data) = self.params.glyph_data.as_ref() {
let glyph = CustomGlyph {