wgui: components refactoring, id handles
This commit is contained in:
@@ -10,7 +10,6 @@
|
|||||||
<div flex_direction="column" padding="16">
|
<div flex_direction="column" padding="16">
|
||||||
<label weight="bold" text="Try these environment variables:" />
|
<label weight="bold" text="Try these environment variables:" />
|
||||||
<label text="TESTBED=bar" />
|
<label text="TESTBED=bar" />
|
||||||
<label text="TESTBED=various_widgets" />
|
|
||||||
<label text="TESTBED=watch" />
|
<label text="TESTBED=watch" />
|
||||||
<label text="TESTBED=dashboard" />
|
<label text="TESTBED=dashboard" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,9 +8,12 @@
|
|||||||
<label text="Raw text" color="#FFFFFF" />
|
<label text="Raw text" color="#FFFFFF" />
|
||||||
<label translation="TESTBED.HELLO_WORLD" color="#FFFFFF" />
|
<label translation="TESTBED.HELLO_WORLD" color="#FFFFFF" />
|
||||||
|
|
||||||
<button text="Red button" width="128" height="32" color="#FF0000" />
|
|
||||||
<button text="Aqua button" width="128" height="32" color="#00FFFF" />
|
<label id="label_current_option" />
|
||||||
<button text="Yellow button" width="128" height="32" color="#FFFF00" />
|
|
||||||
|
<button margin_left="16" id="button_red" text="Red button" width="128" height="32" color="#FF0000" />
|
||||||
|
<button margin_left="16" id="button_aqua" text="Aqua button" width="128" height="32" color="#00FFFF" />
|
||||||
|
<button margin_left="16" id="button_yellow" text="Yellow button" width="128" height="32" color="#FFFF00" />
|
||||||
|
|
||||||
<div flex_direction="row" gap="16">
|
<div flex_direction="row" gap="16">
|
||||||
<div flex_direction="column" gap="8">
|
<div flex_direction="column" gap="8">
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
use crate::{assets, testbed::Testbed};
|
use crate::{assets, testbed::Testbed};
|
||||||
use glam::Vec2;
|
use glam::Vec2;
|
||||||
use wgui::{
|
use wgui::{
|
||||||
event::EventListenerCollection, globals::WguiGlobals, layout::Layout, parser::ParserState,
|
components::button::ComponentButton, event::EventListenerCollection, globals::WguiGlobals,
|
||||||
|
i18n::Translation, layout::Layout, parser::ParserState,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct TestbedGeneric {
|
pub struct TestbedGeneric {
|
||||||
@@ -13,13 +14,23 @@ pub struct TestbedGeneric {
|
|||||||
|
|
||||||
impl TestbedGeneric {
|
impl TestbedGeneric {
|
||||||
pub fn new(listeners: &mut EventListenerCollection<(), ()>) -> anyhow::Result<Self> {
|
pub fn new(listeners: &mut EventListenerCollection<(), ()>) -> anyhow::Result<Self> {
|
||||||
const XML_PATH: &str = "gui/testbed.xml";
|
const XML_PATH: &str = "gui/various_widgets.xml";
|
||||||
|
|
||||||
let globals = WguiGlobals::new(Box::new(assets::Asset {}))?;
|
let globals = WguiGlobals::new(Box::new(assets::Asset {}))?;
|
||||||
|
|
||||||
let (layout, state) =
|
let (mut layout, state) =
|
||||||
wgui::parser::new_layout_from_assets(globals, listeners, XML_PATH, false)?;
|
wgui::parser::new_layout_from_assets(globals, listeners, XML_PATH, false)?;
|
||||||
|
|
||||||
|
let label_current_option = state.fetch_widget("label_current_option")?;
|
||||||
|
let b1 = state.fetch_component_as::<ComponentButton>("button_red")?;
|
||||||
|
let b2 = state.fetch_component_as::<ComponentButton>("button_aqua")?;
|
||||||
|
let b3 = state.fetch_component_as::<ComponentButton>("button_yellow")?;
|
||||||
|
|
||||||
|
b1.set_text(
|
||||||
|
&mut layout.state,
|
||||||
|
Translation::from_raw_text("hello, world!"),
|
||||||
|
);
|
||||||
|
|
||||||
Ok(Self { layout, state })
|
Ok(Self { layout, state })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
use std::rc::Rc;
|
use std::{cell::RefCell, rc::Rc};
|
||||||
use taffy::{AlignItems, JustifyContent, prelude::length};
|
use taffy::{AlignItems, JustifyContent, prelude::length};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
animation::{Animation, AnimationEasing},
|
animation::{Animation, AnimationEasing},
|
||||||
components::{Component, InitData},
|
components::{Component, InitData},
|
||||||
drawing::{self, Color},
|
drawing::{self, Color},
|
||||||
event::{CallbackDataCommon, EventListenerCollection, EventListenerKind, ListenerHandleVec},
|
event::{EventAlterables, EventListenerCollection, EventListenerKind, ListenerHandleVec},
|
||||||
i18n::Translation,
|
i18n::Translation,
|
||||||
layout::{Layout, WidgetID},
|
layout::{Layout, LayoutState, WidgetID},
|
||||||
renderer_vk::text::{FontWeight, TextStyle},
|
renderer_vk::text::{FontWeight, TextStyle},
|
||||||
widget::{
|
widget::{
|
||||||
rectangle::{Rectangle, RectangleParams},
|
rectangle::{Rectangle, RectangleParams},
|
||||||
@@ -38,35 +38,44 @@ impl Default for Params {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
hovered: bool,
|
||||||
|
down: bool,
|
||||||
|
}
|
||||||
|
|
||||||
struct Data {
|
struct Data {
|
||||||
initial_color: drawing::Color,
|
initial_color: drawing::Color,
|
||||||
initial_border_color: drawing::Color,
|
initial_border_color: drawing::Color,
|
||||||
text_id: WidgetID, // Text
|
text_id: WidgetID, // Text
|
||||||
|
rect_id: WidgetID, // Rectangle
|
||||||
text_node: taffy::NodeId,
|
text_node: taffy::NodeId,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Button {
|
pub struct ComponentButton {
|
||||||
data: Rc<Data>,
|
data: Rc<Data>,
|
||||||
|
state: Rc<RefCell<State>>,
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
listener_handles: ListenerHandleVec,
|
listener_handles: ListenerHandleVec,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Button {
|
impl Component for ComponentButton {
|
||||||
fn init(&self, _data: &mut InitData) {}
|
fn init(&self, _data: &mut InitData) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Button {
|
impl ComponentButton {
|
||||||
pub fn set_text<C>(&self, common: &mut CallbackDataCommon, text: Translation) {
|
pub fn set_text(&self, state: &mut LayoutState, text: Translation) {
|
||||||
let globals = common.state.globals.clone();
|
let globals = state.globals.clone();
|
||||||
|
|
||||||
common
|
state
|
||||||
.state
|
|
||||||
.widgets
|
.widgets
|
||||||
.call(self.data.text_id, |label: &mut TextLabel| {
|
.call(self.data.text_id, |label: &mut TextLabel| {
|
||||||
label.set_text(&mut globals.i18n(), text);
|
label.set_text(&mut globals.i18n(), text);
|
||||||
});
|
});
|
||||||
common.alterables.mark_redraw();
|
|
||||||
common.alterables.mark_dirty(self.data.text_node);
|
let mut alterables = EventAlterables::default();
|
||||||
|
alterables.mark_redraw();
|
||||||
|
alterables.mark_dirty(self.data.text_node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,12 +117,98 @@ fn anim_hover_out(data: Rc<Data>, widget_id: WidgetID) -> Animation {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn register_event_mouse_enter<U1, U2>(
|
||||||
|
data: Rc<Data>,
|
||||||
|
state: Rc<RefCell<State>>,
|
||||||
|
listeners: &mut EventListenerCollection<U1, U2>,
|
||||||
|
listener_handles: &mut ListenerHandleVec,
|
||||||
|
) {
|
||||||
|
listeners.register(
|
||||||
|
listener_handles,
|
||||||
|
data.rect_id,
|
||||||
|
EventListenerKind::MouseEnter,
|
||||||
|
Box::new(move |common, event_data, _, _| {
|
||||||
|
common.alterables.trigger_haptics();
|
||||||
|
common
|
||||||
|
.alterables
|
||||||
|
.animate(anim_hover_in(data.clone(), event_data.widget_id));
|
||||||
|
state.borrow_mut().hovered = true;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_event_mouse_leave<U1, U2>(
|
||||||
|
data: Rc<Data>,
|
||||||
|
state: Rc<RefCell<State>>,
|
||||||
|
listeners: &mut EventListenerCollection<U1, U2>,
|
||||||
|
listener_handles: &mut ListenerHandleVec,
|
||||||
|
) {
|
||||||
|
listeners.register(
|
||||||
|
listener_handles,
|
||||||
|
data.rect_id,
|
||||||
|
EventListenerKind::MouseLeave,
|
||||||
|
Box::new(move |common, event_data, _, _| {
|
||||||
|
common.alterables.trigger_haptics();
|
||||||
|
common
|
||||||
|
.alterables
|
||||||
|
.animate(anim_hover_out(data.clone(), event_data.widget_id));
|
||||||
|
state.borrow_mut().hovered = false;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_event_mouse_press<U1, U2>(
|
||||||
|
data: Rc<Data>,
|
||||||
|
state: Rc<RefCell<State>>,
|
||||||
|
listeners: &mut EventListenerCollection<U1, U2>,
|
||||||
|
listener_handles: &mut ListenerHandleVec,
|
||||||
|
) {
|
||||||
|
listeners.register(
|
||||||
|
listener_handles,
|
||||||
|
data.rect_id,
|
||||||
|
EventListenerKind::MousePress,
|
||||||
|
Box::new(move |common, event_data, _, _| {
|
||||||
|
common.alterables.trigger_haptics();
|
||||||
|
let mut state = state.borrow_mut();
|
||||||
|
|
||||||
|
if state.hovered {
|
||||||
|
state.down = true;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_event_mouse_release<U1, U2>(
|
||||||
|
data: Rc<Data>,
|
||||||
|
state: Rc<RefCell<State>>,
|
||||||
|
listeners: &mut EventListenerCollection<U1, U2>,
|
||||||
|
listener_handles: &mut ListenerHandleVec,
|
||||||
|
) {
|
||||||
|
listeners.register(
|
||||||
|
listener_handles,
|
||||||
|
data.rect_id,
|
||||||
|
EventListenerKind::MouseRelease,
|
||||||
|
Box::new(move |common, _data, _, _| {
|
||||||
|
common.alterables.trigger_haptics();
|
||||||
|
|
||||||
|
let mut state = state.borrow_mut();
|
||||||
|
if state.down {
|
||||||
|
state.down = false;
|
||||||
|
|
||||||
|
if state.hovered {
|
||||||
|
//TODO: click event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn construct<U1, U2>(
|
pub fn construct<U1, U2>(
|
||||||
layout: &mut Layout,
|
layout: &mut Layout,
|
||||||
listeners: &mut EventListenerCollection<U1, U2>,
|
listeners: &mut EventListenerCollection<U1, U2>,
|
||||||
parent: WidgetID,
|
parent: WidgetID,
|
||||||
params: Params,
|
params: Params,
|
||||||
) -> anyhow::Result<Rc<Button>> {
|
) -> anyhow::Result<Rc<ComponentButton>> {
|
||||||
let mut style = params.style;
|
let mut style = params.style;
|
||||||
|
|
||||||
// force-override style
|
// force-override style
|
||||||
@@ -162,42 +257,30 @@ pub fn construct<U1, U2>(
|
|||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let _data = Rc::new(Data {
|
let data = Rc::new(Data {
|
||||||
text_id,
|
text_id,
|
||||||
|
rect_id,
|
||||||
text_node,
|
text_node,
|
||||||
initial_color: params.color,
|
initial_color: params.color,
|
||||||
initial_border_color: params.border_color,
|
initial_border_color: params.border_color,
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut listener_handles = ListenerHandleVec::default();
|
let state = Rc::new(RefCell::new(State {
|
||||||
|
down: false,
|
||||||
|
hovered: false,
|
||||||
|
}));
|
||||||
|
|
||||||
let data = _data.clone();
|
let mut lhandles = ListenerHandleVec::default();
|
||||||
listeners.register(
|
|
||||||
&mut listener_handles,
|
|
||||||
rect_id,
|
|
||||||
EventListenerKind::MouseEnter,
|
|
||||||
Box::new(move |common, event_data, _, _| {
|
|
||||||
common
|
|
||||||
.alterables
|
|
||||||
.animate(anim_hover_in(data.clone(), event_data.widget_id));
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
let data = _data.clone();
|
register_event_mouse_enter(data.clone(), state.clone(), listeners, &mut lhandles);
|
||||||
listeners.register(
|
register_event_mouse_leave(data.clone(), state.clone(), listeners, &mut lhandles);
|
||||||
&mut listener_handles,
|
register_event_mouse_press(data.clone(), state.clone(), listeners, &mut lhandles);
|
||||||
rect_id,
|
register_event_mouse_release(data.clone(), state.clone(), listeners, &mut lhandles);
|
||||||
EventListenerKind::MouseLeave,
|
|
||||||
Box::new(move |common, event_data, _, _| {
|
|
||||||
common
|
|
||||||
.alterables
|
|
||||||
.animate(anim_hover_out(data.clone(), event_data.widget_id));
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
let button = Rc::new(Button {
|
let button = Rc::new(ComponentButton {
|
||||||
data: _data.clone(),
|
data,
|
||||||
listener_handles,
|
state,
|
||||||
|
listener_handles: lhandles,
|
||||||
});
|
});
|
||||||
|
|
||||||
layout.defer_component_init(button.clone());
|
layout.defer_component_init(button.clone());
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ pub struct Params {
|
|||||||
pub values: ValuesMinMax,
|
pub values: ValuesMinMax,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SliderState {
|
struct State {
|
||||||
dragging: bool,
|
dragging: bool,
|
||||||
hovered: bool,
|
hovered: bool,
|
||||||
values: ValuesMinMax,
|
values: ValuesMinMax,
|
||||||
@@ -62,15 +62,15 @@ struct Data {
|
|||||||
slider_body_node: taffy::NodeId,
|
slider_body_node: taffy::NodeId,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Slider {
|
pub struct ComponentSlider {
|
||||||
data: Rc<Data>,
|
data: Rc<Data>,
|
||||||
state: Rc<RefCell<SliderState>>,
|
state: Rc<RefCell<State>>,
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
listener_handles: ListenerHandleVec,
|
listener_handles: ListenerHandleVec,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Slider {
|
impl Component for ComponentSlider {
|
||||||
fn init(&self, init_data: &mut InitData) {
|
fn init(&self, init_data: &mut InitData) {
|
||||||
let mut state = self.state.borrow_mut();
|
let mut state = self.state.borrow_mut();
|
||||||
let value = state.values.value;
|
let value = state.values.value;
|
||||||
@@ -106,7 +106,7 @@ const PAD_PERCENT: f32 = 0.75;
|
|||||||
const HANDLE_WIDTH: f32 = 32.0;
|
const HANDLE_WIDTH: f32 = 32.0;
|
||||||
const HANDLE_HEIGHT: f32 = 24.0;
|
const HANDLE_HEIGHT: f32 = 24.0;
|
||||||
|
|
||||||
impl SliderState {
|
impl State {
|
||||||
fn update_value_to_mouse(
|
fn update_value_to_mouse(
|
||||||
&mut self,
|
&mut self,
|
||||||
event_data: &event::CallbackData<'_>,
|
event_data: &event::CallbackData<'_>,
|
||||||
@@ -210,7 +210,7 @@ fn on_leave_anim(common: &mut event::CallbackDataCommon, handle_id: WidgetID) {
|
|||||||
|
|
||||||
fn register_event_mouse_enter<U1, U2>(
|
fn register_event_mouse_enter<U1, U2>(
|
||||||
data: Rc<Data>,
|
data: Rc<Data>,
|
||||||
state: Rc<RefCell<SliderState>>,
|
state: Rc<RefCell<State>>,
|
||||||
listeners: &mut EventListenerCollection<U1, U2>,
|
listeners: &mut EventListenerCollection<U1, U2>,
|
||||||
listener_handles: &mut ListenerHandleVec,
|
listener_handles: &mut ListenerHandleVec,
|
||||||
) {
|
) {
|
||||||
@@ -228,7 +228,7 @@ fn register_event_mouse_enter<U1, U2>(
|
|||||||
|
|
||||||
fn register_event_mouse_leave<U1, U2>(
|
fn register_event_mouse_leave<U1, U2>(
|
||||||
data: Rc<Data>,
|
data: Rc<Data>,
|
||||||
state: Rc<RefCell<SliderState>>,
|
state: Rc<RefCell<State>>,
|
||||||
listeners: &mut EventListenerCollection<U1, U2>,
|
listeners: &mut EventListenerCollection<U1, U2>,
|
||||||
listener_handles: &mut ListenerHandleVec,
|
listener_handles: &mut ListenerHandleVec,
|
||||||
) {
|
) {
|
||||||
@@ -246,7 +246,7 @@ fn register_event_mouse_leave<U1, U2>(
|
|||||||
|
|
||||||
fn register_event_mouse_motion<U1, U2>(
|
fn register_event_mouse_motion<U1, U2>(
|
||||||
data: Rc<Data>,
|
data: Rc<Data>,
|
||||||
state: Rc<RefCell<SliderState>>,
|
state: Rc<RefCell<State>>,
|
||||||
listeners: &mut EventListenerCollection<U1, U2>,
|
listeners: &mut EventListenerCollection<U1, U2>,
|
||||||
listener_handles: &mut ListenerHandleVec,
|
listener_handles: &mut ListenerHandleVec,
|
||||||
) {
|
) {
|
||||||
@@ -266,7 +266,7 @@ fn register_event_mouse_motion<U1, U2>(
|
|||||||
|
|
||||||
fn register_event_mouse_press<U1, U2>(
|
fn register_event_mouse_press<U1, U2>(
|
||||||
data: Rc<Data>,
|
data: Rc<Data>,
|
||||||
state: Rc<RefCell<SliderState>>,
|
state: Rc<RefCell<State>>,
|
||||||
listeners: &mut EventListenerCollection<U1, U2>,
|
listeners: &mut EventListenerCollection<U1, U2>,
|
||||||
listener_handles: &mut ListenerHandleVec,
|
listener_handles: &mut ListenerHandleVec,
|
||||||
) {
|
) {
|
||||||
@@ -288,7 +288,7 @@ fn register_event_mouse_press<U1, U2>(
|
|||||||
|
|
||||||
fn register_event_mouse_release<U1, U2>(
|
fn register_event_mouse_release<U1, U2>(
|
||||||
data: Rc<Data>,
|
data: Rc<Data>,
|
||||||
state: Rc<RefCell<SliderState>>,
|
state: Rc<RefCell<State>>,
|
||||||
listeners: &mut EventListenerCollection<U1, U2>,
|
listeners: &mut EventListenerCollection<U1, U2>,
|
||||||
listener_handles: &mut ListenerHandleVec,
|
listener_handles: &mut ListenerHandleVec,
|
||||||
) {
|
) {
|
||||||
@@ -312,7 +312,7 @@ pub fn construct<U1, U2>(
|
|||||||
listeners: &mut EventListenerCollection<U1, U2>,
|
listeners: &mut EventListenerCollection<U1, U2>,
|
||||||
parent: WidgetID,
|
parent: WidgetID,
|
||||||
params: Params,
|
params: Params,
|
||||||
) -> anyhow::Result<Rc<Slider>> {
|
) -> anyhow::Result<Rc<ComponentSlider>> {
|
||||||
let mut style = params.style;
|
let mut style = params.style;
|
||||||
style.position = taffy::Position::Relative;
|
style.position = taffy::Position::Relative;
|
||||||
style.min_size = style.size;
|
style.min_size = style.size;
|
||||||
@@ -382,7 +382,7 @@ pub fn construct<U1, U2>(
|
|||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let state = SliderState {
|
let state = State {
|
||||||
dragging: false,
|
dragging: false,
|
||||||
hovered: false,
|
hovered: false,
|
||||||
values: params.values,
|
values: params.values,
|
||||||
@@ -426,7 +426,7 @@ pub fn construct<U1, U2>(
|
|||||||
register_event_mouse_leave(data.clone(), state.clone(), listeners, &mut lhandles);
|
register_event_mouse_leave(data.clone(), state.clone(), listeners, &mut lhandles);
|
||||||
register_event_mouse_release(data.clone(), state.clone(), listeners, &mut lhandles);
|
register_event_mouse_release(data.clone(), state.clone(), listeners, &mut lhandles);
|
||||||
|
|
||||||
let slider = Rc::new(Slider {
|
let slider = Rc::new(ComponentSlider {
|
||||||
data,
|
data,
|
||||||
state,
|
state,
|
||||||
listener_handles: lhandles,
|
listener_handles: lhandles,
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ pub struct LayoutState {
|
|||||||
pub widgets: WidgetMap,
|
pub widgets: WidgetMap,
|
||||||
pub nodes: WidgetNodeMap,
|
pub nodes: WidgetNodeMap,
|
||||||
pub tree: taffy::tree::TaffyTree<WidgetID>,
|
pub tree: taffy::tree::TaffyTree<WidgetID>,
|
||||||
|
pub alterables: EventAlterables,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Layout {
|
pub struct Layout {
|
||||||
@@ -282,6 +283,7 @@ impl Layout {
|
|||||||
widgets: WidgetMap::new(),
|
widgets: WidgetMap::new(),
|
||||||
nodes: WidgetNodeMap::default(),
|
nodes: WidgetNodeMap::default(),
|
||||||
globals,
|
globals,
|
||||||
|
alterables: EventAlterables::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (root_widget, root_node) = add_child_internal(
|
let (root_widget, root_node) = add_child_internal(
|
||||||
@@ -364,10 +366,11 @@ impl Layout {
|
|||||||
|
|
||||||
pub fn tick(&mut self) -> anyhow::Result<()> {
|
pub fn tick(&mut self) -> anyhow::Result<()> {
|
||||||
let mut alterables = EventAlterables::default();
|
let mut alterables = EventAlterables::default();
|
||||||
|
|
||||||
self.animations.tick(&self.state, &mut alterables);
|
self.animations.tick(&self.state, &mut alterables);
|
||||||
self.process_alterables(alterables)?;
|
|
||||||
self.process_pending_components()?;
|
self.process_pending_components()?;
|
||||||
|
self.process_alterables(alterables)?;
|
||||||
|
let state_alterables = std::mem::take(&mut self.state.alterables);
|
||||||
|
self.process_alterables(state_alterables)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use crate::{
|
|||||||
i18n::Translation,
|
i18n::Translation,
|
||||||
layout::WidgetID,
|
layout::WidgetID,
|
||||||
parser::{
|
parser::{
|
||||||
ParserContext, ParserFile, iter_attribs,
|
ParserContext, ParserFile, iter_attribs, process_component,
|
||||||
style::{parse_color, parse_color_opt, parse_round, parse_style, parse_text_style},
|
style::{parse_color, parse_color_opt, parse_round, parse_style, parse_text_style},
|
||||||
},
|
},
|
||||||
widget::util::WLength,
|
widget::util::WLength,
|
||||||
@@ -55,7 +55,7 @@ pub fn parse_component_button<'a, U1, U2>(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.components.push(button::construct(
|
let component = button::construct(
|
||||||
ctx.layout,
|
ctx.layout,
|
||||||
ctx.listeners,
|
ctx.listeners,
|
||||||
parent_id,
|
parent_id,
|
||||||
@@ -67,7 +67,9 @@ pub fn parse_component_button<'a, U1, U2>(
|
|||||||
text_style,
|
text_style,
|
||||||
round,
|
round,
|
||||||
},
|
},
|
||||||
)?);
|
)?;
|
||||||
|
|
||||||
|
process_component(file, ctx, node, component)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
components::slider,
|
components::slider,
|
||||||
layout::WidgetID,
|
layout::WidgetID,
|
||||||
parser::{ParserContext, ParserFile, iter_attribs, parse_check_f32, style::parse_style},
|
parser::{
|
||||||
|
ParserContext, ParserFile, iter_attribs, parse_check_f32, process_component, style::parse_style,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parse_component_slider<'a, U1, U2>(
|
pub fn parse_component_slider<'a, U1, U2>(
|
||||||
@@ -32,7 +34,7 @@ pub fn parse_component_slider<'a, U1, U2>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.components.push(slider::construct(
|
let component = slider::construct(
|
||||||
ctx.layout,
|
ctx.layout,
|
||||||
ctx.listeners,
|
ctx.listeners,
|
||||||
parent_id,
|
parent_id,
|
||||||
@@ -44,7 +46,9 @@ pub fn parse_component_slider<'a, U1, U2>(
|
|||||||
value: initial_value,
|
value: initial_value,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)?);
|
)?;
|
||||||
|
|
||||||
|
process_component(file, ctx, node, component)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ mod widget_rectangle;
|
|||||||
mod widget_sprite;
|
mod widget_sprite;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
any::AnyTrait,
|
||||||
assets::AssetProvider,
|
assets::AssetProvider,
|
||||||
components::Component,
|
components::Component,
|
||||||
drawing::{self},
|
drawing::{self},
|
||||||
@@ -56,12 +57,36 @@ pub struct ParserState {
|
|||||||
macro_attribs: HashMap<Rc<str>, MacroAttribs>,
|
macro_attribs: HashMap<Rc<str>, MacroAttribs>,
|
||||||
pub var_map: HashMap<Rc<str>, Rc<str>>,
|
pub var_map: HashMap<Rc<str>, Rc<str>>,
|
||||||
pub components: Vec<Rc<dyn Component>>,
|
pub components: Vec<Rc<dyn Component>>,
|
||||||
|
pub components_id_map: HashMap<Rc<str>, std::rc::Weak<dyn Component>>,
|
||||||
pub templates: HashMap<Rc<str>, Rc<Template>>,
|
pub templates: HashMap<Rc<str>, Rc<Template>>,
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParserState {
|
impl ParserState {
|
||||||
pub fn require_by_id(&self, id: &str) -> anyhow::Result<WidgetID> {
|
pub fn fetch_component(&self, id: &str) -> anyhow::Result<Rc<dyn Component>> {
|
||||||
|
let Some(weak) = self.components_id_map.get(id) else {
|
||||||
|
anyhow::bail!("Component by ID \"{}\" doesn't exist", id);
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(component) = weak.upgrade() else {
|
||||||
|
anyhow::bail!("Component by ID \"{}\" doesn't exist", id);
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(component)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fetch_component_as<T: 'static>(&self, id: &str) -> anyhow::Result<Rc<T>> {
|
||||||
|
let component = self.fetch_component(id)?;
|
||||||
|
|
||||||
|
// FIXME: check T type id
|
||||||
|
log::warn!("fetch_component_as WIP");
|
||||||
|
unsafe {
|
||||||
|
let raw = Rc::into_raw(component);
|
||||||
|
Ok(Rc::from_raw(raw as _))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fetch_widget(&self, id: &str) -> anyhow::Result<WidgetID> {
|
||||||
match self.ids.get(id) {
|
match self.ids.get(id) {
|
||||||
Some(id) => Ok(*id),
|
Some(id) => Ok(*id),
|
||||||
None => anyhow::bail!("Widget by ID \"{}\" doesn't exist", id),
|
None => anyhow::bail!("Widget by ID \"{}\" doesn't exist", id),
|
||||||
@@ -88,6 +113,7 @@ impl ParserState {
|
|||||||
macro_attribs: self.macro_attribs.clone(), // FIXME: prevent copying
|
macro_attribs: self.macro_attribs.clone(), // FIXME: prevent copying
|
||||||
var_map: self.var_map.clone(), // FIXME: prevent copying
|
var_map: self.var_map.clone(), // FIXME: prevent copying
|
||||||
components: self.components.clone(), // FIXME: prevent copying
|
components: self.components.clone(), // FIXME: prevent copying
|
||||||
|
components_id_map: self.components_id_map.clone(), // FIXME: prevent copying
|
||||||
templates: Default::default(),
|
templates: Default::default(),
|
||||||
dev_mode,
|
dev_mode,
|
||||||
};
|
};
|
||||||
@@ -128,6 +154,7 @@ struct ParserContext<'a, U1, U2> {
|
|||||||
ids: HashMap<Rc<str>, WidgetID>,
|
ids: HashMap<Rc<str>, WidgetID>,
|
||||||
templates: HashMap<Rc<str>, Rc<Template>>,
|
templates: HashMap<Rc<str>, Rc<Template>>,
|
||||||
components: Vec<Rc<dyn Component>>,
|
components: Vec<Rc<dyn Component>>,
|
||||||
|
components_id_map: HashMap<Rc<str>, std::rc::Weak<dyn Component>>,
|
||||||
dev_mode: bool,
|
dev_mode: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,7 +557,35 @@ fn parse_tag_macro<U1, U2>(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_universal<'a, U1, U2>(
|
fn process_component<'a, U1, U2>(
|
||||||
|
file: &'a ParserFile,
|
||||||
|
ctx: &mut ParserContext<U1, U2>,
|
||||||
|
node: roxmltree::Node<'a, 'a>,
|
||||||
|
component: Rc<dyn Component>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
let attribs: Vec<_> = iter_attribs(file, ctx, &node, false).collect();
|
||||||
|
|
||||||
|
for (key, value) in attribs {
|
||||||
|
#[allow(clippy::single_match)]
|
||||||
|
match key.as_ref() {
|
||||||
|
"id" => {
|
||||||
|
if ctx
|
||||||
|
.components_id_map
|
||||||
|
.insert(value.clone(), Rc::downgrade(&component))
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
log::warn!("duplicate component ID \"{value}\" in the same layout file!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.components.push(component);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_widget_universal<'a, U1, U2>(
|
||||||
file: &'a ParserFile,
|
file: &'a ParserFile,
|
||||||
ctx: &mut ParserContext<U1, U2>,
|
ctx: &mut ParserContext<U1, U2>,
|
||||||
node: roxmltree::Node<'a, 'a>,
|
node: roxmltree::Node<'a, 'a>,
|
||||||
@@ -544,7 +599,7 @@ fn parse_universal<'a, U1, U2>(
|
|||||||
"id" => {
|
"id" => {
|
||||||
// Attach a specific widget to name-ID map (just like getElementById)
|
// Attach a specific widget to name-ID map (just like getElementById)
|
||||||
if ctx.ids.insert(value.clone(), widget_id).is_some() {
|
if ctx.ids.insert(value.clone(), widget_id).is_some() {
|
||||||
log::warn!("duplicate ID \"{value}\" in the same layout file!");
|
log::warn!("duplicate widget ID \"{value}\" in the same layout file!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -619,6 +674,7 @@ fn create_default_context<'a, U1, U2>(
|
|||||||
templates: Default::default(),
|
templates: Default::default(),
|
||||||
macro_attribs: Default::default(),
|
macro_attribs: Default::default(),
|
||||||
components: Default::default(),
|
components: Default::default(),
|
||||||
|
components_id_map: Default::default(),
|
||||||
dev_mode,
|
dev_mode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -644,6 +700,7 @@ pub fn parse_from_assets<U1, U2>(
|
|||||||
macro_attribs: std::mem::take(&mut ctx.macro_attribs),
|
macro_attribs: std::mem::take(&mut ctx.macro_attribs),
|
||||||
var_map: std::mem::take(&mut ctx.var_map),
|
var_map: std::mem::take(&mut ctx.var_map),
|
||||||
components: std::mem::take(&mut ctx.components),
|
components: std::mem::take(&mut ctx.components),
|
||||||
|
components_id_map: std::mem::take(&mut ctx.components_id_map),
|
||||||
path,
|
path,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
layout::WidgetID,
|
layout::WidgetID,
|
||||||
parser::{
|
parser::{
|
||||||
ParserContext, ParserFile, iter_attribs, parse_children, parse_universal, style::parse_style,
|
ParserContext, ParserFile, iter_attribs, parse_children, parse_widget_universal, style::parse_style,
|
||||||
},
|
},
|
||||||
widget,
|
widget,
|
||||||
};
|
};
|
||||||
@@ -19,7 +19,7 @@ pub fn parse_widget_div<'a, U1, U2>(
|
|||||||
.layout
|
.layout
|
||||||
.add_child(parent_id, widget::div::Div::create()?, style)?;
|
.add_child(parent_id, widget::div::Div::create()?, style)?;
|
||||||
|
|
||||||
parse_universal(file, ctx, node, new_id)?;
|
parse_widget_universal(file, ctx, node, new_id)?;
|
||||||
parse_children(file, ctx, node, new_id)?;
|
parse_children(file, ctx, node, new_id)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use crate::{
|
|||||||
i18n::Translation,
|
i18n::Translation,
|
||||||
layout::WidgetID,
|
layout::WidgetID,
|
||||||
parser::{
|
parser::{
|
||||||
ParserContext, ParserFile, iter_attribs, parse_children, parse_universal,
|
ParserContext, ParserFile, iter_attribs, parse_children, parse_widget_universal,
|
||||||
style::{parse_style, parse_text_style},
|
style::{parse_style, parse_text_style},
|
||||||
},
|
},
|
||||||
widget::text::{TextLabel, TextParams},
|
widget::text::{TextLabel, TextParams},
|
||||||
@@ -38,7 +38,7 @@ pub fn parse_widget_label<'a, U1, U2>(
|
|||||||
.layout
|
.layout
|
||||||
.add_child(parent_id, TextLabel::create(&mut i18n, params)?, style)?;
|
.add_child(parent_id, TextLabel::create(&mut i18n, params)?, style)?;
|
||||||
|
|
||||||
parse_universal(file, ctx, node, new_id)?;
|
parse_widget_universal(file, ctx, node, new_id)?;
|
||||||
parse_children(file, ctx, node, new_id)?;
|
parse_children(file, ctx, node, new_id)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ use crate::{
|
|||||||
drawing::GradientMode,
|
drawing::GradientMode,
|
||||||
layout::WidgetID,
|
layout::WidgetID,
|
||||||
parser::{
|
parser::{
|
||||||
ParserContext, ParserFile, iter_attribs, parse_children, parse_universal, print_invalid_attrib,
|
ParserContext, ParserFile, iter_attribs, parse_children, parse_widget_universal,
|
||||||
|
print_invalid_attrib,
|
||||||
style::{parse_color, parse_round, parse_style},
|
style::{parse_color, parse_round, parse_style},
|
||||||
},
|
},
|
||||||
widget::{self, rectangle::RectangleParams},
|
widget::{self, rectangle::RectangleParams},
|
||||||
@@ -60,7 +61,7 @@ pub fn parse_widget_rectangle<'a, U1, U2>(
|
|||||||
style,
|
style,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
parse_universal(file, ctx, node, new_id)?;
|
parse_widget_universal(file, ctx, node, new_id)?;
|
||||||
parse_children(file, ctx, node, new_id)?;
|
parse_children(file, ctx, node, new_id)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
layout::WidgetID,
|
layout::WidgetID,
|
||||||
parser::{
|
parser::{
|
||||||
ParserContext, ParserFile, iter_attribs, parse_children, parse_universal, style::parse_style,
|
ParserContext, ParserFile, iter_attribs, parse_children, parse_widget_universal,
|
||||||
|
style::parse_style,
|
||||||
},
|
},
|
||||||
renderer_vk::text::custom_glyph::{CustomGlyphContent, CustomGlyphData},
|
renderer_vk::text::custom_glyph::{CustomGlyphContent, CustomGlyphData},
|
||||||
widget::sprite::{SpriteBox, SpriteBoxParams},
|
widget::sprite::{SpriteBox, SpriteBoxParams},
|
||||||
@@ -58,7 +59,7 @@ pub fn parse_widget_sprite<'a, U1, U2>(
|
|||||||
.layout
|
.layout
|
||||||
.add_child(parent_id, SpriteBox::create(params)?, style)?;
|
.add_child(parent_id, SpriteBox::create(params)?, style)?;
|
||||||
|
|
||||||
parse_universal(file, ctx, node, new_id)?;
|
parse_widget_universal(file, ctx, node, new_id)?;
|
||||||
parse_children(file, ctx, node, new_id)?;
|
parse_children(file, ctx, node, new_id)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
Reference in New Issue
Block a user