refactor components_by_widget_id

This commit is contained in:
galister 2026-07-13 20:47:01 +09:00
parent fd8a327395
commit acaabead52
7 changed files with 48 additions and 42 deletions

View File

@ -206,7 +206,7 @@ impl<S: 'static> GuiPanel<S> {
setup_custom_label::<S>(&mut self.layout, &self.parser_state, elem, app);
} else if let Ok(button) = self
.parser_state
.fetch_component_from_widget_id_as::<ComponentButton>(elem.widget_id)
.fetch_component_from_widget_id_as::<ComponentButton>(&self.layout.state, elem.widget_id)
{
setup_custom_button::<S>(
&mut self.layout,

View File

@ -373,7 +373,7 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
let on_custom_attrib: OnCustomAttribFunc = Box::new(move |layout, parser, attribs, _app| {
let Ok(button) =
parser.fetch_component_from_widget_id_as::<ComponentButton>(attribs.widget_id)
parser.fetch_component_from_widget_id_as::<ComponentButton>(&layout.state, attribs.widget_id)
else {
return;
};

View File

@ -205,7 +205,7 @@ impl WvrWindowBackend {
let on_custom_attrib: OnCustomAttribFunc =
Box::new(move |layout, parser, attribs, _app| {
let Ok(button) =
parser.fetch_component_from_widget_id_as::<ComponentButton>(attribs.widget_id)
parser.fetch_component_from_widget_id_as::<ComponentButton>(&layout.state, attribs.widget_id)
else {
return;
};

View File

@ -96,7 +96,7 @@ pub fn create_whisper(
let on_custom_attrib: OnCustomAttribFunc = Box::new(move |layout, parser, attribs, _app| {
let Ok(button) =
parser.fetch_component_from_widget_id_as::<ComponentButton>(attribs.widget_id)
parser.fetch_component_from_widget_id_as::<ComponentButton>(&layout.state, attribs.widget_id)
else {
return;
};

View File

@ -128,6 +128,7 @@ pub struct LayoutState {
pub widgets: WidgetMap,
pub nodes: WidgetNodeMap,
pub tree: taffy::tree::TaffyTree<WidgetID>,
pub components_by_widget_id: SecondaryMap<WidgetID, ComponentWeak>,
}
pub struct ModifyLayoutStateData<'a> {
@ -553,6 +554,7 @@ impl Layout {
nodes: WidgetNodeMap::default(),
globals,
theme: params.theme,
components_by_widget_id: SecondaryMap::default(),
};
let size = if params.resize_to_parent {
@ -989,4 +991,27 @@ impl LayoutState {
pub fn get_widget_style(&self, id: WidgetID) -> Option<&taffy::Style> {
self.get_node_style(*self.nodes.get(id)?)
}
pub fn fetch_component_by_widget_id(&self, widget_id: WidgetID) -> anyhow::Result<Component> {
let Some(weak) = self.components_by_widget_id.get(widget_id) else {
anyhow::bail!("Component by widget ID \"{widget_id:?}\" doesn't exist");
};
let Some(component) = weak.upgrade() else {
anyhow::bail!("Component by widget ID \"{widget_id:?}\" has disappeared");
};
Ok(Component(component))
}
pub fn fetch_component_from_widget_id_as<T: 'static>(&self, widget_id: WidgetID) -> anyhow::Result<Rc<T>> {
let component = self.fetch_component_by_widget_id(widget_id)?;
if !(*component.0).as_any().is::<T>() {
anyhow::bail!("fetch_component_from_widget_id_as({widget_id:?}): type not matching");
}
// safety: we just checked the type
unsafe { Ok(Rc::from_raw(Rc::into_raw(component.0).cast())) }
}
}

View File

@ -3,7 +3,7 @@ use crate::{
i18n::Translation,
layout::WidgetID,
parser::{
AttribPair, Fetchable, ParserContext,
AttribPair, ParserContext,
helpers::{TooltipAttribs, parse_attrib_tooltip},
process_component,
style::parse_style,
@ -66,7 +66,8 @@ pub fn parse_component_checkbox(
while let Some(parent_id) = maybe_parent_id {
if let Ok(radio) = ctx
.data_local
.layout
.state
.fetch_component_from_widget_id_as::<ComponentRadioGroup>(parent_id)
{
radio_group = Some(radio);

View File

@ -79,7 +79,6 @@ struct ParserFile {
#[derive(Default, Clone)]
pub struct ParserData {
pub components_by_id: HashMap<Rc<str>, ComponentWeak>,
pub components_by_widget_id: HashMap<WidgetID, ComponentWeak>,
pub components: Vec<Component>,
pub ids: HashMap<Rc<str>, WidgetID>,
pub templates: HashMap<Rc<str>, Rc<Template>>,
@ -91,14 +90,14 @@ pub trait Fetchable {
/// Return a component by its string ID
fn fetch_component_by_id(&self, id: &str) -> anyhow::Result<Component>;
/// Return a component by the ID of the widget that owns it
fn fetch_component_by_widget_id(&self, widget_id: WidgetID) -> anyhow::Result<Component>;
/// Fetch a component by widget ID (returns Component)
fn fetch_component_by_widget_id(&self, state: &LayoutState, widget_id: WidgetID) -> anyhow::Result<Component>;
/// Fetch a component by string ID and downcast it to a concrete component type `T` (see `components/mod.rs`)
fn fetch_component_as<T: 'static>(&self, id: &str) -> anyhow::Result<Rc<T>>;
/// Fetch a component by widget ID and downcast it to a concrete component type `T` (see `components/mod.rs`)
fn fetch_component_from_widget_id_as<T: 'static>(&self, widget_id: WidgetID) -> anyhow::Result<Rc<T>>;
fn fetch_component_from_widget_id_as<T: 'static>(&self, state: &LayoutState, widget_id: WidgetID) -> anyhow::Result<Rc<T>>;
/// Return a widget by its string ID
fn get_widget_id(&self, id: &str) -> anyhow::Result<WidgetID>;
@ -137,7 +136,6 @@ impl ParserData {
let ids = std::mem::take(&mut from.ids);
let components = std::mem::take(&mut from.components);
let components_by_id = std::mem::take(&mut from.components_by_id);
let components_by_widget_id = std::mem::take(&mut from.components_by_widget_id);
for (id, key) in ids {
self.ids.insert(id, key);
@ -150,10 +148,6 @@ impl ParserData {
for (k, v) in components_by_id {
self.components_by_id.insert(k, v);
}
for (k, v) in components_by_widget_id {
self.components_by_widget_id.insert(k, v);
}
}
}
@ -170,16 +164,12 @@ impl Fetchable for ParserData {
Ok(Component(component))
}
fn fetch_component_by_widget_id(&self, widget_id: WidgetID) -> anyhow::Result<Component> {
let Some(weak) = self.components_by_widget_id.get(&widget_id) else {
anyhow::bail!("Component by widget ID \"{widget_id:?}\" doesn't exist");
};
fn fetch_component_by_widget_id(&self, state: &LayoutState, widget_id: WidgetID) -> anyhow::Result<Component> {
state.fetch_component_by_widget_id(widget_id)
}
let Some(component) = weak.upgrade() else {
anyhow::bail!("Component by widget ID \"{widget_id:?}\" has disappeared");
};
Ok(Component(component))
fn fetch_component_from_widget_id_as<T: 'static>(&self, state: &LayoutState, widget_id: WidgetID) -> anyhow::Result<Rc<T>> {
state.fetch_component_from_widget_id_as(widget_id)
}
fn fetch_component_as<T: 'static>(&self, id: &str) -> anyhow::Result<Rc<T>> {
@ -193,17 +183,6 @@ impl Fetchable for ParserData {
unsafe { Ok(Rc::from_raw(Rc::into_raw(component.0).cast())) }
}
fn fetch_component_from_widget_id_as<T: 'static>(&self, widget_id: WidgetID) -> anyhow::Result<Rc<T>> {
let component = self.fetch_component_by_widget_id(widget_id)?;
if !(*component.0).as_any().is::<T>() {
anyhow::bail!("fetch_component_by_widget_id({widget_id:?}): type not matching");
}
// safety: we just checked the type
unsafe { Ok(Rc::from_raw(Rc::into_raw(component.0).cast())) }
}
fn get_widget_id(&self, id: &str) -> anyhow::Result<WidgetID> {
match self.ids.get(id) {
Some(id) => Ok(*id),
@ -398,18 +377,18 @@ impl Fetchable for ParserState {
self.data.fetch_component_by_id(id)
}
fn fetch_component_by_widget_id(&self, widget_id: WidgetID) -> anyhow::Result<Component> {
self.data.fetch_component_by_widget_id(widget_id)
fn fetch_component_by_widget_id(&self, state: &LayoutState, widget_id: WidgetID) -> anyhow::Result<Component> {
self.data.fetch_component_by_widget_id(state, widget_id)
}
fn fetch_component_from_widget_id_as<T: 'static>(&self, state: &LayoutState, widget_id: WidgetID) -> anyhow::Result<Rc<T>> {
self.data.fetch_component_from_widget_id_as(state, widget_id)
}
fn fetch_component_as<T: 'static>(&self, id: &str) -> anyhow::Result<Rc<T>> {
self.data.fetch_component_as(id)
}
fn fetch_component_from_widget_id_as<T: 'static>(&self, widget_id: WidgetID) -> anyhow::Result<Rc<T>> {
self.data.fetch_component_from_widget_id_as(widget_id)
}
fn get_widget_id(&self, id: &str) -> anyhow::Result<WidgetID> {
self.data.get_widget_id(id)
}
@ -499,7 +478,8 @@ impl ParserContext<'_> {
fn insert_component(&mut self, widget_id: WidgetID, component: Component, id: Option<Rc<str>>) {
self
.data_local
.layout
.state
.components_by_widget_id
.insert(widget_id, component.weak());