dash-frontend: Use native <Button>s, children support

This commit is contained in:
Aleksander
2025-09-13 12:49:36 +02:00
parent c2628c0a15
commit 9efe298f65
13 changed files with 117 additions and 82 deletions

View File

@@ -11,7 +11,7 @@
<rectangle position="absolute" color="#333333" width="100%" height="100%" /> <rectangle position="absolute" color="#333333" width="100%" height="100%" />
<!-- left/right separator (menu and rest) --> <!-- left/right separator (menu and rest) -->
<div flex_direction="row" gap="8" width="950" height="550"> <div flex_direction="row" gap="8" width="100%" height="100%">
<!-- LEFT MENU --> <!-- LEFT MENU -->
<div id="menu" width="48" min_width="48" max_width="48" height="100%" align_items="center" justify_content="center"> <div id="menu" width="48" min_width="48" max_width="48" height="100%" align_items="center" justify_content="center">
<rectangle <rectangle

View File

@@ -1,19 +1,18 @@
<layout> <layout>
<template name="MenuButton"> <template name="MenuButton">
<rectangle <Button
width="120" width="120"
height="82" height="82"
round="8"
border="2"
border_color="#FFFFFF77"
color="#00000033" color="#00000033"
border_color="#FFFFFF77"
round="8">
<div gap="8"
align_items="center" align_items="center"
justify_content="center" justify_content="center"
flex_direction="column" flex_direction="column">
gap="8"
>
<sprite src="${icon}" width="32" height="32" /> <sprite src="${icon}" width="32" height="32" />
<label weight="bold" color="#FFFFFF" size="18" text="${text}" /> <label weight="bold" color="#FFFFFF" size="18" text="${text}" />
</rectangle> </div>
</Button>
</template> </template>
</layout> </layout>

View File

@@ -2,7 +2,7 @@ use glam::Vec2;
use wgui::{ use wgui::{
event::EventListenerCollection, event::EventListenerCollection,
globals::WguiGlobals, globals::WguiGlobals,
layout::Layout, layout::{Layout, LayoutParams},
parser::{ParseDocumentParams, ParserState}, parser::{ParseDocumentParams, ParserState},
}; };
@@ -30,6 +30,9 @@ impl Frontend {
path: "gui/dashboard.xml", path: "gui/dashboard.xml",
extra: Default::default(), extra: Default::default(),
}, },
&LayoutParams {
resize_to_parent: true,
},
)?; )?;
Ok(Self { layout, state }) Ok(Self { layout, state })

View File

@@ -3,7 +3,7 @@ use glam::Vec2;
use wgui::{ use wgui::{
event::EventListenerCollection, event::EventListenerCollection,
globals::WguiGlobals, globals::WguiGlobals,
layout::Layout, layout::{Layout, LayoutParams},
parser::{ParseDocumentParams, ParserState}, parser::{ParseDocumentParams, ParserState},
}; };
@@ -27,6 +27,7 @@ impl TestbedAny {
path: &path, path: &path,
extra: Default::default(), extra: Default::default(),
}, },
&LayoutParams::default(),
)?; )?;
Ok(Self { layout, state }) Ok(Self { layout, state })
} }

View File

@@ -12,7 +12,7 @@ use wgui::{
event::EventListenerCollection, event::EventListenerCollection,
globals::WguiGlobals, globals::WguiGlobals,
i18n::Translation, i18n::Translation,
layout::{Layout, Widget}, layout::{Layout, LayoutParams, Widget},
parser::{ParseDocumentExtra, ParseDocumentParams, ParserState}, parser::{ParseDocumentExtra, ParseDocumentParams, ParserState},
widget::{label::WidgetLabel, rectangle::WidgetRectangle}, widget::{label::WidgetLabel, rectangle::WidgetRectangle},
}; };
@@ -81,6 +81,9 @@ impl TestbedGeneric {
path: XML_PATH, path: XML_PATH,
extra, extra,
}, },
&LayoutParams {
resize_to_parent: true,
},
)?; )?;
let label_cur_option = state.fetch_widget(&layout.state, "label_current_option")?; let label_cur_option = state.fetch_widget(&layout.state, "label_current_option")?;

View File

