dash-frontend: tabs, other fixes (desc)
- set rustfmt line width to 120 columns by default for wgui - dashboard tabs - wgui: `remove_children`
This commit is contained in:
@@ -43,6 +43,11 @@ impl Widget {
|
||||
pub struct WidgetMap(HopSlotMap<WidgetID, Widget>);
|
||||
pub type WidgetNodeMap = SecondaryMap<WidgetID, taffy::NodeId>;
|
||||
|
||||
pub struct WidgetPair {
|
||||
pub id: WidgetID,
|
||||
pub widget: Widget,
|
||||
}
|
||||
|
||||
impl WidgetMap {
|
||||
fn new() -> Self {
|
||||
Self(HopSlotMap::with_key())
|
||||
@@ -60,6 +65,10 @@ impl WidgetMap {
|
||||
self.0.insert(obj)
|
||||
}
|
||||
|
||||
pub fn remove_single(&mut self, handle: WidgetID) {
|
||||
self.0.remove(handle);
|
||||
}
|
||||
|
||||
// cast to specific widget type, does nothing if widget ID is expired
|
||||
// panics in case if the widget type is wrong
|
||||
// TODO: panic-less alternative
|
||||
@@ -101,6 +110,8 @@ pub struct Layout {
|
||||
pub animations: Animations,
|
||||
}
|
||||
|
||||
pub type RcLayout = Rc<RefCell<Layout>>;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct LayoutParams {
|
||||
pub resize_to_parent: bool,
|
||||
@@ -128,6 +139,10 @@ fn add_child_internal(
|
||||
}
|
||||
|
||||
impl Layout {
|
||||
pub fn as_rc(self) -> RcLayout {
|
||||
Rc::new(RefCell::new(self))
|
||||
}
|
||||
|
||||
pub fn add_child(
|
||||
&mut self,
|
||||
parent_widget_id: WidgetID,
|
||||
@@ -148,6 +163,34 @@ impl Layout {
|
||||
)
|
||||
}
|
||||
|
||||
fn collect_children_ids_recursive(&self, widget_id: WidgetID, out: &mut Vec<(WidgetID, taffy::NodeId)>) {
|
||||
let Some(node_id) = self.state.nodes.get(widget_id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
for child_id in self.state.tree.child_ids(*node_id) {
|
||||
let child_widget_id = self.state.tree.get_node_context(child_id).unwrap();
|
||||
out.push((*child_widget_id, child_id));
|
||||
self.collect_children_ids_recursive(*child_widget_id, out);
|
||||
}
|
||||
}
|
||||
|
||||
// removes all children of a specific widget
|
||||
pub fn remove_children(&mut self, widget_id: WidgetID) {
|
||||
let mut ids = Vec::new();
|
||||
self.collect_children_ids_recursive(widget_id, &mut ids);
|
||||
|
||||
if !ids.is_empty() {
|
||||
self.needs_redraw = true;
|
||||
}
|
||||
|
||||
for (widget_id, node_id) in ids {
|
||||
self.state.widgets.remove_single(widget_id);
|
||||
self.state.nodes.remove(widget_id);
|
||||
self.state.tree.remove(node_id).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn process_pending_components(&mut self) -> anyhow::Result<()> {
|
||||
let mut alterables = EventAlterables::default();
|
||||
|
||||
@@ -224,20 +267,11 @@ impl Layout {
|
||||
|
||||
let mut widget = widget.0.borrow_mut();
|
||||
|
||||
match widget.process_event(
|
||||
widget_id,
|
||||
listeners_vec,
|
||||
node_id,
|
||||
event,
|
||||
user_data,
|
||||
&mut params,
|
||||
)? {
|
||||
match widget.process_event(widget_id, listeners_vec, node_id, event, user_data, &mut params)? {
|
||||
widget::EventResult::Pass => {
|
||||
// go on
|
||||
}
|
||||
widget::EventResult::Consumed
|
||||
| widget::EventResult::Outside
|
||||
| widget::EventResult::Unused => {
|
||||
widget::EventResult::Consumed | widget::EventResult::Outside | widget::EventResult::Unused => {
|
||||
iter_children = false;
|
||||
}
|
||||
}
|
||||
@@ -279,13 +313,7 @@ impl Layout {
|
||||
) -> anyhow::Result<()> {
|
||||
let mut alterables = EventAlterables::default();
|
||||
|
||||
self.push_event_widget(
|
||||
listeners,
|
||||
self.root_node,
|
||||
event,
|
||||
&mut alterables,
|
||||
&mut user_data,
|
||||
)?;
|
||||
self.push_event_widget(listeners, self.root_node, event, &mut alterables, &mut user_data)?;
|
||||
|
||||
self.process_alterables(alterables)?;
|
||||
|
||||
@@ -360,10 +388,7 @@ impl Layout {
|
||||
None => taffy::Size::ZERO,
|
||||
Some(h) => {
|
||||
if let Some(w) = self.state.widgets.get(*h) {
|
||||
w.0
|
||||
.borrow_mut()
|
||||
.obj
|
||||
.measure(known_dimensions, available_space)
|
||||
w.0.borrow_mut().obj.measure(known_dimensions, available_space)
|
||||
} else {
|
||||
taffy::Size::ZERO
|
||||
}
|
||||
@@ -388,9 +413,7 @@ impl Layout {
|
||||
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.animations.process(&self.state, &mut alterables, timestep_alpha);
|
||||
|
||||
self.process_alterables(alterables)?;
|
||||
self.try_recompute_layout(size)?;
|
||||
@@ -428,11 +451,7 @@ 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
|
||||
);
|
||||
log::error!("failed to set style for taffy widget ID {:?}: {:?}", request.0, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@ use crate::{
|
||||
i18n::Translation,
|
||||
layout::WidgetID,
|
||||
parser::{
|
||||
ParserContext, ParserFile, iter_attribs, parse_check_f32, parse_check_i32, parse_children,
|
||||
process_component, style::parse_style,
|
||||
ParserContext, ParserFile, iter_attribs, parse_check_f32, parse_check_i32, process_component, style::parse_style,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
use crate::{
|
||||
components::{Component, slider},
|
||||
layout::WidgetID,
|
||||
parser::{
|
||||
ParserContext, ParserFile, iter_attribs, parse_check_f32, parse_children, process_component,
|
||||
style::parse_style,
|
||||
},
|
||||
parser::{ParserContext, ParserFile, iter_attribs, parse_check_f32, process_component, style::parse_style},
|
||||
};
|
||||
|
||||
pub fn parse_component_slider<'a, U1, U2>(
|
||||
|
||||
@@ -13,12 +13,11 @@ use crate::{
|
||||
drawing::{self},
|
||||
event::EventListenerCollection,
|
||||
globals::WguiGlobals,
|
||||
layout::{Layout, LayoutParams, LayoutState, Widget, WidgetID, WidgetMap},
|
||||
layout::{Layout, LayoutParams, LayoutState, Widget, WidgetID, WidgetMap, WidgetPair},
|
||||
parser::{
|
||||
component_button::parse_component_button, component_checkbox::parse_component_checkbox,
|
||||
component_slider::parse_component_slider, widget_div::parse_widget_div,
|
||||
widget_label::parse_widget_label, widget_rectangle::parse_widget_rectangle,
|
||||
widget_sprite::parse_widget_sprite,
|
||||
component_slider::parse_component_slider, widget_div::parse_widget_div, widget_label::parse_widget_label,
|
||||
widget_rectangle::parse_widget_rectangle, widget_sprite::parse_widget_sprite,
|
||||
},
|
||||
};
|
||||
use ouroboros::self_referencing;
|
||||
@@ -95,13 +94,16 @@ impl ParserState {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fetch_widget(&self, state: &LayoutState, id: &str) -> anyhow::Result<Widget> {
|
||||
pub fn fetch_widget(&self, state: &LayoutState, id: &str) -> anyhow::Result<WidgetPair> {
|
||||
let widget_id = self.get_widget_id(id)?;
|
||||
let widget = state
|
||||
.widgets
|
||||
.get(widget_id)
|
||||
.ok_or_else(|| anyhow::anyhow!("fetch_widget({}): widget not found", id))?;
|
||||
Ok(widget.clone())
|
||||
Ok(WidgetPair {
|
||||
id: widget_id,
|
||||
widget: widget.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn process_template<U1, U2>(
|
||||
@@ -121,9 +123,9 @@ impl ParserState {
|
||||
layout,
|
||||
listeners,
|
||||
ids: Default::default(),
|
||||
macro_attribs: self.macro_attribs.clone(), // FIXME: prevent copying
|
||||
var_map: self.var_map.clone(), // FIXME: prevent copying
|
||||
components: self.components.clone(), // FIXME: prevent copying
|
||||
macro_attribs: self.macro_attribs.clone(), // FIXME: prevent copying
|
||||
var_map: self.var_map.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(),
|
||||
doc_params,
|
||||
@@ -135,13 +137,7 @@ impl ParserState {
|
||||
template_parameters: template_parameters.clone(), // FIXME: prevent copying
|
||||
};
|
||||
|
||||
parse_widget_other_internal(
|
||||
&template.clone(),
|
||||
template_parameters,
|
||||
&file,
|
||||
&mut ctx,
|
||||
widget_id,
|
||||
)?;
|
||||
parse_widget_other_internal(&template.clone(), template_parameters, &file, &mut ctx, widget_id)?;
|
||||
|
||||
// FIXME?
|
||||
ctx.ids.into_iter().for_each(|(id, key)| {
|
||||
@@ -203,19 +199,11 @@ pub fn parse_color_hex(html_hex: &str) -> Option<drawing::Color> {
|
||||
None
|
||||
}
|
||||
|
||||
fn get_tag_by_name<'a>(
|
||||
node: &roxmltree::Node<'a, 'a>,
|
||||
name: &str,
|
||||
) -> Option<roxmltree::Node<'a, 'a>> {
|
||||
node
|
||||
.children()
|
||||
.find(|&child| child.tag_name().name() == name)
|
||||
fn get_tag_by_name<'a>(node: &roxmltree::Node<'a, 'a>, name: &str) -> Option<roxmltree::Node<'a, 'a>> {
|
||||
node.children().find(|&child| child.tag_name().name() == name)
|
||||
}
|
||||
|
||||
fn require_tag_by_name<'a>(
|
||||
node: &roxmltree::Node<'a, 'a>,
|
||||
name: &str,
|
||||
) -> anyhow::Result<roxmltree::Node<'a, 'a>> {
|
||||
fn require_tag_by_name<'a>(node: &roxmltree::Node<'a, 'a>, name: &str) -> anyhow::Result<roxmltree::Node<'a, 'a>> {
|
||||
get_tag_by_name(node, name).ok_or_else(|| anyhow::anyhow!("Tag \"{}\" not found", name))
|
||||
}
|
||||
|
||||
@@ -332,8 +320,7 @@ fn parse_widget_other<'a, U1, U2>(
|
||||
return Ok(()); // not critical
|
||||
};
|
||||
|
||||
let template_parameters: HashMap<Rc<str>, Rc<str>> =
|
||||
iter_attribs(file, ctx, &node, false).collect();
|
||||
let template_parameters: HashMap<Rc<str>, Rc<str>> = iter_attribs(file, ctx, &node, false).collect();
|
||||
|
||||
parse_widget_other_internal(&template.clone(), template_parameters, file, ctx, parent_id)
|
||||
}
|
||||
@@ -350,11 +337,7 @@ fn parse_tag_include<'a, U1, U2>(
|
||||
#[allow(clippy::single_match)]
|
||||
match key {
|
||||
"src" => {
|
||||
let mut new_path = file
|
||||
.path
|
||||
.parent()
|
||||
.unwrap_or_else(|| Path::new("/"))
|
||||
.to_path_buf();
|
||||
let mut new_path = file.path.parent().unwrap_or_else(|| Path::new("/")).to_path_buf();
|
||||
new_path.push(value);
|
||||
|
||||
let (new_file, node_layout) = get_doc_from_path(ctx, &new_path)?;
|
||||
@@ -443,10 +426,7 @@ fn process_attrib<'a, U1, U2>(
|
||||
},
|
||||
)
|
||||
} else {
|
||||
(
|
||||
Rc::from(key),
|
||||
replace_vars(value, &file.template_parameters),
|
||||
)
|
||||
(Rc::from(key), replace_vars(value, &file.template_parameters))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,11 +481,7 @@ fn parse_tag_theme<'a, U1, U2>(ctx: &mut ParserContext<U1, U2>, node: roxmltree:
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_tag_template<U1, U2>(
|
||||
file: &ParserFile,
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
node: roxmltree::Node<'_, '_>,
|
||||
) {
|
||||
fn parse_tag_template<U1, U2>(file: &ParserFile, ctx: &mut ParserContext<U1, U2>, node: roxmltree::Node<'_, '_>) {
|
||||
let mut template_name: Option<Rc<str>> = None;
|
||||
|
||||
let attribs: Vec<_> = iter_attribs(file, ctx, &node, false).collect();
|
||||
@@ -535,11 +511,7 @@ fn parse_tag_template<U1, U2>(
|
||||
);
|
||||
}
|
||||
|
||||
fn parse_tag_macro<U1, U2>(
|
||||
file: &ParserFile,
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
node: roxmltree::Node<'_, '_>,
|
||||
) {
|
||||
fn parse_tag_macro<U1, U2>(file: &ParserFile, ctx: &mut ParserContext<U1, U2>, node: roxmltree::Node<'_, '_>) {
|
||||
let mut macro_name: Option<Rc<str>> = None;
|
||||
|
||||
let attribs: Vec<_> = iter_attribs(file, ctx, &node, true).collect();
|
||||
@@ -563,12 +535,7 @@ fn parse_tag_macro<U1, U2>(
|
||||
return;
|
||||
};
|
||||
|
||||
ctx.macro_attribs.insert(
|
||||
name,
|
||||
MacroAttribs {
|
||||
attribs: macro_attribs,
|
||||
},
|
||||
);
|
||||
ctx.macro_attribs.insert(name, MacroAttribs { attribs: macro_attribs });
|
||||
}
|
||||
|
||||
fn process_component<'a, U1, U2>(
|
||||
@@ -583,11 +550,7 @@ fn process_component<'a, U1, U2>(
|
||||
#[allow(clippy::single_match)]
|
||||
match key.as_ref() {
|
||||
"id" => {
|
||||
if ctx
|
||||
.components_id_map
|
||||
.insert(value.clone(), component.weak())
|
||||
.is_some()
|
||||
{
|
||||
if ctx.components_id_map.insert(value.clone(), component.weak()).is_some() {
|
||||
log::warn!("duplicate component ID \"{value}\" in the same layout file!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ use crate::{
|
||||
any::AnyTrait,
|
||||
drawing,
|
||||
event::{
|
||||
self, CallbackData, CallbackDataCommon, CallbackMetadata, Event, EventAlterables,
|
||||
EventListenerKind, EventListenerVec, MouseWheelEvent,
|
||||
self, CallbackData, CallbackDataCommon, CallbackMetadata, Event, EventAlterables, EventListenerKind,
|
||||
EventListenerVec, MouseWheelEvent,
|
||||
},
|
||||
layout::{Layout, LayoutState, WidgetID},
|
||||
transform_stack::TransformStack,
|
||||
@@ -138,8 +138,8 @@ impl EventParams<'_> {
|
||||
pub enum EventResult {
|
||||
Pass, // widget acknowledged it and allows the event to pass to the children
|
||||
Consumed, // widget triggered an action, do not pass to children
|
||||
Outside, // widget acknowledged this event but ignores it due the fact the mouse is not hovered over it
|
||||
Unused, // widget doesn't have any events attached
|
||||
Outside, // widget acknowledged this event but ignores it due the fact the mouse is not hovered over it
|
||||
Unused, // widget doesn't have any events attached
|
||||
}
|
||||
|
||||
fn get_scroll_enabled(style: &taffy::Style) -> (bool, bool) {
|
||||
@@ -223,12 +223,7 @@ impl WidgetState {
|
||||
self.obj.draw(state, params);
|
||||
}
|
||||
|
||||
pub fn draw_scrollbars(
|
||||
&mut self,
|
||||
state: &mut DrawState,
|
||||
params: &DrawParams,
|
||||
info: &ScrollbarInfo,
|
||||
) {
|
||||
pub fn draw_scrollbars(&mut self, state: &mut DrawState, params: &DrawParams, info: &ScrollbarInfo) {
|
||||
let (enabled_horiz, enabled_vert) = get_scroll_enabled(params.style);
|
||||
if !enabled_horiz && !enabled_vert {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user