wgui: StyleSetRequest
This commit is contained in:
@@ -13,6 +13,7 @@ use wgui::{
|
|||||||
checkbox::ComponentCheckbox,
|
checkbox::ComponentCheckbox,
|
||||||
},
|
},
|
||||||
drawing::Color,
|
drawing::Color,
|
||||||
|
event::StyleSetRequest,
|
||||||
font_config::WguiFontConfig,
|
font_config::WguiFontConfig,
|
||||||
globals::WguiGlobals,
|
globals::WguiGlobals,
|
||||||
i18n::Translation,
|
i18n::Translation,
|
||||||
@@ -123,17 +124,14 @@ impl TestbedGeneric {
|
|||||||
let div_visibility = state.fetch_widget(&layout.state, "div_visibility")?;
|
let div_visibility = state.fetch_widget(&layout.state, "div_visibility")?;
|
||||||
|
|
||||||
cb_visible.on_toggle(Box::new(move |common, evt| {
|
cb_visible.on_toggle(Box::new(move |common, evt| {
|
||||||
let mut style = common
|
common.alterables.set_style(
|
||||||
.state
|
div_visibility.id,
|
||||||
.get_widget_style(div_visibility.id)
|
StyleSetRequest::Display(if evt.checked {
|
||||||
.unwrap()
|
|
||||||
.clone();
|
|
||||||
style.display = if evt.checked {
|
|
||||||
taffy::Display::Flex
|
taffy::Display::Flex
|
||||||
} else {
|
} else {
|
||||||
taffy::Display::None
|
taffy::Display::None
|
||||||
};
|
}),
|
||||||
common.alterables.set_style(div_visibility.id, style);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use crate::{
|
|||||||
animation::{Animation, AnimationEasing},
|
animation::{Animation, AnimationEasing},
|
||||||
components::{Component, ComponentBase, ComponentTrait, RefreshData},
|
components::{Component, ComponentBase, ComponentTrait, RefreshData},
|
||||||
drawing::{self},
|
drawing::{self},
|
||||||
event::{self, CallbackDataCommon, EventListenerCollection, EventListenerKind},
|
event::{self, CallbackDataCommon, EventAlterables, EventListenerCollection, EventListenerKind, StyleSetRequest},
|
||||||
i18n::Translation,
|
i18n::Translation,
|
||||||
layout::{WidgetID, WidgetPair},
|
layout::{WidgetID, WidgetPair},
|
||||||
renderer_vk::{
|
renderer_vk::{
|
||||||
@@ -76,13 +76,11 @@ struct State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Data {
|
struct Data {
|
||||||
#[allow(dead_code)]
|
body_node: taffy::NodeId,
|
||||||
body: WidgetID, // Div
|
|
||||||
slider_handle_rect_id: WidgetID, // Rectangle
|
slider_handle_rect_id: WidgetID, // Rectangle
|
||||||
slider_text_id: WidgetID, // Text
|
slider_text_id: WidgetID, // Text
|
||||||
slider_handle: WidgetPair,
|
slider_handle_id: WidgetID,
|
||||||
slider_handle_node_id: taffy::NodeId,
|
slider_handle_node_id: taffy::NodeId,
|
||||||
slider_body_node: taffy::NodeId,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SliderValueChangedEvent {
|
pub struct SliderValueChangedEvent {
|
||||||
@@ -140,26 +138,31 @@ fn get_width(slider_body_node: taffy::NodeId, tree: &taffy::tree::TaffyTree<Widg
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn conf_handle_style(
|
fn conf_handle_style(
|
||||||
|
alterables: &mut EventAlterables,
|
||||||
values: &ValuesMinMax,
|
values: &ValuesMinMax,
|
||||||
slider_body_node: taffy::NodeId,
|
slider_handle_id: WidgetID,
|
||||||
|
body_node: taffy::NodeId,
|
||||||
slider_handle_style: &taffy::Style,
|
slider_handle_style: &taffy::Style,
|
||||||
tree: &taffy::tree::TaffyTree<WidgetID>,
|
tree: &taffy::tree::TaffyTree<WidgetID>,
|
||||||
) -> Option<taffy::Style> {
|
) -> bool {
|
||||||
|
/* returns false if nothing changed */
|
||||||
let norm = values.to_normalized();
|
let norm = values.to_normalized();
|
||||||
|
|
||||||
// convert normalized value to taffy percentage margin in percent
|
// 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 percent_margin = (HANDLE_WIDTH / width) / 2.0;
|
||||||
|
|
||||||
let new_percent = percent(percent_margin + norm * (1.0 - percent_margin * 2.0));
|
let new_percent = percent(percent_margin + norm * (1.0 - percent_margin * 2.0));
|
||||||
|
|
||||||
if slider_handle_style.margin.left == new_percent {
|
if slider_handle_style.margin.left == new_percent {
|
||||||
None // nothing changed
|
return false; // nothing changed
|
||||||
} else {
|
|
||||||
let mut new_style = slider_handle_style.clone();
|
|
||||||
new_style.margin.left = new_percent;
|
|
||||||
Some(new_style)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
const PAD_PERCENT: f32 = 0.75;
|
||||||
@@ -180,7 +183,7 @@ impl State {
|
|||||||
|
|
||||||
let norm = map_mouse_x_to_normalized(
|
let norm = map_mouse_x_to_normalized(
|
||||||
mouse_pos.x - HANDLE_WIDTH / 2.0,
|
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);
|
let target_value = self.values.get_from_normalized(norm);
|
||||||
@@ -206,13 +209,19 @@ impl State {
|
|||||||
|
|
||||||
let changed = self.values.value != before;
|
let changed = self.values.value != before;
|
||||||
let style = common.state.tree.style(data.slider_handle_node_id).unwrap();
|
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 {
|
if !conf_handle_style(
|
||||||
return; //nothing changed visually
|
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_dirty(data.slider_handle_node_id);
|
||||||
common.alterables.mark_redraw();
|
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) {
|
if let Some(mut label) = common.state.widgets.get_as::<WidgetLabel>(data.slider_text_id) {
|
||||||
Self::update_text(common, &mut label, self.values.value);
|
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 {
|
let data = Rc::new(Data {
|
||||||
body: body_id,
|
|
||||||
slider_handle,
|
|
||||||
slider_handle_rect_id: slider_handle_rect.id,
|
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_handle_node_id,
|
||||||
slider_text_id: slider_text.id,
|
slider_text_id: slider_text.id,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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
|
// alterables which will be dispatched in the next loop iteration phase
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct EventAlterables {
|
pub struct EventAlterables {
|
||||||
pub dirty_nodes: Vec<taffy::NodeId>,
|
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 animations: Vec<animation::Animation>,
|
||||||
pub widgets_to_tick: HashSet<WidgetID>, // widgets which needs to be ticked in the next `Layout::update()` fn
|
pub widgets_to_tick: HashSet<WidgetID>, // widgets which needs to be ticked in the next `Layout::update()` fn
|
||||||
pub transform_stack: TransformStack,
|
pub transform_stack: TransformStack,
|
||||||
@@ -112,8 +117,8 @@ impl EventAlterables {
|
|||||||
self.needs_redraw = true;
|
self.needs_redraw = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_style(&mut self, widget_id: WidgetID, style: taffy::Style) {
|
pub fn set_style(&mut self, widget_id: WidgetID, request: StyleSetRequest) {
|
||||||
self.style_set_requests.push((widget_id, style));
|
self.style_set_requests.push((widget_id, request));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_dirty(&mut self, node_id: taffy::NodeId) {
|
pub fn mark_dirty(&mut self, node_id: taffy::NodeId) {
|
||||||
|
|||||||
@@ -721,20 +721,33 @@ impl Layout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (widget_id, new_style) in alterables.style_set_requests {
|
for (widget_id, style_request) in alterables.style_set_requests {
|
||||||
if let Some(node_id) = self.state.nodes.get(widget_id) {
|
let Some(node_id) = self.state.nodes.get(widget_id) else {
|
||||||
let old_style = self.state.tree.style(*node_id).unwrap() /* always safe */;
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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 */;
|
||||||
|
|
||||||
|
match style_request {
|
||||||
|
event::StyleSetRequest::Display(display) => {
|
||||||
// refresh the component in case if visibility/display mode has changed
|
// refresh the component in case if visibility/display mode has changed
|
||||||
if old_style.display != new_style.display
|
if cur_style.display != display
|
||||||
&& let Some(component) = self.registered_components_to_refresh.get(node_id)
|
&& let Some(component) = self.registered_components_to_refresh.get(node_id)
|
||||||
{
|
{
|
||||||
self.components_to_refresh_once.insert(component.clone());
|
self.components_to_refresh_once.insert(component.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = self.state.tree.set_style(*node_id, new_style) {
|
cur_style.display = display;
|
||||||
log::error!("failed to set style for taffy widget ID {node_id:?}: {e:?}");
|
|
||||||
}
|
}
|
||||||
|
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:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
use button::setup_custom_button;
|
use button::setup_custom_button;
|
||||||
use glam::{vec2, Affine2, Vec2};
|
use glam::{Affine2, Vec2, vec2};
|
||||||
use label::setup_custom_label;
|
use label::setup_custom_label;
|
||||||
use wgui::{
|
use wgui::{
|
||||||
assets::AssetPath,
|
assets::AssetPath,
|
||||||
@@ -9,14 +9,14 @@ use wgui::{
|
|||||||
event::{
|
event::{
|
||||||
Event as WguiEvent, EventAlterables, EventCallback, EventListenerID, EventListenerKind,
|
Event as WguiEvent, EventAlterables, EventCallback, EventListenerID, EventListenerKind,
|
||||||
InternalStateChangeEvent, MouseButtonIndex, MouseDownEvent, MouseLeaveEvent,
|
InternalStateChangeEvent, MouseButtonIndex, MouseDownEvent, MouseLeaveEvent,
|
||||||
MouseMotionEvent, MouseUpEvent, MouseWheelEvent,
|
MouseMotionEvent, MouseUpEvent, MouseWheelEvent, StyleSetRequest,
|
||||||
},
|
},
|
||||||
gfx::cmd::WGfxClearMode,
|
gfx::cmd::WGfxClearMode,
|
||||||
layout::{Layout, LayoutParams, WidgetID},
|
layout::{Layout, LayoutParams, WidgetID},
|
||||||
parser::{CustomAttribsInfoOwned, ParserState},
|
parser::{CustomAttribsInfoOwned, ParserState},
|
||||||
renderer_vk::context::Context as WguiContext,
|
renderer_vk::context::Context as WguiContext,
|
||||||
taffy,
|
taffy,
|
||||||
widget::{label::WidgetLabel, rectangle::WidgetRectangle, EventResult},
|
widget::{EventResult, label::WidgetLabel, rectangle::WidgetRectangle},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -24,7 +24,7 @@ use crate::{
|
|||||||
state::AppState,
|
state::AppState,
|
||||||
subsystem::hid::WheelDelta,
|
subsystem::hid::WheelDelta,
|
||||||
windowing::backend::{
|
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,
|
display: taffy::Display,
|
||||||
alterables: &mut EventAlterables,
|
alterables: &mut EventAlterables,
|
||||||
) {
|
) {
|
||||||
let mut style = self
|
alterables.set_style(widget_id, StyleSetRequest::Display(display));
|
||||||
.layout
|
|
||||||
.state
|
|
||||||
.get_widget_style(widget_id)
|
|
||||||
.unwrap_or(&taffy::Style::DEFAULT)
|
|
||||||
.clone();
|
|
||||||
style.display = display;
|
|
||||||
alterables.set_style(widget_id, style);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
use std::{collections::HashMap, rc::Rc};
|
use std::{collections::HashMap, rc::Rc};
|
||||||
|
|
||||||
use wgui::{
|
use wgui::{
|
||||||
components::button::ComponentButton, event::CallbackDataCommon, layout::WidgetID,
|
components::button::ComponentButton,
|
||||||
parser::Fetchable, taffy,
|
event::{CallbackDataCommon, StyleSetRequest},
|
||||||
|
layout::WidgetID,
|
||||||
|
parser::Fetchable,
|
||||||
|
taffy,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::gui::panel::GuiPanel;
|
use crate::gui::panel::GuiPanel;
|
||||||
@@ -76,19 +79,15 @@ impl ButtonPaneTabSwitcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_tab_active(common: &mut CallbackDataCommon, data: &TabData, active: bool) {
|
fn set_tab_active(common: &mut CallbackDataCommon, data: &TabData, active: bool) {
|
||||||
let mut style = common
|
common.alterables.set_style(
|
||||||
.state
|
data.pane,
|
||||||
.get_widget_style(data.pane)
|
StyleSetRequest::Display(if active {
|
||||||
.unwrap_or(&taffy::Style::DEFAULT)
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
style.display = if active {
|
|
||||||
taffy::Display::Block
|
taffy::Display::Block
|
||||||
} else {
|
} else {
|
||||||
taffy::Display::None
|
taffy::Display::None
|
||||||
};
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
common.alterables.set_style(data.pane, style);
|
|
||||||
if let Some(button) = data.button.as_ref() {
|
if let Some(button) = data.button.as_ref() {
|
||||||
button.set_sticky_state(common, active);
|
button.set_sticky_state(common, active);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user