@@ -64,7 +64,7 @@
## div widget ## div widget
`<div>` ### `<div>`
### The most simple element ### The most simple element
@@ -76,7 +76,7 @@ _None_
## label widget ## label widget
`<label>` ### `<label>`
### A simple text element ### A simple text element
@@ -104,7 +104,7 @@ _Text size in pixel units_
## rectangle widget ## rectangle widget
`<rectangle>` ### `<rectangle>`
### A styled rectangle ### A styled rectangle
@@ -130,7 +130,7 @@ _2nd gradient color_
## sprite widget ## sprite widget
`<sprite>` ### `<sprite>`
### Image widget, supports raster and svg vector ### Image widget, supports raster and svg vector
@@ -150,7 +150,7 @@ _External image path_
## Button component ## Button component
`<Button>` ### `<Button>`
### A clickable, decorated button ### A clickable, decorated button
@@ -170,11 +170,15 @@ _Translated by key_
`border_color`: #FFAABB | #FFAABBCC `border_color`: #FFAABB | #FFAABBCC
#### Info
Child widgets are supported and can be added directly in XML.
--- ---
## Slider component ## Slider component
`<Slider>` ### `<Slider>`
### A simple slider. ### A simple slider.
@@ -194,7 +198,7 @@ _Initial slider value_
## Checkbox component ## Checkbox component
`<CheckBox>` ### `<CheckBox>`
### A check-box with label. ### A check-box with label.

View File

@@ -101,6 +101,11 @@ pub struct Layout {
pub animations: Animations, pub animations: Animations,
} }
#[derive(Default)]
pub struct LayoutParams {
pub resize_to_parent: bool,
}
fn add_child_internal( fn add_child_internal(
tree: &mut taffy::TaffyTree<WidgetID>, tree: &mut taffy::TaffyTree<WidgetID>,
widgets: &mut WidgetMap, widgets: &mut WidgetMap,
@@ -289,7 +294,7 @@ impl Layout {
Ok(()) Ok(())
} }
pub fn new(globals: WguiGlobals) -> anyhow::Result<Self> { pub fn new(globals: WguiGlobals, params: &LayoutParams) -> anyhow::Result<Self> {
let mut state = LayoutState { let mut state = LayoutState {
tree: TaffyTree::new(), tree: TaffyTree::new(),
widgets: WidgetMap::new(), widgets: WidgetMap::new(),
@@ -304,7 +309,11 @@ impl Layout {
None, // no parent None, // no parent
WidgetDiv::create(), WidgetDiv::create(),
taffy::Style { taffy::Style {
size: taffy::Size::auto(), size: if params.resize_to_parent {
taffy::Size::percent(1.0)
} else {
taffy::Size::auto()
},
..Default::default() ..Default::default()
}, },
)?; )?;
@@ -322,19 +331,16 @@ impl Layout {
}) })
} }
pub fn update(&mut self, size: Vec2, timestep_alpha: f32) -> anyhow::Result<()> { fn try_recompute_layout(&mut self, size: Vec2) -> anyhow::Result<()> {
let mut alterables = EventAlterables::default(); if !self.state.tree.dirty(self.root_node)? && self.prev_size == size {
// Nothing to do
return Ok(());
}
self
.animations
.process(&self.state, &mut alterables, timestep_alpha);
self.process_alterables(alterables)?;
if self.state.tree.dirty(self.root_node)? || self.prev_size != size {
self.needs_redraw = true; self.needs_redraw = true;
log::debug!("re-computing layout, size {}x{}", size.x, size.y); log::debug!("re-computing layout, size {}x{}", size.x, size.y);
self.prev_size = size; self.prev_size = size;
self.state.tree.compute_layout_with_measure( self.state.tree.compute_layout_with_measure(
self.root_node, self.root_node,
taffy::Size { taffy::Size {
@@ -376,7 +382,18 @@ impl Layout {
); );
} }
self.content_size = vec2(root_size.width, root_size.height); self.content_size = vec2(root_size.width, root_size.height);
Ok(())
} }
pub fn update(&mut self, size: Vec2, timestep_alpha: f32) -> anyhow::Result<()> {
let mut alterables = EventAlterables::default();
self
.animations
.process(&self.state, &mut alterables, timestep_alpha);
self.process_alterables(alterables)?;
self.try_recompute_layout(size)?;
Ok(()) Ok(())
} }

View File

@@ -4,7 +4,7 @@ use crate::{
i18n::Translation, i18n::Translation,
layout::WidgetID, layout::WidgetID,
parser::{ parser::{
ParserContext, ParserFile, iter_attribs, process_component, ParserContext, ParserFile, iter_attribs, parse_children, 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,
@@ -70,6 +70,7 @@ pub fn parse_component_button<'a, U1, U2>(
)?; )?;
process_component(file, ctx, node, Component(component)); process_component(file, ctx, node, Component(component));
parse_children(file, ctx, node, new_id)?;
Ok(new_id) Ok(new_id)
} }

View File

@@ -3,8 +3,8 @@ use crate::{
i18n::Translation, i18n::Translation,
layout::WidgetID, layout::WidgetID,
parser::{ parser::{
ParserContext, ParserFile, iter_attribs, parse_check_f32, parse_check_i32, process_component, ParserContext, ParserFile, iter_attribs, parse_check_f32, parse_check_i32, parse_children,
style::parse_style, process_component, style::parse_style,
}, },
}; };

