wgui: StyleSetRequest

This commit is contained in:
Aleksander
2025-11-26 22:49:50 +01:00
parent 85eab33c94
commit 9696d6730d
6 changed files with 88 additions and 72 deletions

View File

@@ -13,6 +13,7 @@ use wgui::{
checkbox::ComponentCheckbox,
},
drawing::Color,
event::StyleSetRequest,
font_config::WguiFontConfig,
globals::WguiGlobals,
i18n::Translation,
@@ -123,17 +124,14 @@ impl TestbedGeneric {
let div_visibility = state.fetch_widget(&layout.state, "div_visibility")?;
cb_visible.on_toggle(Box::new(move |common, evt| {
let mut style = common
.state
.get_widget_style(div_visibility.id)
.unwrap()
.clone();
style.display = if evt.checked {
taffy::Display::Flex
} else {
taffy::Display::None
};
common.alterables.set_style(div_visibility.id, style);
common.alterables.set_style(
div_visibility.id,
StyleSetRequest::Display(if evt.checked {
taffy::Display::Flex
} else {
taffy::Display::None
}),
);
Ok(())
}));

View File

@@ -7,7 +7,7 @@ use crate::{
animation::{Animation, AnimationEasing},
components::{Component, ComponentBase, ComponentTrait, RefreshData},
drawing::{self},
event::{self, CallbackDataCommon, EventListenerCollection, EventListenerKind},
event::{self, CallbackDataCommon, EventAlterables, EventListenerCollection, EventListenerKind, StyleSetRequest},
i18n::Translation,
layout::{WidgetID, WidgetPair},
renderer_vk::{
@@ -76,13 +76,11 @@ struct State {
}
struct Data {
#[allow(dead_code)]
body: WidgetID, // Div
body_node: taffy::NodeId,
slider_handle_rect_id: WidgetID, // Rectangle
slider_text_id: WidgetID, // Text
slider_handle: WidgetPair,
slider_handle_id: WidgetID,
slider_handle_node_id: taffy::NodeId,
slider_body_node: taffy::NodeId,
}
pub struct SliderValueChangedEvent {
@@ -140,26 +138,31 @@ fn get_width(slider_body_node: taffy::NodeId, tree: &taffy::tree::TaffyTree<Widg
}
fn conf_handle_style(
alterables: &mut EventAlterables,
values: &ValuesMinMax,
slider_body_node: taffy::NodeId,
slider_handle_id: WidgetID,
body_node: taffy::NodeId,
slider_handle_style: &taffy::Style,
tree: &taffy::tree::TaffyTree<WidgetID>,
) -> Option<taffy::Style> {
) -> bool {
/* returns false if nothing changed */
let norm = values.to_normalized();
// convert normalized value to taffy percentage margin in percent
let width = get_width(slider_body_node, tree);
let width = get_width(body_node, tree);
let percent_margin = (HANDLE_WIDTH / width) / 2.0;
let new_percent = percent(percent_margin + norm * (1.0 - percent_margin * 2.0));
if slider_handle_style.margin.left == new_percent {
None // nothing changed
} else {
let mut new_style = slider_handle_style.clone();
new_style.margin.left = new_percent;
Some(new_style)
return false; // nothing changed
}
let mut margin = slider_handle_style.margin;
margin.left = new_percent;
alterables.set_style(slider_handle_id, StyleSetRequest::Margin(margin));
true
}
const PAD_PERCENT: f32 = 0.75;
@@ -180,7 +183,7 @@ impl State {
let norm = map_mouse_x_to_normalized(
mouse_pos.x - HANDLE_WIDTH / 2.0,
get_width(data.slider_body_node, &common.state.tree) - HANDLE_WIDTH,
get_width(data.body_node, &common.state.tree) - HANDLE_WIDTH,
);
let target_value = self.values.get_from_normalized(norm);
@@ -206,13 +209,19 @@ impl State {
let changed = self.values.value != before;
let style = common.state.tree.style(data.slider_handle_node_id).unwrap();
let Some(new_style) = conf_handle_style(&self.values, data.slider_body_node, style, &common.state.tree) else {
return; //nothing changed visually
};
if !conf_handle_style(
common.alterables,
&self.values,
data.slider_handle_id,
data.body_node,
style,
&common.state.tree,
) {
return; // nothing changed visually
}
common.alterables.mark_dirty(data.slider_handle_node_id);
common.alterables.mark_redraw();
common.alterables.set_style(data.slider_handle.id, new_style);
if let Some(mut label) = common.state.widgets.get_as::<WidgetLabel>(data.slider_text_id) {
Self::update_text(common, &mut label, self.values.value);
@@ -467,10 +476,9 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
)?;
let data = Rc::new(Data {
body: body_id,
slider_handle,
slider_handle_rect_id: slider_handle_rect.id,
slider_body_node,
body_node: slider_body_node,
slider_handle_id: slider_handle.id,
slider_handle_node_id,
slider_text_id: slider_text.id,
});

View File

@@ -92,11 +92,16 @@ impl Event {
}
}
pub enum StyleSetRequest {
Display(taffy::Display),
Margin(taffy::Rect<taffy::LengthPercentageAuto>),
}
// alterables which will be dispatched in the next loop iteration phase
#[derive(Default)]
pub struct EventAlterables {
pub dirty_nodes: Vec<taffy::NodeId>,
pub style_set_requests: Vec<(WidgetID, taffy::Style)>,
pub style_set_requests: Vec<(WidgetID, StyleSetRequest)>,
pub animations: Vec<animation::Animation>,
pub widgets_to_tick: HashSet<WidgetID>, // widgets which needs to be ticked in the next `Layout::update()` fn
pub transform_stack: TransformStack,
@@ -112,8 +117,8 @@ impl EventAlterables {
self.needs_redraw = true;
}
pub fn set_style(&mut self, widget_id: WidgetID, style: taffy::Style) {
self.style_set_requests.push((widget_id, style));
pub fn set_style(&mut self, widget_id: WidgetID, request: StyleSetRequest) {
self.style_set_requests.push((widget_id, request));
}
pub fn mark_dirty(&mut self, node_id: taffy::NodeId) {

View File

@@ -721,20 +721,33 @@ impl Layout {
}
}
for (widget_id, new_style) in alterables.style_set_requests {
if let Some(node_id) = self.state.nodes.get(widget_id) {
let old_style = self.state.tree.style(*node_id).unwrap() /* always safe */;
for (widget_id, style_request) in alterables.style_set_requests {
let Some(node_id) = self.state.nodes.get(widget_id) else {
continue;
};
// refresh the component in case if visibility/display mode has changed
if old_style.display != new_style.display
&& let Some(component) = self.registered_components_to_refresh.get(node_id)
{
self.components_to_refresh_once.insert(component.clone());
}
// taffy requires us to copy this whole 536-byte style struct.
// we can't get `&mut Style` directly from taffy unfortunately
let mut cur_style = self.state.tree.style(*node_id).unwrap().clone() /* always safe */;
if let Err(e) = self.state.tree.set_style(*node_id, new_style) {
log::error!("failed to set style for taffy widget ID {node_id:?}: {e:?}");
match style_request {
event::StyleSetRequest::Display(display) => {
// refresh the component in case if visibility/display mode has changed
if cur_style.display != display
&& let Some(component) = self.registered_components_to_refresh.get(node_id)
{
self.components_to_refresh_once.insert(component.clone());
}
cur_style.display = display;
}
event::StyleSetRequest::Margin(margin) => {
cur_style.margin = margin;
}
}
if let Err(e) = self.state.tree.set_style(*node_id, cur_style) {
log::error!("failed to set style for taffy widget ID {node_id:?}: {e:?}");
}
}

View File

@@ -1,7 +1,7 @@
use std::{cell::RefCell, rc::Rc};
use button::setup_custom_button;
use glam::{vec2, Affine2, Vec2};
use glam::{Affine2, Vec2, vec2};
use label::setup_custom_label;
use wgui::{
assets::AssetPath,
@@ -9,14 +9,14 @@ use wgui::{
event::{
Event as WguiEvent, EventAlterables, EventCallback, EventListenerID, EventListenerKind,
InternalStateChangeEvent, MouseButtonIndex, MouseDownEvent, MouseLeaveEvent,
MouseMotionEvent, MouseUpEvent, MouseWheelEvent,
MouseMotionEvent, MouseUpEvent, MouseWheelEvent, StyleSetRequest,
},
gfx::cmd::WGfxClearMode,
layout::{Layout, LayoutParams, WidgetID},
parser::{CustomAttribsInfoOwned, ParserState},
renderer_vk::context::Context as WguiContext,
taffy,
widget::{label::WidgetLabel, rectangle::WidgetRectangle, EventResult},
widget::{EventResult, label::WidgetLabel, rectangle::WidgetRectangle},
};
use crate::{
@@ -24,7 +24,7 @@ use crate::{
state::AppState,
subsystem::hid::WheelDelta,
windowing::backend::{
ui_transform, FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender,
FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender, ui_transform,
},
};
@@ -228,14 +228,7 @@ impl<S: 'static> GuiPanel<S> {
display: taffy::Display,
alterables: &mut EventAlterables,
) {
let mut style = self
.layout
.state
.get_widget_style(widget_id)
.unwrap_or(&taffy::Style::DEFAULT)
.clone();
style.display = display;
alterables.set_style(widget_id, style);
alterables.set_style(widget_id, StyleSetRequest::Display(display));
}
}

View File

@@ -1,8 +1,11 @@
use std::{collections::HashMap, rc::Rc};
use wgui::{
components::button::ComponentButton, event::CallbackDataCommon, layout::WidgetID,
parser::Fetchable, taffy,
components::button::ComponentButton,
event::{CallbackDataCommon, StyleSetRequest},
layout::WidgetID,
parser::Fetchable,
taffy,
};
use crate::gui::panel::GuiPanel;
@@ -76,19 +79,15 @@ impl ButtonPaneTabSwitcher {
}
fn set_tab_active(common: &mut CallbackDataCommon, data: &TabData, active: bool) {
let mut style = common
.state
.get_widget_style(data.pane)
.unwrap_or(&taffy::Style::DEFAULT)
.clone();
common.alterables.set_style(
data.pane,
StyleSetRequest::Display(if active {
taffy::Display::Block
} else {
taffy::Display::None
}),
);
style.display = if active {
taffy::Display::Block
} else {
taffy::Display::None
};
common.alterables.set_style(data.pane, style);
if let Some(button) = data.button.as_ref() {
button.set_sticky_state(common, active);
}