wgui: Refactoring, various changes (see desc)
- use parking_lot for mutex (less restrictive and easier to use) - simplify event callbacks and widget type casting - defer component initialization at start (required for setting the initial state of sliders) - fix non-working scroll events - update testbed.xml - replace slider with the real one in bar.xml - show slider text on its handle
This commit is contained in:
@@ -18,6 +18,7 @@ image = { version = "0.25.6", default-features = false, features = [
|
||||
log = { workspace = true }
|
||||
lru = "0.14.0"
|
||||
ouroboros = "0.18.5"
|
||||
parking_lot = "0.12.4"
|
||||
regex = "1.11.1"
|
||||
resvg = { version = "0.45.1", default-features = false }
|
||||
roxmltree = "0.20.0"
|
||||
|
||||
@@ -2,7 +2,7 @@ use glam::{FloatExt, Vec2};
|
||||
|
||||
use crate::{
|
||||
event::{CallbackDataCommon, EventAlterables, EventRefs},
|
||||
layout::{WidgetID, WidgetMap, WidgetNodeMap},
|
||||
layout::WidgetID,
|
||||
widget::{WidgetData, WidgetObj},
|
||||
};
|
||||
|
||||
@@ -90,14 +90,14 @@ impl Animation {
|
||||
}
|
||||
|
||||
fn call(&self, refs: &EventRefs, alterables: &mut EventAlterables, pos: f32) {
|
||||
let Some(widget) = refs.widget_map.get(self.target_widget).cloned() else {
|
||||
let Some(widget) = refs.widgets.get(self.target_widget).cloned() else {
|
||||
return; // failed
|
||||
};
|
||||
|
||||
let widget_node = *refs.widget_node_map.get(self.target_widget).unwrap();
|
||||
let widget_node = *refs.nodes.get(self.target_widget).unwrap();
|
||||
let layout = refs.tree.layout(widget_node).unwrap(); // should always succeed
|
||||
|
||||
let mut widget = widget.lock().unwrap();
|
||||
let mut widget = widget.lock();
|
||||
|
||||
let (data, obj) = widget.get_data_obj_mut();
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ use taffy::{AlignItems, JustifyContent, prelude::length};
|
||||
|
||||
use crate::{
|
||||
animation::{Animation, AnimationEasing},
|
||||
components::Component,
|
||||
components::{Component, InitData},
|
||||
drawing::{self, Color},
|
||||
event::{CallbackDataCommon, EventListenerCollection, EventListenerKind, ListenerHandleVec},
|
||||
layout::{Layout, WidgetID},
|
||||
@@ -50,15 +50,20 @@ pub struct Button {
|
||||
listener_handles: ListenerHandleVec,
|
||||
}
|
||||
|
||||
impl Component for Button {}
|
||||
impl Component for Button {
|
||||
fn init(&self, _data: &mut InitData) {}
|
||||
}
|
||||
|
||||
impl Button {
|
||||
pub fn set_text<C>(&self, callback_data: &mut CallbackDataCommon, text: &str) {
|
||||
callback_data.call_on_widget(self.data.text_id, |label: &mut TextLabel| {
|
||||
label.set_text(text);
|
||||
});
|
||||
callback_data.mark_redraw();
|
||||
callback_data.mark_dirty(self.data.text_node);
|
||||
pub fn set_text<C>(&self, common: &mut CallbackDataCommon, text: &str) {
|
||||
common
|
||||
.refs
|
||||
.widgets
|
||||
.call(self.data.text_id, |label: &mut TextLabel| {
|
||||
label.set_text(text);
|
||||
});
|
||||
common.alterables.mark_redraw();
|
||||
common.alterables.mark_dirty(self.data.text_node);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,12 +82,12 @@ fn anim_hover(rect: &mut Rectangle, data: &Data, pos: f32) {
|
||||
fn anim_hover_in(data: Rc<Data>, widget_id: WidgetID) -> Animation {
|
||||
Animation::new(
|
||||
widget_id,
|
||||
10,
|
||||
5,
|
||||
AnimationEasing::OutQuad,
|
||||
Box::new(move |common, anim_data| {
|
||||
let rect = anim_data.obj.get_as_mut::<Rectangle>();
|
||||
anim_hover(rect, &data, anim_data.pos);
|
||||
common.mark_redraw();
|
||||
common.alterables.mark_redraw();
|
||||
}),
|
||||
)
|
||||
}
|
||||
@@ -90,12 +95,12 @@ fn anim_hover_in(data: Rc<Data>, widget_id: WidgetID) -> Animation {
|
||||
fn anim_hover_out(data: Rc<Data>, widget_id: WidgetID) -> Animation {
|
||||
Animation::new(
|
||||
widget_id,
|
||||
15,
|
||||
8,
|
||||
AnimationEasing::OutQuad,
|
||||
Box::new(move |common, anim_data| {
|
||||
let rect = anim_data.obj.get_as_mut::<Rectangle>();
|
||||
anim_hover(rect, &data, 1.0 - anim_data.pos);
|
||||
common.mark_redraw();
|
||||
common.alterables.mark_redraw();
|
||||
}),
|
||||
)
|
||||
}
|
||||
@@ -164,7 +169,9 @@ pub fn construct<U1, U2>(
|
||||
rect_id,
|
||||
EventListenerKind::MouseEnter,
|
||||
Box::new(move |common, event_data, _, _| {
|
||||
common.animate(anim_hover_in(data.clone(), event_data.widget_id));
|
||||
common
|
||||
.alterables
|
||||
.animate(anim_hover_in(data.clone(), event_data.widget_id));
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -174,12 +181,17 @@ pub fn construct<U1, U2>(
|
||||
rect_id,
|
||||
EventListenerKind::MouseLeave,
|
||||
Box::new(move |common, event_data, _, _| {
|
||||
common.animate(anim_hover_out(data.clone(), event_data.widget_id));
|
||||
common
|
||||
.alterables
|
||||
.animate(anim_hover_out(data.clone(), event_data.widget_id));
|
||||
}),
|
||||
);
|
||||
|
||||
Ok(Rc::new(Button {
|
||||
let button = Rc::new(Button {
|
||||
data: _data.clone(),
|
||||
listener_handles,
|
||||
}))
|
||||
});
|
||||
|
||||
layout.defer_component_init(button.clone());
|
||||
Ok(button)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
use crate::any::AnyTrait;
|
||||
use taffy::TaffyTree;
|
||||
|
||||
use crate::{
|
||||
any::AnyTrait,
|
||||
event::EventAlterables,
|
||||
layout::{WidgetID, WidgetMap},
|
||||
};
|
||||
|
||||
pub mod button;
|
||||
pub mod slider;
|
||||
|
||||
pub trait Component: AnyTrait {}
|
||||
pub struct InitData<'a> {
|
||||
pub alterables: &'a mut EventAlterables,
|
||||
pub widgets: &'a WidgetMap,
|
||||
pub tree: &'a TaffyTree<WidgetID>,
|
||||
}
|
||||
|
||||
pub trait Component: AnyTrait {
|
||||
fn init(&self, data: &mut InitData);
|
||||
}
|
||||
|
||||
@@ -1,23 +1,28 @@
|
||||
use std::{
|
||||
cell::{RefCell, RefMut},
|
||||
rc::Rc,
|
||||
};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
use glam::{Mat4, Vec2, Vec3};
|
||||
use taffy::prelude::{length, percent};
|
||||
use taffy::{
|
||||
TaffyTree,
|
||||
prelude::{length, percent},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
animation::{Animation, AnimationEasing},
|
||||
components::Component,
|
||||
components::{Component, InitData},
|
||||
drawing::{self},
|
||||
event::{
|
||||
self, CallbackDataCommon, EventListenerCollection, EventListenerKind, ListenerHandleVec,
|
||||
self, CallbackDataCommon, EventAlterables, EventListenerCollection, EventListenerKind,
|
||||
ListenerHandleVec,
|
||||
},
|
||||
layout::{Layout, WidgetID, WidgetMap},
|
||||
renderer_vk::{
|
||||
text::{FontWeight, HorizontalAlign, TextStyle},
|
||||
util,
|
||||
},
|
||||
layout::{Layout, WidgetID},
|
||||
renderer_vk::util,
|
||||
widget::{
|
||||
div::Div,
|
||||
rectangle::{Rectangle, RectangleParams},
|
||||
text::{TextLabel, TextParams},
|
||||
util::WLength,
|
||||
},
|
||||
};
|
||||
@@ -53,8 +58,8 @@ pub struct SliderState {
|
||||
|
||||
struct Data {
|
||||
body: WidgetID, // Div
|
||||
slider_handle_id: WidgetID, // Div
|
||||
slider_handle_rect_id: WidgetID, // Rectangle
|
||||
slider_text_id: WidgetID, // Text
|
||||
slider_handle_node: taffy::NodeId,
|
||||
slider_body_node: taffy::NodeId,
|
||||
}
|
||||
@@ -62,10 +67,24 @@ struct Data {
|
||||
pub struct Slider {
|
||||
data: Rc<Data>,
|
||||
state: Rc<RefCell<SliderState>>,
|
||||
|
||||
#[allow(dead_code)]
|
||||
listener_handles: ListenerHandleVec,
|
||||
}
|
||||
|
||||
impl Component for Slider {}
|
||||
impl Component for Slider {
|
||||
fn init(&self, init_data: &mut InitData) {
|
||||
let mut state = self.state.borrow_mut();
|
||||
let value = state.values.value;
|
||||
state.set_value(
|
||||
&self.data,
|
||||
init_data.alterables,
|
||||
init_data.widgets,
|
||||
init_data.tree,
|
||||
value,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTICE: this can be re-used in the future
|
||||
fn map_mouse_x_to_normalized(mouse_x_rel: f32, widget_width: f32) -> f32 {
|
||||
@@ -109,34 +128,44 @@ impl SliderState {
|
||||
|
||||
let norm = map_mouse_x_to_normalized(
|
||||
mouse_pos.x - HANDLE_WIDTH / 2.0,
|
||||
get_width(data.slider_body_node, common.get_tree()) - HANDLE_WIDTH,
|
||||
get_width(data.slider_body_node, common.refs.tree) - HANDLE_WIDTH,
|
||||
);
|
||||
|
||||
let target_value = self.values.get_from_normalized(norm);
|
||||
let val = target_value;
|
||||
self.set_value(data, common, val);
|
||||
|
||||
self.set_value(
|
||||
data,
|
||||
common.alterables,
|
||||
common.refs.widgets,
|
||||
common.refs.tree,
|
||||
val,
|
||||
);
|
||||
}
|
||||
|
||||
fn set_value(&mut self, data: &Data, common: &mut CallbackDataCommon, value: f32) {
|
||||
fn update_text(&self, text: &mut TextLabel, value: f32) {
|
||||
// round displayed value, should be sufficient for now
|
||||
text.set_text(&format!("{}", value.round()));
|
||||
}
|
||||
|
||||
fn set_value(
|
||||
&mut self,
|
||||
data: &Data,
|
||||
alterables: &mut EventAlterables,
|
||||
widgets: &WidgetMap,
|
||||
tree: &TaffyTree<WidgetID>,
|
||||
value: f32,
|
||||
) {
|
||||
//common.call_on_widget(data.slider_handle_id, |_div: &mut Div| {});
|
||||
self.values.value = value;
|
||||
|
||||
let mut style = common
|
||||
.refs
|
||||
.tree
|
||||
.style(data.slider_handle_node)
|
||||
.unwrap()
|
||||
.clone();
|
||||
|
||||
conf_handle_style(
|
||||
&self.values,
|
||||
data.slider_body_node,
|
||||
&mut style,
|
||||
common.get_tree(),
|
||||
);
|
||||
|
||||
common.mark_dirty(data.slider_handle_node);
|
||||
common.mark_redraw();
|
||||
common.set_style(data.slider_handle_node, style);
|
||||
let mut style = tree.style(data.slider_handle_node).unwrap().clone();
|
||||
conf_handle_style(&self.values, data.slider_body_node, &mut style, tree);
|
||||
alterables.mark_dirty(data.slider_handle_node);
|
||||
alterables.mark_redraw();
|
||||
alterables.set_style(data.slider_handle_node, style);
|
||||
widgets.call(data.slider_text_id, |label: &mut TextLabel| {
|
||||
self.update_text(label, value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,21 +191,21 @@ fn anim_rect(rect: &mut Rectangle, pos: f32) {
|
||||
}
|
||||
|
||||
fn on_enter_anim(common: &mut event::CallbackDataCommon, handle_id: WidgetID) {
|
||||
common.animate(Animation::new(
|
||||
common.alterables.animate(Animation::new(
|
||||
handle_id,
|
||||
5,
|
||||
AnimationEasing::OutQuad,
|
||||
20,
|
||||
AnimationEasing::OutBack,
|
||||
Box::new(move |common, data| {
|
||||
let rect = data.obj.get_as_mut::<Rectangle>();
|
||||
data.data.transform = get_anim_transform(data.pos, data.widget_size);
|
||||
anim_rect(rect, data.pos);
|
||||
common.mark_redraw();
|
||||
common.alterables.mark_redraw();
|
||||
}),
|
||||
));
|
||||
}
|
||||
|
||||
fn on_leave_anim(common: &mut event::CallbackDataCommon, handle_id: WidgetID) {
|
||||
common.animate(Animation::new(
|
||||
common.alterables.animate(Animation::new(
|
||||
handle_id,
|
||||
10,
|
||||
AnimationEasing::OutQuad,
|
||||
@@ -184,7 +213,7 @@ fn on_leave_anim(common: &mut event::CallbackDataCommon, handle_id: WidgetID) {
|
||||
let rect = data.obj.get_as_mut::<Rectangle>();
|
||||
data.data.transform = get_anim_transform(1.0 - data.pos, data.widget_size);
|
||||
anim_rect(rect, 1.0 - data.pos);
|
||||
common.mark_redraw();
|
||||
common.alterables.mark_redraw();
|
||||
}),
|
||||
));
|
||||
}
|
||||
@@ -200,7 +229,7 @@ fn register_event_mouse_enter<U1, U2>(
|
||||
data.body,
|
||||
EventListenerKind::MouseEnter,
|
||||
Box::new(move |common, _data, _, _| {
|
||||
common.trigger_haptics();
|
||||
common.alterables.trigger_haptics();
|
||||
state.borrow_mut().hovered = true;
|
||||
on_enter_anim(common, data.slider_handle_rect_id);
|
||||
}),
|
||||
@@ -218,7 +247,7 @@ fn register_event_mouse_leave<U1, U2>(
|
||||
data.body,
|
||||
EventListenerKind::MouseLeave,
|
||||
Box::new(move |common, _data, _, _| {
|
||||
common.trigger_haptics();
|
||||
common.alterables.trigger_haptics();
|
||||
state.borrow_mut().hovered = false;
|
||||
on_leave_anim(common, data.slider_handle_rect_id);
|
||||
}),
|
||||
@@ -256,7 +285,7 @@ fn register_event_mouse_press<U1, U2>(
|
||||
data.body,
|
||||
EventListenerKind::MousePress,
|
||||
Box::new(move |common, event_data, _, _| {
|
||||
common.trigger_haptics();
|
||||
common.alterables.trigger_haptics();
|
||||
let mut state = state.borrow_mut();
|
||||
|
||||
if state.hovered {
|
||||
@@ -278,7 +307,7 @@ fn register_event_mouse_release<U1, U2>(
|
||||
data.body,
|
||||
EventListenerKind::MouseRelease,
|
||||
Box::new(move |common, _data, _, _| {
|
||||
common.trigger_haptics();
|
||||
common.alterables.trigger_haptics();
|
||||
|
||||
let mut state = state.borrow_mut();
|
||||
if state.dragging {
|
||||
@@ -340,14 +369,6 @@ pub fn construct<U1, U2>(
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// TODO: dispatch style config after this taffy tree did a re-layout
|
||||
/*conf_handle_style(
|
||||
¶ms.values,
|
||||
slider_body_node,
|
||||
&mut slider_handle_style,
|
||||
&layout.tree,
|
||||
);*/
|
||||
|
||||
// invisible outer handle body
|
||||
let (slider_handle_id, slider_handle_node) =
|
||||
layout.add_child(body_id, Div::create()?, slider_handle_style)?;
|
||||
@@ -371,19 +392,34 @@ pub fn construct<U1, U2>(
|
||||
},
|
||||
)?;
|
||||
|
||||
let state = SliderState {
|
||||
dragging: false,
|
||||
hovered: false,
|
||||
values: params.values,
|
||||
};
|
||||
|
||||
let (slider_text_id, _) = layout.add_child(
|
||||
slider_handle_id,
|
||||
TextLabel::create(TextParams {
|
||||
content: String::new(),
|
||||
style: TextStyle {
|
||||
weight: Some(FontWeight::Bold),
|
||||
align: Some(HorizontalAlign::Center),
|
||||
..Default::default()
|
||||
},
|
||||
})?,
|
||||
Default::default(),
|
||||
)?;
|
||||
|
||||
let data = Rc::new(Data {
|
||||
body: body_id,
|
||||
slider_handle_node,
|
||||
slider_handle_rect_id,
|
||||
slider_handle_id,
|
||||
slider_body_node,
|
||||
slider_text_id,
|
||||
});
|
||||
|
||||
let state = Rc::new(RefCell::new(SliderState {
|
||||
dragging: false,
|
||||
hovered: false,
|
||||
values: params.values,
|
||||
}));
|
||||
let state = Rc::new(RefCell::new(state));
|
||||
|
||||
let mut lhandles = ListenerHandleVec::default();
|
||||
|
||||
@@ -400,5 +436,6 @@ pub fn construct<U1, U2>(
|
||||
listener_handles: lhandles,
|
||||
});
|
||||
|
||||
layout.defer_component_init(slider.clone());
|
||||
Ok(slider)
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ fn draw_widget(
|
||||
return;
|
||||
};
|
||||
|
||||
let mut widget_state = widget.lock().unwrap();
|
||||
let mut widget_state = widget.lock();
|
||||
|
||||
let transform = widget_state.data.transform * *parent_transform;
|
||||
|
||||
|
||||
@@ -88,8 +88,8 @@ impl Event {
|
||||
}
|
||||
|
||||
pub struct EventRefs<'a> {
|
||||
pub widget_map: &'a WidgetMap,
|
||||
pub widget_node_map: &'a WidgetNodeMap,
|
||||
pub widgets: &'a WidgetMap,
|
||||
pub nodes: &'a WidgetNodeMap,
|
||||
pub tree: &'a taffy::tree::TaffyTree<WidgetID>,
|
||||
}
|
||||
|
||||
@@ -103,53 +103,33 @@ pub struct EventAlterables {
|
||||
pub trigger_haptics: bool,
|
||||
}
|
||||
|
||||
pub struct CallbackDataCommon<'a> {
|
||||
pub refs: &'a EventRefs<'a>,
|
||||
pub alterables: &'a mut EventAlterables,
|
||||
}
|
||||
|
||||
impl CallbackDataCommon<'_> {
|
||||
pub fn call_on_widget<WIDGET, FUNC>(&self, widget_id: WidgetID, func: FUNC)
|
||||
where
|
||||
WIDGET: WidgetObj,
|
||||
FUNC: FnOnce(&mut WIDGET),
|
||||
{
|
||||
let Some(widget) = self.refs.widget_map.get(widget_id) else {
|
||||
debug_assert!(false);
|
||||
return;
|
||||
};
|
||||
|
||||
let mut lock = widget.lock().unwrap();
|
||||
let m = lock.obj.get_as_mut::<WIDGET>();
|
||||
|
||||
func(m);
|
||||
}
|
||||
|
||||
impl EventAlterables {
|
||||
pub fn mark_redraw(&mut self) {
|
||||
self.alterables.needs_redraw = true;
|
||||
self.needs_redraw = true;
|
||||
}
|
||||
|
||||
pub fn set_style(&mut self, node_id: taffy::NodeId, style: taffy::Style) {
|
||||
self.alterables.style_set_requests.push((node_id, style));
|
||||
self.style_set_requests.push((node_id, style));
|
||||
}
|
||||
|
||||
pub fn mark_dirty(&mut self, node_id: taffy::NodeId) {
|
||||
self.alterables.dirty_nodes.push(node_id);
|
||||
self.dirty_nodes.push(node_id);
|
||||
}
|
||||
|
||||
pub fn trigger_haptics(&mut self) {
|
||||
self.alterables.trigger_haptics = true;
|
||||
}
|
||||
|
||||
pub fn get_tree(&self) -> &taffy::TaffyTree<WidgetID> {
|
||||
self.refs.tree
|
||||
self.trigger_haptics = true;
|
||||
}
|
||||
|
||||
pub fn animate(&mut self, animation: Animation) {
|
||||
self.alterables.animations.push(animation);
|
||||
self.animations.push(animation);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CallbackDataCommon<'a> {
|
||||
pub refs: &'a EventRefs<'a>,
|
||||
pub alterables: &'a mut EventAlterables,
|
||||
}
|
||||
|
||||
pub struct CallbackData<'a> {
|
||||
pub obj: &'a mut dyn WidgetObj,
|
||||
pub widget_data: &'a mut WidgetData,
|
||||
@@ -234,6 +214,7 @@ impl<U1, U2> EventListener<U1, U2> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct EventListenerVec<U1, U2>(Vec<EventListener<U1, U2>>);
|
||||
|
||||
impl<U1, U2> EventListenerVec<U1, U2> {
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{collections::VecDeque, rc::Rc, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
animation::{self, Animations},
|
||||
animation::Animations,
|
||||
assets::AssetProvider,
|
||||
components::{Component, InitData},
|
||||
event::{self, EventAlterables, EventListenerCollection, EventRefs},
|
||||
transform_stack::{Transform, TransformStack},
|
||||
widget::{self, EventParams, WidgetState, div::Div},
|
||||
transform_stack::Transform,
|
||||
widget::{self, EventParams, WidgetObj, WidgetState, div::Div},
|
||||
};
|
||||
|
||||
use glam::{Vec2, vec2};
|
||||
use parking_lot::{MappedMutexGuard, Mutex, MutexGuard};
|
||||
use slotmap::{HopSlotMap, SecondaryMap, new_key_type};
|
||||
use taffy::{TaffyTree, TraversePartialTree};
|
||||
|
||||
@@ -17,13 +19,52 @@ new_key_type! {
|
||||
}
|
||||
|
||||
pub type BoxWidget = Arc<Mutex<WidgetState>>;
|
||||
pub type WidgetMap = HopSlotMap<WidgetID, BoxWidget>;
|
||||
|
||||
pub struct WidgetMap(HopSlotMap<WidgetID, BoxWidget>);
|
||||
pub type WidgetNodeMap = SecondaryMap<WidgetID, taffy::NodeId>;
|
||||
|
||||
impl WidgetMap {
|
||||
fn new() -> Self {
|
||||
Self(HopSlotMap::with_key())
|
||||
}
|
||||
|
||||
pub fn get_as<T: 'static>(&self, handle: WidgetID) -> Option<MappedMutexGuard<T>> {
|
||||
let widget = self.0.get(handle)?;
|
||||
Some(MutexGuard::map(widget.lock(), |w| w.obj.get_as_mut::<T>()))
|
||||
}
|
||||
|
||||
pub fn get(&self, handle: WidgetID) -> Option<&BoxWidget> {
|
||||
self.0.get(handle)
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, obj: BoxWidget) -> WidgetID {
|
||||
self.0.insert(obj)
|
||||
}
|
||||
|
||||
// cast to specific widget type, does nothing if widget ID is expired
|
||||
// panics in case if the widget type is wrong
|
||||
pub fn call<WIDGET, FUNC>(&self, widget_id: WidgetID, func: FUNC)
|
||||
where
|
||||
WIDGET: WidgetObj,
|
||||
FUNC: FnOnce(&mut WIDGET),
|
||||
{
|
||||
let Some(widget) = self.get(widget_id) else {
|
||||
debug_assert!(false);
|
||||
return;
|
||||
};
|
||||
|
||||
let mut lock = widget.lock();
|
||||
let m = lock.obj.get_as_mut::<WIDGET>();
|
||||
|
||||
func(m);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Layout {
|
||||
pub tree: TaffyTree<WidgetID>,
|
||||
|
||||
pub assets: Box<dyn AssetProvider>,
|
||||
pub components_to_init: VecDeque<Rc<dyn Component>>,
|
||||
|
||||
pub widget_map: WidgetMap,
|
||||
pub widget_node_map: WidgetNodeMap,
|
||||
@@ -82,6 +123,26 @@ impl Layout {
|
||||
)
|
||||
}
|
||||
|
||||
fn process_pending_components(&mut self) -> anyhow::Result<()> {
|
||||
let mut alterables = EventAlterables::default();
|
||||
|
||||
while let Some(c) = self.components_to_init.pop_front() {
|
||||
c.init(&mut InitData {
|
||||
widgets: &self.widget_map,
|
||||
alterables: &mut alterables,
|
||||
tree: &self.tree,
|
||||
});
|
||||
}
|
||||
|
||||
self.process_alterables(alterables)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn defer_component_init(&mut self, component: Rc<dyn Component>) {
|
||||
self.components_to_init.push_back(component);
|
||||
}
|
||||
|
||||
fn push_event_children<U1, U2>(
|
||||
&self,
|
||||
listeners: &EventListenerCollection<U1, U2>,
|
||||
@@ -117,7 +178,7 @@ impl Layout {
|
||||
anyhow::bail!("invalid widget");
|
||||
};
|
||||
|
||||
let mut widget = widget.lock().unwrap();
|
||||
let mut widget = widget.lock();
|
||||
|
||||
let transform = Transform {
|
||||
pos: Vec2::new(l.location.x, l.location.y),
|
||||
@@ -132,8 +193,8 @@ impl Layout {
|
||||
let mut params = EventParams {
|
||||
refs: &EventRefs {
|
||||
tree: &self.tree,
|
||||
widget_map: &self.widget_map,
|
||||
widget_node_map: &self.widget_node_map,
|
||||
widgets: &self.widget_map,
|
||||
nodes: &self.widget_node_map,
|
||||
},
|
||||
layout: l,
|
||||
alterables,
|
||||
@@ -141,20 +202,27 @@ impl Layout {
|
||||
style,
|
||||
};
|
||||
|
||||
if let Some(listeners) = listeners.get(widget_id) {
|
||||
match widget.process_event(widget_id, listeners, node_id, event, user_data, &mut params) {
|
||||
widget::EventResult::Pass => {
|
||||
// go on
|
||||
}
|
||||
widget::EventResult::Consumed => {
|
||||
iter_children = false;
|
||||
}
|
||||
widget::EventResult::Outside => {
|
||||
iter_children = false;
|
||||
}
|
||||
widget::EventResult::Unused => {
|
||||
iter_children = false;
|
||||
}
|
||||
let listeners_vec = listeners.get(widget_id);
|
||||
|
||||
match widget.process_event(
|
||||
widget_id,
|
||||
listeners_vec,
|
||||
node_id,
|
||||
event,
|
||||
user_data,
|
||||
&mut params,
|
||||
) {
|
||||
widget::EventResult::Pass => {
|
||||
// go on
|
||||
}
|
||||
widget::EventResult::Consumed => {
|
||||
iter_children = false;
|
||||
}
|
||||
widget::EventResult::Outside => {
|
||||
iter_children = false;
|
||||
}
|
||||
widget::EventResult::Unused => {
|
||||
iter_children = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,7 +281,7 @@ impl Layout {
|
||||
pub fn new(assets: Box<dyn AssetProvider>) -> anyhow::Result<Self> {
|
||||
let mut tree = TaffyTree::new();
|
||||
let mut widget_node_map = WidgetNodeMap::default();
|
||||
let mut widget_map = HopSlotMap::with_key();
|
||||
let mut widget_map = WidgetMap::new();
|
||||
|
||||
let (root_widget, root_node) = add_child_internal(
|
||||
&mut tree,
|
||||
@@ -239,6 +307,7 @@ impl Layout {
|
||||
haptics_triggered: false,
|
||||
animations: Animations::default(),
|
||||
assets,
|
||||
components_to_init: VecDeque::new(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -247,8 +316,8 @@ impl Layout {
|
||||
|
||||
let refs = EventRefs {
|
||||
tree: &self.tree,
|
||||
widget_map: &self.widget_map,
|
||||
widget_node_map: &self.widget_node_map,
|
||||
widgets: &self.widget_map,
|
||||
nodes: &self.widget_node_map,
|
||||
};
|
||||
|
||||
self
|
||||
@@ -280,10 +349,7 @@ impl Layout {
|
||||
None => taffy::Size::ZERO,
|
||||
Some(h) => {
|
||||
if let Some(w) = self.widget_map.get(*h) {
|
||||
w.lock()
|
||||
.unwrap()
|
||||
.obj
|
||||
.measure(known_dimensions, available_space)
|
||||
w.lock().obj.measure(known_dimensions, available_space)
|
||||
} else {
|
||||
taffy::Size::ZERO
|
||||
}
|
||||
@@ -309,12 +375,13 @@ impl Layout {
|
||||
|
||||
let refs = EventRefs {
|
||||
tree: &self.tree,
|
||||
widget_map: &self.widget_map,
|
||||
widget_node_map: &self.widget_node_map,
|
||||
widgets: &self.widget_map,
|
||||
nodes: &self.widget_node_map,
|
||||
};
|
||||
|
||||
self.animations.tick(&refs, &mut alterables);
|
||||
self.process_alterables(alterables)?;
|
||||
self.process_pending_components()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -53,8 +53,8 @@ impl RendererPass<'_> {
|
||||
self.rect_renderer.render(gfx, viewport, cmd_buf)?;
|
||||
|
||||
{
|
||||
let mut font_system = FONT_SYSTEM.lock().unwrap();
|
||||
let mut swash_cache = SWASH_CACHE.lock().unwrap();
|
||||
let mut font_system = FONT_SYSTEM.lock();
|
||||
let mut swash_cache = SWASH_CACHE.lock();
|
||||
|
||||
self.text_renderer.prepare(
|
||||
&mut font_system,
|
||||
|
||||
@@ -3,11 +3,7 @@ mod shaders;
|
||||
pub mod text_atlas;
|
||||
pub mod text_renderer;
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
rc::Rc,
|
||||
sync::{LazyLock, Mutex},
|
||||
};
|
||||
use std::{cell::RefCell, rc::Rc, sync::LazyLock};
|
||||
|
||||
use cosmic_text::{
|
||||
Align, Attrs, Buffer, Color, FontSystem, Metrics, Style, SwashCache, Weight, Wrap,
|
||||
@@ -15,6 +11,7 @@ use cosmic_text::{
|
||||
use custom_glyph::{ContentType, CustomGlyph};
|
||||
use etagere::AllocId;
|
||||
use glam::Mat4;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use crate::drawing::{self};
|
||||
|
||||
|
||||
@@ -320,7 +320,7 @@ impl WidgetState {
|
||||
pub fn process_event<'a, U1, U2>(
|
||||
&mut self,
|
||||
widget_id: WidgetID,
|
||||
listeners: &EventListenerVec<U1, U2>,
|
||||
listeners: Option<&EventListenerVec<U1, U2>>,
|
||||
node_id: taffy::NodeId,
|
||||
event: &Event,
|
||||
user_data: &mut (&mut U1, &mut U2),
|
||||
@@ -331,52 +331,92 @@ impl WidgetState {
|
||||
match &event {
|
||||
Event::MouseDown(e) => {
|
||||
if hovered && self.data.set_device_pressed(e.device, true) {
|
||||
call_event!(
|
||||
self,
|
||||
listeners,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
MousePress,
|
||||
user_data,
|
||||
CallbackMetadata::MouseButton(event::MouseButton {
|
||||
index: e.index,
|
||||
pos: e.pos
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
Event::MouseUp(e) => {
|
||||
if self.data.set_device_pressed(e.device, false) {
|
||||
call_event!(
|
||||
self,
|
||||
listeners,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
MouseRelease,
|
||||
user_data,
|
||||
CallbackMetadata::MouseButton(event::MouseButton {
|
||||
index: e.index,
|
||||
pos: e.pos,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
Event::MouseMotion(e) => {
|
||||
if self.data.set_device_hovered(e.device, hovered) {
|
||||
if self.data.is_hovered() {
|
||||
if let Some(listeners) = &listeners {
|
||||
call_event!(
|
||||
self,
|
||||
listeners,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
MouseEnter,
|
||||
MousePress,
|
||||
user_data,
|
||||
CallbackMetadata::None
|
||||
CallbackMetadata::MouseButton(event::MouseButton {
|
||||
index: e.index,
|
||||
pos: e.pos
|
||||
})
|
||||
);
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
Event::MouseUp(e) => {
|
||||
if self.data.set_device_pressed(e.device, false) {
|
||||
if let Some(listeners) = listeners {
|
||||
call_event!(
|
||||
self,
|
||||
listeners,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
MouseRelease,
|
||||
user_data,
|
||||
CallbackMetadata::MouseButton(event::MouseButton {
|
||||
index: e.index,
|
||||
pos: e.pos,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Event::MouseMotion(e) => {
|
||||
let hover_state_changed = self.data.set_device_hovered(e.device, hovered);
|
||||
|
||||
if let Some(listeners) = &listeners {
|
||||
if hover_state_changed {
|
||||
if self.data.is_hovered() {
|
||||
call_event!(
|
||||
self,
|
||||
listeners,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
MouseEnter,
|
||||
user_data,
|
||||
CallbackMetadata::None
|
||||
);
|
||||
} else {
|
||||
call_event!(
|
||||
self,
|
||||
listeners,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
MouseLeave,
|
||||
user_data,
|
||||
CallbackMetadata::None
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
call_event!(
|
||||
self,
|
||||
listeners,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
MouseMotion,
|
||||
user_data,
|
||||
CallbackMetadata::MousePosition(event::MousePosition { pos: e.pos })
|
||||
);
|
||||
}
|
||||
}
|
||||
Event::MouseWheel(e) => {
|
||||
if hovered && self.process_wheel(params, e) {
|
||||
return EventResult::Consumed;
|
||||
}
|
||||
}
|
||||
Event::MouseLeave(e) => {
|
||||
if self.data.set_device_hovered(e.device, false) {
|
||||
if let Some(listeners) = &listeners {
|
||||
call_event!(
|
||||
self,
|
||||
listeners,
|
||||
@@ -389,49 +429,21 @@ impl WidgetState {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
call_event!(
|
||||
self,
|
||||
listeners,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
MouseMotion,
|
||||
user_data,
|
||||
CallbackMetadata::MousePosition(event::MousePosition { pos: e.pos })
|
||||
);
|
||||
}
|
||||
Event::MouseWheel(e) => {
|
||||
if hovered && self.process_wheel(params, e) {
|
||||
return EventResult::Consumed;
|
||||
}
|
||||
}
|
||||
Event::MouseLeave(e) => {
|
||||
if self.data.set_device_hovered(e.device, false) {
|
||||
Event::InternalStateChange(e) => {
|
||||
if let Some(listeners) = &listeners {
|
||||
call_event!(
|
||||
self,
|
||||
listeners,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
MouseLeave,
|
||||
InternalStateChange,
|
||||
user_data,
|
||||
CallbackMetadata::None
|
||||
CallbackMetadata::Custom(e.metadata)
|
||||
);
|
||||
}
|
||||
}
|
||||
Event::InternalStateChange(e) => {
|
||||
call_event!(
|
||||
self,
|
||||
listeners,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
InternalStateChange,
|
||||
user_data,
|
||||
CallbackMetadata::Custom(e.metadata)
|
||||
);
|
||||
}
|
||||
}
|
||||
EventResult::Pass
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ impl WidgetObj for SpriteBox {
|
||||
let mut buffer = Buffer::new_empty(DEFAULT_METRICS);
|
||||
|
||||
{
|
||||
let mut font_system = FONT_SYSTEM.lock().unwrap(); // safe unwrap
|
||||
let mut font_system = FONT_SYSTEM.lock();
|
||||
let mut buffer = buffer.borrow_with(&mut font_system);
|
||||
let attrs = Attrs::new()
|
||||
.color(Color::rgb(255, 0, 255))
|
||||
|
||||
@@ -30,7 +30,7 @@ impl TextLabel {
|
||||
|
||||
let mut buffer = Buffer::new_empty(metrics);
|
||||
{
|
||||
let mut font_system = FONT_SYSTEM.lock().unwrap(); // safe unwrap
|
||||
let mut font_system = FONT_SYSTEM.lock();
|
||||
let mut buffer = buffer.borrow_with(&mut font_system);
|
||||
buffer.set_wrap(wrap);
|
||||
|
||||
@@ -56,7 +56,7 @@ impl TextLabel {
|
||||
|
||||
self.params.content = String::from(text);
|
||||
let attrs = Attrs::from(&self.params.style);
|
||||
let mut font_system = FONT_SYSTEM.lock().unwrap(); // safe unwrap
|
||||
let mut font_system = FONT_SYSTEM.lock();
|
||||
|
||||
let mut buffer = self.buffer.borrow_mut();
|
||||
buffer.set_rich_text(
|
||||
@@ -79,7 +79,7 @@ impl WidgetObj for TextLabel {
|
||||
|
||||
if self.last_boundary != boundary {
|
||||
self.last_boundary = boundary;
|
||||
let mut font_system = FONT_SYSTEM.lock().unwrap(); // safe unwrap
|
||||
let mut font_system = FONT_SYSTEM.lock();
|
||||
let mut buffer = self.buffer.borrow_mut();
|
||||
buffer.set_size(
|
||||
&mut font_system,
|
||||
@@ -108,7 +108,7 @@ impl WidgetObj for TextLabel {
|
||||
AvailableSpace::Definite(width) => Some(width),
|
||||
});
|
||||
|
||||
let mut font_system = FONT_SYSTEM.lock().unwrap(); // safe unwrap
|
||||
let mut font_system = FONT_SYSTEM.lock();
|
||||
let mut buffer = self.buffer.borrow_mut();
|
||||
|
||||
buffer.set_size(&mut font_system, width_constraint, None);
|
||||
|
||||
Reference in New Issue
Block a user