View File

@@ -2,7 +2,8 @@ use crate::{
components::{Component, slider}, components::{Component, slider},
layout::WidgetID, layout::WidgetID,
parser::{ parser::{
ParserContext, ParserFile, iter_attribs, parse_check_f32, process_component, style::parse_style, ParserContext, ParserFile, iter_attribs, parse_check_f32, parse_children, process_component,
style::parse_style,
}, },
}; };

View File

@@ -13,7 +13,7 @@ use crate::{
drawing::{self}, drawing::{self},
event::EventListenerCollection, event::EventListenerCollection,
globals::WguiGlobals, globals::WguiGlobals,
layout::{Layout, LayoutState, Widget, WidgetID, WidgetMap}, layout::{Layout, LayoutParams, LayoutState, Widget, WidgetID, WidgetMap},
parser::{ parser::{
component_button::parse_component_button, component_checkbox::parse_component_checkbox, component_button::parse_component_button, component_checkbox::parse_component_checkbox,
component_slider::parse_component_slider, widget_div::parse_widget_div, component_slider::parse_component_slider, widget_div::parse_widget_div,
@@ -797,8 +797,9 @@ pub fn parse_from_assets<U1, U2>(
pub fn new_layout_from_assets<U1, U2>( pub fn new_layout_from_assets<U1, U2>(
listeners: &mut EventListenerCollection<U1, U2>, listeners: &mut EventListenerCollection<U1, U2>,
doc_params: &ParseDocumentParams, doc_params: &ParseDocumentParams,
layout_params: &LayoutParams,
) -> anyhow::Result<(Layout, ParserState)> { ) -> anyhow::Result<(Layout, ParserState)> {
let mut layout = Layout::new(doc_params.globals.clone())?; let mut layout = Layout::new(doc_params.globals.clone(), layout_params)?;
let widget = layout.root_widget; let widget = layout.root_widget;
let state = parse_from_assets(doc_params, &mut layout, listeners, widget)?; let state = parse_from_assets(doc_params, &mut layout, listeners, widget)?;
Ok((layout, state)) Ok((layout, state))

View File

@@ -8,7 +8,7 @@ use wgui::{
MouseButtonIndex, MouseDownEvent, MouseLeaveEvent, MouseMotionEvent, MouseUpEvent, MouseButtonIndex, MouseDownEvent, MouseLeaveEvent, MouseMotionEvent, MouseUpEvent,
MouseWheelEvent, MouseWheelEvent,
}, },
layout::Layout, layout::{Layout, LayoutParams},
parser::ParserState, parser::ParserState,
renderer_vk::context::Context as WguiContext, renderer_vk::context::Context as WguiContext,
}; };
@@ -50,6 +50,7 @@ impl<S> GuiPanel<S> {
path, path,
extra: Default::default(), extra: Default::default(),
}, },
&LayoutParams::default(),
)?; )?;
let context = WguiContext::new(&mut app.wgui_shared, 1.0)?; let context = WguiContext::new(&mut app.wgui_shared, 1.0)?;
@@ -70,7 +71,7 @@ impl<S> GuiPanel<S> {
} }
pub fn new_blank(app: &mut AppState, state: S) -> anyhow::Result<Self> { pub fn new_blank(app: &mut AppState, state: S) -> anyhow::Result<Self> {
let layout = Layout::new(app.wgui_globals.clone())?; let layout = Layout::new(app.wgui_globals.clone(), &LayoutParams::default())?;
let context = WguiContext::new(&mut app.wgui_shared, 1.0)?; let context = WguiContext::new(&mut app.wgui_shared, 1.0)?;
let mut timestep = Timestep::new(); let mut timestep = Timestep::new();
timestep.set_tps(60.0); timestep.set_tps(60.0);

View File

@@ -5,6 +5,7 @@ use wgui::{
animation::{Animation, AnimationEasing}, animation::{Animation, AnimationEasing},
drawing::Color, drawing::Color,
event::{self, CallbackMetadata, EventListenerKind}, event::{self, CallbackMetadata, EventListenerKind},
layout::LayoutParams,
renderer_vk::util, renderer_vk::util,
taffy::{self, prelude::length}, taffy::{self, prelude::length},
widget::{ widget::{
@@ -80,8 +81,11 @@ where
extra: Default::default(), extra: Default::default(),
}; };
let (_, mut gui_state_key) = let (_, mut gui_state_key) = wgui::parser::new_layout_from_assets(
wgui::parser::new_layout_from_assets(&mut panel.listeners, &parse_doc_params)?; &mut panel.listeners,
&parse_doc_params,
&LayoutParams::default(),
)?;
for row in 0..layout.key_sizes.len() { for row in 0..layout.key_sizes.len() {
let (div, _) = panel.layout.add_child( let (div, _) = panel.layout.add_child(