various_widgets: add visibility test, minor refactoring

This commit is contained in:
Aleksander
2025-11-15 00:00:41 +01:00
parent 3daee83838
commit 5ce745d2b9
11 changed files with 182 additions and 94 deletions

View File

@@ -1,6 +1,6 @@
use crate::{
animation::{Animation, AnimationEasing},
components::{self, tooltip::ComponentTooltip, Component, ComponentBase, ComponentTrait, InitData},
components::{self, Component, ComponentBase, ComponentTrait, RefreshData, tooltip::ComponentTooltip},
drawing::{self, Boundary, Color},
event::{CallbackDataCommon, EventListenerCollection, EventListenerID, EventListenerKind},
i18n::Translation,
@@ -10,15 +10,15 @@ use crate::{
util::centered_matrix,
},
widget::{
ConstructEssentials, EventResult, WidgetData,
label::{WidgetLabel, WidgetLabelParams},
rectangle::{WidgetRectangle, WidgetRectangleParams},
util::WLength,
ConstructEssentials, EventResult, WidgetData,
},
};
use glam::{Mat4, Vec3};
use std::{cell::RefCell, rc::Rc};
use taffy::{prelude::length, AlignItems, JustifyContent};
use taffy::{AlignItems, JustifyContent, prelude::length};
pub struct Params {
pub text: Option<Translation>, // if unset, label will not be populated
@@ -83,11 +83,15 @@ pub struct ComponentButton {
}
impl ComponentTrait for ComponentButton {
fn base(&mut self) -> &mut ComponentBase {
fn base(&self) -> &ComponentBase {
&self.base
}
fn base_mut(&mut self) -> &mut ComponentBase {
&mut self.base
}
fn init(&self, _data: &mut InitData) {}
fn refresh(&self, _data: &mut RefreshData) {}
}
impl ComponentButton {
@@ -339,6 +343,7 @@ fn register_event_mouse_release(
)
}
#[allow(clippy::too_many_lines)]
pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Result<(WidgetPair, Rc<ComponentButton>)> {
let globals = ess.layout.state.globals.clone();
let mut style = params.style;
@@ -390,7 +395,14 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
let id_rect = root.id;
let light_text = (color.r + color.g + color.b) < 1.5;
let light_text = {
let mult = if globals.get().defaults.dark_mode {
color.a
} else {
1.0 - color.a
};
(color.r + color.g + color.b) * mult < 1.5
};
let id_label = if let Some(content) = params.text {
let (label, _node_label) = ess.layout.add_child(
@@ -436,6 +448,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
}));
let base = ComponentBase {
id: root.id,
lhandles: {
let mut widget = ess.layout.state.widgets.get(id_rect).unwrap().state();
vec![
@@ -449,6 +462,6 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
let button = Rc::new(ComponentButton { base, data, state });
ess.layout.defer_component_init(Component(button.clone()));
ess.layout.defer_component_refresh(Component(button.clone()));
Ok((root, button))
}

View File

@@ -1,22 +1,22 @@
use std::{cell::RefCell, rc::Rc};
use taffy::{
prelude::{length, percent},
AlignItems, JustifyContent,
prelude::{length, percent},
};
use crate::{
animation::{Animation, AnimationEasing},
components::{Component, ComponentBase, ComponentTrait, InitData},
components::{Component, ComponentBase, ComponentTrait, RefreshData},
drawing::Color,
event::{CallbackDataCommon, EventListenerCollection, EventListenerID, EventListenerKind},
i18n::Translation,
layout::{self, WidgetID, WidgetPair},
renderer_vk::text::{FontWeight, TextStyle},
widget::{
ConstructEssentials, EventResult,
label::{WidgetLabel, WidgetLabelParams},
rectangle::{WidgetRectangle, WidgetRectangleParams},
util::WLength,
ConstructEssentials, EventResult,
},
};
@@ -68,11 +68,15 @@ pub struct ComponentCheckbox {
}
impl ComponentTrait for ComponentCheckbox {
fn base(&mut self) -> &mut ComponentBase {
fn base(&self) -> &ComponentBase {
&self.base
}
fn base_mut(&mut self) -> &mut ComponentBase {
&mut self.base
}
fn init(&self, _data: &mut InitData) {}
fn refresh(&self, _data: &mut RefreshData) {}
}
const COLOR_CHECKED: Color = Color::new(0.1, 0.5, 1.0, 1.0);
@@ -333,6 +337,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
}));
let base = ComponentBase {
id: root.id,
lhandles: {
let mut widget = ess.layout.state.widgets.get(id_container).unwrap().state();
vec![
@@ -346,6 +351,6 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
let checkbox = Rc::new(ComponentCheckbox { base, data, state });
ess.layout.defer_component_init(Component(checkbox.clone()));
ess.layout.defer_component_refresh(Component(checkbox.clone()));
Ok((root, checkbox))
}

View File

@@ -3,6 +3,7 @@ use std::rc::Rc;
use crate::{
any::AnyTrait,
event::{CallbackDataCommon, EventListenerID},
layout::WidgetID,
};
pub mod button;
@@ -10,7 +11,7 @@ pub mod checkbox;
pub mod slider;
pub mod tooltip;
pub struct InitData<'a> {
pub struct RefreshData<'a> {
pub common: &'a mut CallbackDataCommon<'a>,
}
@@ -19,11 +20,19 @@ pub struct InitData<'a> {
pub struct ComponentBase {
#[allow(dead_code)]
lhandles: Vec<EventListenerID>,
id: WidgetID,
}
impl ComponentBase {
pub const fn get_id(&self) -> WidgetID {
self.id
}
}
pub trait ComponentTrait: AnyTrait {
fn base(&mut self) -> &mut ComponentBase;
fn init(&self, data: &mut InitData);
fn base(&self) -> &ComponentBase;
fn base_mut(&mut self) -> &mut ComponentBase;
fn refresh(&self, data: &mut RefreshData);
}
#[derive(Clone)]

View File

@@ -5,7 +5,7 @@ use taffy::prelude::{length, percent};
use crate::{
animation::{Animation, AnimationEasing},
components::{Component, ComponentBase, ComponentTrait, InitData},
components::{Component, ComponentBase, ComponentTrait, RefreshData},
drawing::{self},
event::{self, CallbackDataCommon, EventListenerCollection, EventListenerKind},
i18n::Translation,
@@ -15,11 +15,11 @@ use crate::{
util,
},
widget::{
ConstructEssentials, EventResult,
div::WidgetDiv,
label::{WidgetLabel, WidgetLabelParams},
rectangle::{WidgetRectangle, WidgetRectangleParams},
util::WLength,
ConstructEssentials, EventResult,
},
};
@@ -80,7 +80,8 @@ struct Data {
body: WidgetID, // Div
slider_handle_rect_id: WidgetID, // Rectangle
slider_text_id: WidgetID, // Text
slider_handle_node: taffy::NodeId,
slider_handle: WidgetPair,
slider_handle_node_id: taffy::NodeId,
slider_body_node: taffy::NodeId,
}
@@ -98,13 +99,17 @@ pub struct ComponentSlider {
}
impl ComponentTrait for ComponentSlider {
fn init(&self, init_data: &mut InitData) {
fn refresh(&self, init_data: &mut RefreshData) {
let mut state = self.state.borrow_mut();
let value = state.values.value;
state.set_value(init_data.common, &self.data, value);
}
fn base(&mut self) -> &mut ComponentBase {
fn base(&self) -> &ComponentBase {
&self.base
}
fn base_mut(&mut self) -> &mut ComponentBase {
&mut self.base
}
}
@@ -187,17 +192,15 @@ impl State {
}
fn set_value(&mut self, common: &mut CallbackDataCommon, data: &Data, value: f32) {
//common.call_on_widget(data.slider_handle_id, |_div: &mut Div| {});
let before = self.values.value;
self.values.set_value(value);
let changed = self.values.value != before;
let mut style = common.state.tree.style(data.slider_handle_node).unwrap().clone();
let mut style = common.state.tree.style(data.slider_handle_node_id).unwrap().clone();
conf_handle_style(&self.values, data.slider_body_node, &mut style, &common.state.tree);
common.alterables.mark_dirty(data.slider_handle_node);
common.alterables.mark_dirty(data.slider_handle_node_id);
common.alterables.mark_redraw();
common.alterables.set_style(data.slider_handle_node, style);
common.alterables.set_style(data.slider_handle.id, 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);
@@ -401,9 +404,10 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
};
// invisible outer handle body
let (slider_handle, slider_handle_node) = ess
.layout
.add_child(body_id, WidgetDiv::create(), slider_handle_style)?;
let (slider_handle, slider_handle_node_id) =
ess
.layout
.add_child(body_id, WidgetDiv::create(), slider_handle_style)?;
let (slider_handle_rect, _) = ess.layout.add_child(
slider_handle.id,
@@ -452,15 +456,17 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
let data = Rc::new(Data {
body: body_id,
slider_handle_node,
slider_handle,
slider_handle_rect_id: slider_handle_rect.id,
slider_body_node,
slider_handle_node_id,
slider_text_id: slider_text.id,
});
let state = Rc::new(RefCell::new(state));
let base = ComponentBase {
id: root.id,
lhandles: {
let mut widget = ess.layout.state.widgets.get(body_id).unwrap().state();
vec![
@@ -476,6 +482,6 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
let slider = Rc::new(ComponentSlider { base, data, state });
ess.layout.defer_component_init(Component(slider.clone()));
ess.layout.defer_component_refresh(Component(slider.clone()));
Ok((root, slider))
}

View File

@@ -3,7 +3,7 @@ use std::{cell::RefCell, rc::Rc};
use taffy::prelude::length;
use crate::{
components::{self, Component, ComponentBase, ComponentTrait, InitData},
components::{self, Component, ComponentBase, ComponentTrait, RefreshData},
drawing::Color,
i18n::Translation,
layout::{self, LayoutTask, LayoutTasks, WidgetID, WidgetPair},
@@ -65,11 +65,15 @@ pub struct ComponentTooltip {
}
impl ComponentTrait for ComponentTooltip {
fn base(&mut self) -> &mut ComponentBase {
fn base_mut(&mut self) -> &mut ComponentBase {
&mut self.base
}
fn init(&self, _data: &mut InitData) {}
fn base(&self) -> &ComponentBase {
&self.base
}
fn refresh(&self, _data: &mut RefreshData) {}
}
impl ComponentTooltip {}
@@ -200,7 +204,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
tasks: ess.layout.tasks.clone(),
});
ess.layout.defer_component_init(Component(tooltip.clone()));
ess.layout.defer_component_refresh(Component(tooltip.clone()));
Ok((div, tooltip))
}

View File

@@ -96,7 +96,7 @@ impl Event {
#[derive(Default)]
pub struct EventAlterables {
pub dirty_nodes: Vec<taffy::NodeId>,
pub style_set_requests: Vec<(taffy::NodeId, taffy::Style)>,
pub style_set_requests: Vec<(WidgetID, taffy::Style)>,
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 +112,8 @@ impl EventAlterables {
self.needs_redraw = true;
}
pub fn set_style(&mut self, node_id: taffy::NodeId, style: taffy::Style) {
self.style_set_requests.push((node_id, style));
pub fn set_style(&mut self, widget_id: WidgetID, style: taffy::Style) {
self.style_set_requests.push((widget_id, style));
}
pub fn mark_dirty(&mut self, node_id: taffy::NodeId) {

View File

@@ -7,7 +7,7 @@ use std::{
use crate::{
animation::Animations,
components::{Component, InitData},
components::{Component, RefreshData},
drawing::{self, ANSI_BOLD_CODE, ANSI_RESET_CODE, Boundary, push_scissor_stack, push_transform_stack},
event::{self, CallbackDataCommon, EventAlterables},
globals::WguiGlobals,
@@ -139,7 +139,8 @@ pub struct Layout {
pub tasks: LayoutTasks,
pub components_to_init: Vec<Component>,
components_to_refresh: Vec<Component>,
pub widgets_to_tick: Vec<WidgetID>,
// *Main root*
@@ -311,15 +312,19 @@ impl Layout {
}
fn process_pending_components(&mut self, alterables: &mut EventAlterables) {
for comp in &self.components_to_init {
for comp in &self.components_to_refresh {
let mut common = CallbackDataCommon {
state: &self.state,
alterables,
};
comp.0.init(&mut InitData { common: &mut common });
/* todo
let widget_id = comp.0.base().get_id();
*/
comp.0.refresh(&mut RefreshData { common: &mut common });
}
self.components_to_init.clear();
self.components_to_refresh.clear();
}
fn process_pending_widget_ticks(&mut self, alterables: &mut EventAlterables) {
@@ -333,8 +338,8 @@ impl Layout {
self.widgets_to_tick.clear();
}
pub fn defer_component_init(&mut self, component: Component) {
self.components_to_init.push(component);
pub fn defer_component_refresh(&mut self, component: Component) {
self.components_to_refresh.push(component);
}
/// Convenience function to avoid repeated `WidgetID` → `WidgetState` lookups.
@@ -552,7 +557,7 @@ impl Layout {
needs_redraw: true,
haptics_triggered: false,
animations: Animations::default(),
components_to_init: Vec::new(),
components_to_refresh: Vec::new(),
widgets_to_tick: Vec::new(),
tasks: LayoutTasks::new(),
})
@@ -680,9 +685,11 @@ impl Layout {
}
}
for request in alterables.style_set_requests {
if let Err(e) = self.state.tree.set_style(request.0, request.1) {
log::error!("failed to set style for taffy widget ID {:?}: {:?}", request.0, e);
for (widget_id, style) in alterables.style_set_requests {
if let Some(node_id) = self.state.nodes.get(widget_id) {
if let Err(e) = self.state.tree.set_style(*node_id, style) {
log::error!("failed to set style for taffy widget ID {node_id:?}: {e:?}");
}
}
}
@@ -763,6 +770,14 @@ impl LayoutState {
Vec2::new(layout.size.width, layout.size.height)
}
pub fn get_node_style(&self, id: NodeId) -> Option<&taffy::Style> {
let Ok(style) = self.tree.style(id) else {
return None;
};
Some(style)
}
pub fn get_widget_boundary(&self, id: WidgetID) -> Boundary {
let Some(node_id) = self.nodes.get(id) else {
return Boundary::default();
@@ -778,4 +793,8 @@ impl LayoutState {
self.get_node_size(*node_id)
}
pub fn get_widget_style(&self, id: WidgetID) -> Option<&taffy::Style> {
self.get_node_style(*self.nodes.get(id)?)
}
}