mirror of https://github.com/linebender/xilem
Create WidgetArenaMut type and start refactor of pass internals. (#1197)
This is the first step of a refactor where widgets, widget states and widget properties will be stored in the same object. So we would end up with a type like this: ```rust struct WidgetArenaNode { pub(crate) widget: Box<dyn Widget>, pub(crate) state: WidgetState, pub(crate) properties: AnyMap, } ``` and WidgetArena might look like: ```rust pub(crate) struct WidgetArena { pub(crate) nodes: TreeArena<WidgetArenaNode>, } ``` Doing so without making an absolutely unreadable diff is tough, so I split the work into several PRs. This one just moves code around to make future diffs shorter.
This commit is contained in:
parent
38e3d9a564
commit
69e5f2b808
|
@ -16,8 +16,8 @@ use vello::kurbo::{Rect, Size};
|
|||
|
||||
use crate::core::{
|
||||
AccessEvent, BrushIndex, DefaultProperties, ErasedAction, Handled, Ime, PointerEvent,
|
||||
PropertiesRef, QueryCtx, ResizeDirection, TextEvent, Widget, WidgetArena, WidgetId, WidgetMut,
|
||||
WidgetPod, WidgetRef, WidgetState, WindowEvent,
|
||||
PropertiesRef, QueryCtx, ResizeDirection, TextEvent, Widget, WidgetArena, WidgetArenaMut,
|
||||
WidgetArenaRef, WidgetId, WidgetMut, WidgetPod, WidgetRef, WidgetState, WindowEvent,
|
||||
};
|
||||
use crate::passes::accessibility::run_accessibility_pass;
|
||||
use crate::passes::anim::run_update_anim_pass;
|
||||
|
@ -459,31 +459,8 @@ impl RenderRoot {
|
|||
// --- MARK: ACCESS WIDGETS
|
||||
/// Get a [`WidgetRef`] to the root widget.
|
||||
pub fn get_root_widget(&self) -> WidgetRef<'_, dyn Widget> {
|
||||
let root_state_token = self.widget_arena.states.roots();
|
||||
let root_widget_token = self.widget_arena.widgets.roots();
|
||||
let root_properties_token = self.widget_arena.properties.roots();
|
||||
let state_ref = root_state_token
|
||||
.into_item(self.root.id())
|
||||
.expect("root widget not in widget tree");
|
||||
let widget_ref = root_widget_token
|
||||
.into_item(self.root.id())
|
||||
.expect("root widget not in widget tree");
|
||||
let properties_ref = root_properties_token
|
||||
.into_item(self.root.id())
|
||||
.expect("root widget not in widget tree");
|
||||
let widget = &**widget_ref.item;
|
||||
let ctx = QueryCtx {
|
||||
global_state: &self.global_state,
|
||||
widget_state_children: state_ref.children,
|
||||
widget_children: widget_ref.children,
|
||||
widget_state: state_ref.item,
|
||||
properties: PropertiesRef {
|
||||
map: properties_ref.item,
|
||||
default_map: self.default_properties.for_widget(widget.type_id()),
|
||||
},
|
||||
properties_children: properties_ref.children,
|
||||
};
|
||||
WidgetRef { ctx, widget }
|
||||
self.get_widget(self.root.id())
|
||||
.expect("root widget not in widget tree")
|
||||
}
|
||||
|
||||
/// Get a [`WidgetRef`] to a specific widget.
|
||||
|
@ -500,17 +477,23 @@ impl RenderRoot {
|
|||
.find(id)
|
||||
.expect("found state but not properties");
|
||||
|
||||
let children = WidgetArenaRef {
|
||||
widget_children: widget_ref.children,
|
||||
widget_state_children: state_ref.children,
|
||||
properties_children: properties_ref.children,
|
||||
};
|
||||
let widget = &**widget_ref.item;
|
||||
let state = state_ref.item;
|
||||
let properties = properties_ref.item;
|
||||
|
||||
let ctx = QueryCtx {
|
||||
global_state: &self.global_state,
|
||||
widget_state_children: state_ref.children,
|
||||
widget_children: widget_ref.children,
|
||||
widget_state: state_ref.item,
|
||||
widget_state: state,
|
||||
properties: PropertiesRef {
|
||||
map: properties_ref.item,
|
||||
map: properties,
|
||||
default_map: self.default_properties.for_widget(widget.type_id()),
|
||||
},
|
||||
properties_children: properties_ref.children,
|
||||
children,
|
||||
};
|
||||
Some(WidgetRef { ctx, widget })
|
||||
}
|
||||
|
@ -628,25 +611,27 @@ impl RenderRoot {
|
|||
|
||||
pub(crate) fn request_render_all(&mut self) {
|
||||
fn request_render_all_in(
|
||||
mut widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
state: ArenaMut<'_, WidgetState>,
|
||||
properties: ArenaMut<'_, AnyMap>,
|
||||
) {
|
||||
state.item.needs_paint = true;
|
||||
state.item.needs_accessibility = true;
|
||||
state.item.request_paint = true;
|
||||
state.item.request_accessibility = true;
|
||||
let children = WidgetArenaMut {
|
||||
widget_children: widget.children,
|
||||
widget_state_children: state.children,
|
||||
properties_children: properties.children,
|
||||
};
|
||||
let widget = &mut **widget.item;
|
||||
let state = state.item;
|
||||
|
||||
let id = state.item.id;
|
||||
recurse_on_children(
|
||||
id,
|
||||
widget.reborrow_mut(),
|
||||
state.children,
|
||||
properties.children,
|
||||
|widget, state, properties| {
|
||||
request_render_all_in(widget, state, properties);
|
||||
},
|
||||
);
|
||||
state.needs_paint = true;
|
||||
state.needs_accessibility = true;
|
||||
state.request_paint = true;
|
||||
state.request_accessibility = true;
|
||||
|
||||
let id = state.id;
|
||||
recurse_on_children(id, widget, children, |widget, state, properties| {
|
||||
request_render_all_in(widget, state, properties);
|
||||
});
|
||||
}
|
||||
|
||||
let (root_widget, root_state, root_properties) =
|
||||
|
|
|
@ -10,19 +10,18 @@ use anymore::AnyDebug;
|
|||
use dpi::{LogicalPosition, PhysicalPosition};
|
||||
use parley::{FontContext, LayoutContext};
|
||||
use tracing::{trace, warn};
|
||||
use tree_arena::{ArenaMutList, ArenaRefList};
|
||||
use vello::kurbo::{Affine, Insets, Point, Rect, Size, Vec2};
|
||||
|
||||
use crate::app::{MutateCallback, RenderRootSignal, RenderRootState};
|
||||
use crate::core::{
|
||||
AllowRawMut, BoxConstraints, BrushIndex, CreateWidget, DefaultProperties, ErasedAction,
|
||||
FromDynWidget, PropertiesMut, PropertiesRef, ResizeDirection, Widget, WidgetId, WidgetMut,
|
||||
WidgetPod, WidgetRef, WidgetState,
|
||||
FromDynWidget, PropertiesMut, PropertiesRef, ResizeDirection, Widget, WidgetArenaMut,
|
||||
WidgetArenaRef, WidgetId, WidgetMut, WidgetPod, WidgetRef, WidgetState,
|
||||
};
|
||||
use crate::debug_panic;
|
||||
use crate::passes::layout::run_layout_on;
|
||||
use crate::peniko::Color;
|
||||
use crate::util::{AnyMap, get_debug_color};
|
||||
use crate::util::get_debug_color;
|
||||
|
||||
// Note - Most methods defined in this file revolve around `WidgetState` fields.
|
||||
// Consider reading `WidgetState` documentation (especially the documented naming scheme)
|
||||
|
@ -52,10 +51,8 @@ pub struct MutateCtx<'a> {
|
|||
pub(crate) global_state: &'a mut RenderRootState,
|
||||
pub(crate) parent_widget_state: Option<&'a mut WidgetState>,
|
||||
pub(crate) widget_state: &'a mut WidgetState,
|
||||
pub(crate) widget_state_children: ArenaMutList<'a, WidgetState>,
|
||||
pub(crate) widget_children: ArenaMutList<'a, Box<dyn Widget>>,
|
||||
pub(crate) properties: PropertiesMut<'a>,
|
||||
pub(crate) properties_children: ArenaMutList<'a, AnyMap>,
|
||||
pub(crate) children: WidgetArenaMut<'a>,
|
||||
}
|
||||
|
||||
/// A context provided inside of [`WidgetRef`].
|
||||
|
@ -65,19 +62,15 @@ pub struct MutateCtx<'a> {
|
|||
pub struct QueryCtx<'a> {
|
||||
pub(crate) global_state: &'a RenderRootState,
|
||||
pub(crate) widget_state: &'a WidgetState,
|
||||
pub(crate) widget_state_children: ArenaRefList<'a, WidgetState>,
|
||||
pub(crate) widget_children: ArenaRefList<'a, Box<dyn Widget>>,
|
||||
pub(crate) properties: PropertiesRef<'a>,
|
||||
pub(crate) properties_children: ArenaRefList<'a, AnyMap>,
|
||||
pub(crate) children: WidgetArenaRef<'a>,
|
||||
}
|
||||
|
||||
/// A context provided to event-handling [`Widget`] methods.
|
||||
pub struct EventCtx<'a> {
|
||||
pub(crate) global_state: &'a mut RenderRootState,
|
||||
pub(crate) widget_state: &'a mut WidgetState,
|
||||
pub(crate) widget_state_children: ArenaMutList<'a, WidgetState>,
|
||||
pub(crate) widget_children: ArenaMutList<'a, Box<dyn Widget>>,
|
||||
pub(crate) properties_children: ArenaMutList<'a, AnyMap>,
|
||||
pub(crate) children: WidgetArenaMut<'a>,
|
||||
pub(crate) target: WidgetId,
|
||||
pub(crate) allow_pointer_capture: bool,
|
||||
pub(crate) is_handled: bool,
|
||||
|
@ -85,9 +78,7 @@ pub struct EventCtx<'a> {
|
|||
|
||||
/// A context provided to the [`Widget::register_children`] method.
|
||||
pub struct RegisterCtx<'a> {
|
||||
pub(crate) widget_state_children: ArenaMutList<'a, WidgetState>,
|
||||
pub(crate) widget_children: ArenaMutList<'a, Box<dyn Widget>>,
|
||||
pub(crate) properties_children: ArenaMutList<'a, AnyMap>,
|
||||
pub(crate) children: WidgetArenaMut<'a>,
|
||||
#[cfg(debug_assertions)]
|
||||
pub(crate) registered_ids: Vec<WidgetId>,
|
||||
}
|
||||
|
@ -96,9 +87,7 @@ pub struct RegisterCtx<'a> {
|
|||
pub struct UpdateCtx<'a> {
|
||||
pub(crate) global_state: &'a mut RenderRootState,
|
||||
pub(crate) widget_state: &'a mut WidgetState,
|
||||
pub(crate) widget_state_children: ArenaMutList<'a, WidgetState>,
|
||||
pub(crate) widget_children: ArenaMutList<'a, Box<dyn Widget>>,
|
||||
pub(crate) properties_children: ArenaMutList<'a, AnyMap>,
|
||||
pub(crate) children: WidgetArenaMut<'a>,
|
||||
}
|
||||
|
||||
// TODO - Change this once other layout methods are added.
|
||||
|
@ -106,9 +95,7 @@ pub struct UpdateCtx<'a> {
|
|||
pub struct LayoutCtx<'a> {
|
||||
pub(crate) global_state: &'a mut RenderRootState,
|
||||
pub(crate) widget_state: &'a mut WidgetState,
|
||||
pub(crate) widget_state_children: ArenaMutList<'a, WidgetState>,
|
||||
pub(crate) widget_children: ArenaMutList<'a, Box<dyn Widget>>,
|
||||
pub(crate) properties_children: ArenaMutList<'a, AnyMap>,
|
||||
pub(crate) children: WidgetArenaMut<'a>,
|
||||
pub(crate) default_properties: &'a DefaultProperties,
|
||||
}
|
||||
|
||||
|
@ -116,16 +103,14 @@ pub struct LayoutCtx<'a> {
|
|||
pub struct ComposeCtx<'a> {
|
||||
pub(crate) global_state: &'a mut RenderRootState,
|
||||
pub(crate) widget_state: &'a mut WidgetState,
|
||||
pub(crate) widget_state_children: ArenaMutList<'a, WidgetState>,
|
||||
pub(crate) widget_children: ArenaMutList<'a, Box<dyn Widget>>,
|
||||
pub(crate) children: WidgetArenaMut<'a>,
|
||||
}
|
||||
|
||||
/// A context passed to [`Widget::paint`] method.
|
||||
pub struct PaintCtx<'a> {
|
||||
pub(crate) global_state: &'a mut RenderRootState,
|
||||
pub(crate) widget_state: &'a WidgetState,
|
||||
pub(crate) widget_state_children: ArenaMutList<'a, WidgetState>,
|
||||
pub(crate) widget_children: ArenaMutList<'a, Box<dyn Widget>>,
|
||||
pub(crate) children: WidgetArenaMut<'a>,
|
||||
pub(crate) debug_paint: bool,
|
||||
}
|
||||
|
||||
|
@ -133,9 +118,7 @@ pub struct PaintCtx<'a> {
|
|||
pub struct AccessCtx<'a> {
|
||||
pub(crate) global_state: &'a mut RenderRootState,
|
||||
pub(crate) widget_state: &'a WidgetState,
|
||||
pub(crate) widget_state_children: ArenaMutList<'a, WidgetState>,
|
||||
pub(crate) widget_children: ArenaMutList<'a, Box<dyn Widget>>,
|
||||
pub(crate) properties_children: ArenaMutList<'a, AnyMap>,
|
||||
pub(crate) children: WidgetArenaMut<'a>,
|
||||
pub(crate) tree_update: &'a mut TreeUpdate,
|
||||
pub(crate) rebuild_all: bool,
|
||||
}
|
||||
|
@ -161,6 +144,7 @@ impl_context_method!(
|
|||
/// Helper method to get a direct reference to a child widget from its `WidgetPod`.
|
||||
fn get_child<Child: Widget>(&self, child: &'_ WidgetPod<Child>) -> &'_ Child {
|
||||
let child_ref = self
|
||||
.children
|
||||
.widget_children
|
||||
.item(child.id())
|
||||
.expect("get_child: child not found");
|
||||
|
@ -173,6 +157,7 @@ impl_context_method!(
|
|||
/// Helper method to get a direct reference to a child widget from its `WidgetPod`.
|
||||
fn get_child_dyn(&self, child: &'_ WidgetPod<impl Widget + ?Sized>) -> &'_ dyn Widget {
|
||||
let child_ref = self
|
||||
.children
|
||||
.widget_children
|
||||
.item(child.id())
|
||||
.expect("get_child: child not found");
|
||||
|
@ -183,6 +168,7 @@ impl_context_method!(
|
|||
/// Helper method to get a direct reference to a child widget's `WidgetState` from its `WidgetPod`.
|
||||
fn get_child_state(&self, child: &'_ WidgetPod<impl Widget + ?Sized>) -> &'_ WidgetState {
|
||||
let child_state_ref = self
|
||||
.children
|
||||
.widget_state_children
|
||||
.item(child.id())
|
||||
.expect("get_child_state: child not found");
|
||||
|
@ -213,6 +199,7 @@ impl_context_method!(
|
|||
child: &'_ mut WidgetPod<Child>,
|
||||
) -> &'_ mut WidgetState {
|
||||
let child_state_mut = self
|
||||
.children
|
||||
.widget_state_children
|
||||
.item_mut(child.id())
|
||||
.expect("get_child_state_mut: child not found");
|
||||
|
@ -230,28 +217,34 @@ impl MutateCtx<'_> {
|
|||
child: &'c mut WidgetPod<Child>,
|
||||
) -> WidgetMut<'c, Child> {
|
||||
let child_state_mut = self
|
||||
.children
|
||||
.widget_state_children
|
||||
.item_mut(child.id())
|
||||
.expect("get_mut: child not found");
|
||||
let child_mut = self
|
||||
.children
|
||||
.widget_children
|
||||
.item_mut(child.id())
|
||||
.expect("get_mut: child not found");
|
||||
let child_properties = self
|
||||
.children
|
||||
.properties_children
|
||||
.item_mut(child.id())
|
||||
.expect("get_mut: child not found");
|
||||
let children = WidgetArenaMut {
|
||||
widget_state_children: child_state_mut.children,
|
||||
widget_children: child_mut.children,
|
||||
properties_children: child_properties.children,
|
||||
};
|
||||
let child_ctx = MutateCtx {
|
||||
global_state: self.global_state,
|
||||
parent_widget_state: Some(&mut self.widget_state),
|
||||
widget_state: child_state_mut.item,
|
||||
widget_state_children: child_state_mut.children,
|
||||
widget_children: child_mut.children,
|
||||
properties: PropertiesMut {
|
||||
map: child_properties.item,
|
||||
default_map: self.properties.default_map,
|
||||
},
|
||||
properties_children: child_properties.children,
|
||||
children,
|
||||
};
|
||||
WidgetMut {
|
||||
ctx: child_ctx,
|
||||
|
@ -267,10 +260,8 @@ impl MutateCtx<'_> {
|
|||
// It will still be called when the original borrow is dropped.
|
||||
parent_widget_state: None,
|
||||
widget_state: self.widget_state,
|
||||
widget_state_children: self.widget_state_children.reborrow_mut(),
|
||||
widget_children: self.widget_children.reborrow_mut(),
|
||||
properties: self.properties.reborrow_mut(),
|
||||
properties_children: self.properties_children.reborrow_mut(),
|
||||
children: self.children.reborrow_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -278,9 +269,7 @@ impl MutateCtx<'_> {
|
|||
UpdateCtx {
|
||||
global_state: self.global_state,
|
||||
widget_state: self.widget_state,
|
||||
widget_state_children: self.widget_state_children.reborrow_mut(),
|
||||
widget_children: self.widget_children.reborrow_mut(),
|
||||
properties_children: self.properties_children.reborrow_mut(),
|
||||
children: self.children.reborrow_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -300,28 +289,34 @@ impl<'w> QueryCtx<'w> {
|
|||
/// Return a [`WidgetRef`] to a child widget.
|
||||
pub fn get(self, child: WidgetId) -> WidgetRef<'w, dyn Widget> {
|
||||
let child_state = self
|
||||
.children
|
||||
.widget_state_children
|
||||
.into_item(child)
|
||||
.expect("get: child not found");
|
||||
let child_widget = self
|
||||
.children
|
||||
.widget_children
|
||||
.into_item(child)
|
||||
.expect("get: child not found");
|
||||
let child_properties = self
|
||||
.children
|
||||
.properties_children
|
||||
.into_item(child)
|
||||
.expect("get: child not found");
|
||||
let children = WidgetArenaRef {
|
||||
widget_state_children: child_state.children,
|
||||
widget_children: child_widget.children,
|
||||
properties_children: child_properties.children,
|
||||
};
|
||||
|
||||
let ctx = QueryCtx {
|
||||
global_state: self.global_state,
|
||||
widget_state_children: child_state.children,
|
||||
widget_children: child_widget.children,
|
||||
widget_state: child_state.item,
|
||||
properties: PropertiesRef {
|
||||
map: child_properties.item,
|
||||
default_map: self.properties.default_map,
|
||||
},
|
||||
properties_children: child_properties.children,
|
||||
children,
|
||||
};
|
||||
WidgetRef {
|
||||
ctx,
|
||||
|
@ -1100,14 +1095,17 @@ impl_context_method!(MutateCtx<'_>, EventCtx<'_>, UpdateCtx<'_>, {
|
|||
// TODO - Send recursive event to child
|
||||
let id = child.id();
|
||||
let _ = self
|
||||
.children
|
||||
.widget_state_children
|
||||
.remove(id)
|
||||
.expect("remove_child: child not found");
|
||||
let _ = self
|
||||
.children
|
||||
.widget_children
|
||||
.remove(id)
|
||||
.expect("remove_child: child not found");
|
||||
let _ = self
|
||||
.children
|
||||
.properties_children
|
||||
.remove(id)
|
||||
.expect("remove_child: child not found");
|
||||
|
@ -1300,9 +1298,11 @@ impl RegisterCtx<'_> {
|
|||
let id = child.id();
|
||||
let state = WidgetState::new(child.id(), widget.short_type_name(), options);
|
||||
|
||||
self.widget_children.insert(id, widget.as_box_dyn());
|
||||
self.widget_state_children.insert(id, state);
|
||||
self.properties_children.insert(id, properties.map);
|
||||
self.children
|
||||
.widget_children
|
||||
.insert(id, widget.as_box_dyn());
|
||||
self.children.widget_state_children.insert(id, state);
|
||||
self.children.properties_children.insert(id, properties.map);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1347,27 +1347,33 @@ macro_rules! impl_get_raw {
|
|||
's: 'r,
|
||||
{
|
||||
let child_state_mut = self
|
||||
.children
|
||||
.widget_state_children
|
||||
.item_mut(child.id())
|
||||
.expect("get_raw_ref: child not found");
|
||||
let child_mut = self
|
||||
.children
|
||||
.widget_children
|
||||
.item_mut(child.id())
|
||||
.expect("get_raw_ref: child not found");
|
||||
let child_properties = self
|
||||
.children
|
||||
.properties_children
|
||||
.item_mut(child.id())
|
||||
.expect("get_raw_ref: child not found");
|
||||
let children = WidgetArenaMut {
|
||||
widget_state_children: child_state_mut.children,
|
||||
widget_children: child_mut.children,
|
||||
properties_children: child_properties.children,
|
||||
};
|
||||
#[allow(
|
||||
clippy::needless_update,
|
||||
reason = "May be needless in some macro invocations"
|
||||
)]
|
||||
let child_ctx = $SomeCtx {
|
||||
widget_state: child_state_mut.item,
|
||||
widget_state_children: child_state_mut.children,
|
||||
widget_children: child_mut.children,
|
||||
properties_children: child_properties.children,
|
||||
global_state: self.global_state,
|
||||
children,
|
||||
..*self
|
||||
};
|
||||
RawWrapper {
|
||||
|
@ -1388,27 +1394,33 @@ macro_rules! impl_get_raw {
|
|||
's: 'r,
|
||||
{
|
||||
let child_state_mut = self
|
||||
.children
|
||||
.widget_state_children
|
||||
.item_mut(child.id())
|
||||
.expect("get_raw_mut: child not found");
|
||||
let child_mut = self
|
||||
.children
|
||||
.widget_children
|
||||
.item_mut(child.id())
|
||||
.expect("get_raw_mut: child not found");
|
||||
let child_properties = self
|
||||
.children
|
||||
.properties_children
|
||||
.item_mut(child.id())
|
||||
.expect("get_raw_mut: child not found");
|
||||
let children = WidgetArenaMut {
|
||||
widget_state_children: child_state_mut.children,
|
||||
widget_children: child_mut.children,
|
||||
properties_children: child_properties.children,
|
||||
};
|
||||
#[allow(
|
||||
clippy::needless_update,
|
||||
reason = "May be needless in some macro invocations"
|
||||
)]
|
||||
let child_ctx = $SomeCtx {
|
||||
widget_state: child_state_mut.item,
|
||||
widget_state_children: child_state_mut.children,
|
||||
widget_children: child_mut.children,
|
||||
properties_children: child_properties.children,
|
||||
global_state: self.global_state,
|
||||
children,
|
||||
..*self
|
||||
};
|
||||
RawWrapperMut {
|
||||
|
@ -1436,22 +1448,28 @@ impl<'s> AccessCtx<'s> {
|
|||
's: 'r,
|
||||
{
|
||||
let child_state_mut = self
|
||||
.children
|
||||
.widget_state_children
|
||||
.item_mut(child.id())
|
||||
.expect("get_raw_ref: child not found");
|
||||
let child_mut = self
|
||||
.children
|
||||
.widget_children
|
||||
.item_mut(child.id())
|
||||
.expect("get_raw_ref: child not found");
|
||||
let child_properties = self
|
||||
.children
|
||||
.properties_children
|
||||
.item_mut(child.id())
|
||||
.expect("get_raw_ref: child not found");
|
||||
let child_ctx = AccessCtx {
|
||||
widget_state: child_state_mut.item,
|
||||
let children = WidgetArenaMut {
|
||||
widget_state_children: child_state_mut.children,
|
||||
widget_children: child_mut.children,
|
||||
properties_children: child_properties.children,
|
||||
};
|
||||
let child_ctx = AccessCtx {
|
||||
widget_state: child_state_mut.item,
|
||||
children,
|
||||
global_state: self.global_state,
|
||||
tree_update: self.tree_update,
|
||||
rebuild_all: self.rebuild_all,
|
||||
|
|
|
@ -41,7 +41,7 @@ pub use ui_events::pointer::{
|
|||
};
|
||||
pub use ui_events::{ScrollDelta, keyboard, pointer};
|
||||
|
||||
pub(crate) use widget_arena::WidgetArena;
|
||||
pub(crate) use widget_arena::{WidgetArena, WidgetArenaMut, WidgetArenaRef};
|
||||
pub(crate) use widget_pod::CreateWidget;
|
||||
pub(crate) use widget_state::WidgetState;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright 2024 the Xilem Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use tree_arena::{ArenaMut, ArenaRef, TreeArena};
|
||||
use tree_arena::{ArenaMut, ArenaMutList, ArenaRef, ArenaRefList, TreeArena};
|
||||
|
||||
use crate::core::{Widget, WidgetId, WidgetState};
|
||||
use crate::util::AnyMap;
|
||||
|
@ -12,6 +12,19 @@ pub(crate) struct WidgetArena {
|
|||
pub(crate) properties: TreeArena<AnyMap>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) struct WidgetArenaRef<'a> {
|
||||
pub(crate) widget_state_children: ArenaRefList<'a, WidgetState>,
|
||||
pub(crate) widget_children: ArenaRefList<'a, Box<dyn Widget>>,
|
||||
pub(crate) properties_children: ArenaRefList<'a, AnyMap>,
|
||||
}
|
||||
|
||||
pub(crate) struct WidgetArenaMut<'a> {
|
||||
pub(crate) widget_state_children: ArenaMutList<'a, WidgetState>,
|
||||
pub(crate) widget_children: ArenaMutList<'a, Box<dyn Widget>>,
|
||||
pub(crate) properties_children: ArenaMutList<'a, AnyMap>,
|
||||
}
|
||||
|
||||
impl WidgetArena {
|
||||
pub(crate) fn has(&self, widget_id: WidgetId) -> bool {
|
||||
self.widgets.find(widget_id).is_some()
|
||||
|
@ -106,3 +119,22 @@ impl WidgetArena {
|
|||
.expect("get_state_mut: widget state not in widget tree")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> WidgetArenaMut<'a> {
|
||||
#[allow(unused, reason = "May be used later")]
|
||||
pub(crate) fn reborrow(&self) -> WidgetArenaRef<'_> {
|
||||
WidgetArenaRef {
|
||||
widget_state_children: self.widget_state_children.reborrow(),
|
||||
widget_children: self.widget_children.reborrow(),
|
||||
properties_children: self.properties_children.reborrow(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn reborrow_mut(&mut self) -> WidgetArenaMut<'_> {
|
||||
WidgetArenaMut {
|
||||
widget_state_children: self.widget_state_children.reborrow_mut(),
|
||||
widget_children: self.widget_children.reborrow_mut(),
|
||||
properties_children: self.properties_children.reborrow_mut(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::ops::Deref;
|
|||
use smallvec::SmallVec;
|
||||
use vello::kurbo::Point;
|
||||
|
||||
use crate::core::{PropertiesRef, Property, QueryCtx, Widget, WidgetId};
|
||||
use crate::core::{PropertiesRef, Property, QueryCtx, Widget, WidgetArenaRef, WidgetId};
|
||||
|
||||
/// A rich reference to a [`Widget`].
|
||||
///
|
||||
|
@ -117,42 +117,43 @@ impl<'w, W: Widget + ?Sized> WidgetRef<'w, W> {
|
|||
.children_ids()
|
||||
.iter()
|
||||
.map(|&id| {
|
||||
let Some(state_ref) = self.ctx.widget_state_children.into_item(id) else {
|
||||
let Some(state_ref) = self.ctx.children.widget_state_children.into_item(id) else {
|
||||
panic!(
|
||||
"Error in '{}' #{parent_id}: child #{id} has not been added to tree",
|
||||
self.widget.short_type_name()
|
||||
);
|
||||
};
|
||||
let Some(widget_ref) = self.ctx.widget_children.into_item(id) else {
|
||||
let Some(widget_ref) = self.ctx.children.widget_children.into_item(id) else {
|
||||
panic!(
|
||||
"Error in '{}' #{parent_id}: child #{id} has not been added to tree",
|
||||
self.widget.short_type_name()
|
||||
);
|
||||
};
|
||||
let Some(properties_ref) = self.ctx.properties_children.into_item(id) else {
|
||||
let Some(properties_ref) = self.ctx.children.properties_children.into_item(id)
|
||||
else {
|
||||
panic!(
|
||||
"Error in '{}' #{parent_id}: child #{id} has not been added to tree",
|
||||
self.widget.short_type_name()
|
||||
);
|
||||
};
|
||||
|
||||
// Box<dyn Widget> -> &dyn Widget
|
||||
// Without this step, the type of `WidgetRef::widget` would be
|
||||
// `&Box<dyn Widget> as &dyn Widget`, which would be an additional layer
|
||||
// of indirection.
|
||||
let widget = widget_ref.item;
|
||||
let widget: &dyn Widget = &**widget;
|
||||
let children = WidgetArenaRef {
|
||||
widget_children: widget_ref.children,
|
||||
widget_state_children: state_ref.children,
|
||||
properties_children: properties_ref.children,
|
||||
};
|
||||
let widget = &**widget_ref.item;
|
||||
let state = state_ref.item;
|
||||
let properties = properties_ref.item;
|
||||
|
||||
let ctx = QueryCtx {
|
||||
global_state: self.ctx.global_state,
|
||||
widget_state_children: state_ref.children,
|
||||
widget_children: widget_ref.children,
|
||||
widget_state: state_ref.item,
|
||||
widget_state: state,
|
||||
properties: PropertiesRef {
|
||||
map: properties_ref.item,
|
||||
map: properties,
|
||||
default_map: self.ctx.properties.default_map,
|
||||
},
|
||||
properties_children: properties_ref.children,
|
||||
children,
|
||||
};
|
||||
|
||||
WidgetRef { ctx, widget }
|
||||
|
|
|
@ -7,7 +7,9 @@ use tree_arena::ArenaMut;
|
|||
use vello::kurbo::Rect;
|
||||
|
||||
use crate::app::{RenderRoot, RenderRootState};
|
||||
use crate::core::{AccessCtx, DefaultProperties, PropertiesRef, Widget, WidgetId, WidgetState};
|
||||
use crate::core::{
|
||||
AccessCtx, DefaultProperties, PropertiesRef, Widget, WidgetArenaMut, WidgetId, WidgetState,
|
||||
};
|
||||
use crate::passes::{enter_span_if, recurse_on_children};
|
||||
use crate::util::AnyMap;
|
||||
|
||||
|
@ -16,43 +18,49 @@ fn build_accessibility_tree(
|
|||
global_state: &mut RenderRootState,
|
||||
default_properties: &DefaultProperties,
|
||||
tree_update: &mut TreeUpdate,
|
||||
mut widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
mut state: ArenaMut<'_, WidgetState>,
|
||||
mut properties: ArenaMut<'_, AnyMap>,
|
||||
properties: ArenaMut<'_, AnyMap>,
|
||||
rebuild_all: bool,
|
||||
scale_factor: Option<f64>,
|
||||
) {
|
||||
let _span = enter_span_if(global_state.trace.access, state.reborrow());
|
||||
let id = state.item.id;
|
||||
let mut children = WidgetArenaMut {
|
||||
widget_children: widget.children,
|
||||
widget_state_children: state.children,
|
||||
properties_children: properties.children,
|
||||
};
|
||||
let widget = &mut **widget.item;
|
||||
let state = state.item;
|
||||
let properties = properties.item;
|
||||
|
||||
if !rebuild_all && !state.item.needs_accessibility {
|
||||
if !rebuild_all && !state.needs_accessibility {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rebuild_all || state.item.request_accessibility) && !state.item.is_stashed {
|
||||
if (rebuild_all || state.request_accessibility) && !state.is_stashed {
|
||||
if global_state.trace.access {
|
||||
trace!(
|
||||
"Building accessibility node for widget '{}' {}",
|
||||
widget.item.short_type_name(),
|
||||
widget.short_type_name(),
|
||||
id,
|
||||
);
|
||||
}
|
||||
|
||||
let mut ctx = AccessCtx {
|
||||
global_state,
|
||||
widget_state: state.item,
|
||||
widget_state_children: state.children.reborrow_mut(),
|
||||
widget_children: widget.children.reborrow_mut(),
|
||||
properties_children: properties.children.reborrow_mut(),
|
||||
widget_state: state,
|
||||
children: children.reborrow_mut(),
|
||||
tree_update,
|
||||
rebuild_all,
|
||||
};
|
||||
let mut node = build_access_node(&mut **widget.item, &mut ctx, scale_factor);
|
||||
let mut node = build_access_node(widget, &mut ctx, scale_factor);
|
||||
let props = PropertiesRef {
|
||||
map: properties.item,
|
||||
default_map: default_properties.for_widget(widget.item.type_id()),
|
||||
map: properties,
|
||||
default_map: default_properties.for_widget(widget.type_id()),
|
||||
};
|
||||
widget.item.accessibility(&mut ctx, &props, &mut node);
|
||||
widget.accessibility(&mut ctx, &props, &mut node);
|
||||
|
||||
let id: NodeId = ctx.widget_state.id.into();
|
||||
if ctx.global_state.trace.access {
|
||||
|
@ -61,30 +69,23 @@ fn build_accessibility_tree(
|
|||
ctx.tree_update.nodes.push((id, node));
|
||||
}
|
||||
|
||||
state.item.request_accessibility = false;
|
||||
state.item.needs_accessibility = false;
|
||||
state.request_accessibility = false;
|
||||
state.needs_accessibility = false;
|
||||
|
||||
let id = state.item.id;
|
||||
let parent_state = state.item;
|
||||
recurse_on_children(
|
||||
id,
|
||||
widget.reborrow_mut(),
|
||||
state.children,
|
||||
properties.children,
|
||||
|widget, mut state, properties| {
|
||||
build_accessibility_tree(
|
||||
global_state,
|
||||
default_properties,
|
||||
tree_update,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
rebuild_all,
|
||||
None,
|
||||
);
|
||||
parent_state.merge_up(state.item);
|
||||
},
|
||||
);
|
||||
let parent_state = state;
|
||||
recurse_on_children(id, widget, children, |widget, mut state, properties| {
|
||||
build_accessibility_tree(
|
||||
global_state,
|
||||
default_properties,
|
||||
tree_update,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
rebuild_all,
|
||||
None,
|
||||
);
|
||||
parent_state.merge_up(state.item);
|
||||
});
|
||||
}
|
||||
|
||||
// --- MARK: BUILD NODE
|
||||
|
@ -105,7 +106,8 @@ fn build_access_node(
|
|||
node.set_transform(accesskit::Affine::new(local_transform.as_coeffs()));
|
||||
|
||||
fn is_child_stashed(ctx: &mut AccessCtx<'_>, id: WidgetId) -> bool {
|
||||
ctx.widget_state_children
|
||||
ctx.children
|
||||
.widget_state_children
|
||||
.find(id)
|
||||
.expect("is_child_stashed: child not found")
|
||||
.item
|
||||
|
|
|
@ -5,7 +5,9 @@ use tracing::info_span;
|
|||
use tree_arena::ArenaMut;
|
||||
|
||||
use crate::app::{RenderRoot, RenderRootState};
|
||||
use crate::core::{DefaultProperties, PropertiesMut, UpdateCtx, Widget, WidgetState};
|
||||
use crate::core::{
|
||||
DefaultProperties, PropertiesMut, UpdateCtx, Widget, WidgetArenaMut, WidgetState,
|
||||
};
|
||||
use crate::passes::{enter_span_if, recurse_on_children};
|
||||
use crate::util::AnyMap;
|
||||
|
||||
|
@ -13,55 +15,56 @@ use crate::util::AnyMap;
|
|||
fn update_anim_for_widget(
|
||||
global_state: &mut RenderRootState,
|
||||
default_properties: &DefaultProperties,
|
||||
mut widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
mut state: ArenaMut<'_, WidgetState>,
|
||||
mut properties: ArenaMut<'_, AnyMap>,
|
||||
properties: ArenaMut<'_, AnyMap>,
|
||||
elapsed_ns: u64,
|
||||
) {
|
||||
let _span = enter_span_if(global_state.trace.anim, state.reborrow());
|
||||
if !state.item.needs_anim {
|
||||
let mut children = WidgetArenaMut {
|
||||
widget_children: widget.children,
|
||||
widget_state_children: state.children,
|
||||
properties_children: properties.children,
|
||||
};
|
||||
let widget = &mut **widget.item;
|
||||
let state = state.item;
|
||||
let properties = properties.item;
|
||||
|
||||
if !state.needs_anim {
|
||||
return;
|
||||
}
|
||||
state.item.needs_anim = false;
|
||||
state.needs_anim = false;
|
||||
|
||||
// Most passes reset their `needs` and `request` flags after the call to
|
||||
// the widget method, but it's valid and expected for `request_anim` to be
|
||||
// set in response to `AnimFrame`.
|
||||
if state.item.request_anim {
|
||||
state.item.request_anim = false;
|
||||
if state.request_anim {
|
||||
state.request_anim = false;
|
||||
let mut ctx = UpdateCtx {
|
||||
global_state,
|
||||
widget_state: state.item,
|
||||
widget_state_children: state.children.reborrow_mut(),
|
||||
widget_children: widget.children.reborrow_mut(),
|
||||
properties_children: properties.children.reborrow_mut(),
|
||||
widget_state: state,
|
||||
children: children.reborrow_mut(),
|
||||
};
|
||||
let mut props = PropertiesMut {
|
||||
map: properties.item,
|
||||
default_map: default_properties.for_widget(widget.item.type_id()),
|
||||
map: properties,
|
||||
default_map: default_properties.for_widget(widget.type_id()),
|
||||
};
|
||||
widget.item.on_anim_frame(&mut ctx, &mut props, elapsed_ns);
|
||||
widget.on_anim_frame(&mut ctx, &mut props, elapsed_ns);
|
||||
}
|
||||
|
||||
let id = state.item.id;
|
||||
let parent_state = state.item;
|
||||
recurse_on_children(
|
||||
id,
|
||||
widget.reborrow_mut(),
|
||||
state.children,
|
||||
properties.children,
|
||||
|widget, mut state, properties| {
|
||||
update_anim_for_widget(
|
||||
global_state,
|
||||
default_properties,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
elapsed_ns,
|
||||
);
|
||||
parent_state.merge_up(state.item);
|
||||
},
|
||||
);
|
||||
let id = state.id;
|
||||
let parent_state = state;
|
||||
recurse_on_children(id, widget, children, |widget, mut state, properties| {
|
||||
update_anim_for_widget(
|
||||
global_state,
|
||||
default_properties,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
elapsed_ns,
|
||||
);
|
||||
parent_state.merge_up(state.item);
|
||||
});
|
||||
}
|
||||
|
||||
// TODO - switch anim frames to being about age / an absolute timestamp
|
||||
|
|
|
@ -6,81 +6,81 @@ use tree_arena::ArenaMut;
|
|||
use vello::kurbo::Affine;
|
||||
|
||||
use crate::app::{RenderRoot, RenderRootState};
|
||||
use crate::core::{ComposeCtx, Widget, WidgetState};
|
||||
use crate::core::{ComposeCtx, Widget, WidgetArenaMut, WidgetState};
|
||||
use crate::passes::{enter_span_if, recurse_on_children};
|
||||
use crate::util::AnyMap;
|
||||
|
||||
// --- MARK: RECURSE
|
||||
fn compose_widget(
|
||||
global_state: &mut RenderRootState,
|
||||
mut widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
mut state: ArenaMut<'_, WidgetState>,
|
||||
properties: ArenaMut<'_, AnyMap>,
|
||||
parent_transformed: bool,
|
||||
parent_window_transform: Affine,
|
||||
) {
|
||||
let _span = enter_span_if(global_state.trace.compose, state.reborrow());
|
||||
let mut children = WidgetArenaMut {
|
||||
widget_children: widget.children,
|
||||
widget_state_children: state.children,
|
||||
properties_children: properties.children,
|
||||
};
|
||||
let widget = &mut **widget.item;
|
||||
let state = state.item;
|
||||
|
||||
let transformed = parent_transformed || state.item.transform_changed;
|
||||
let transformed = parent_transformed || state.transform_changed;
|
||||
|
||||
if !transformed && !state.item.needs_compose {
|
||||
if !transformed && !state.needs_compose {
|
||||
return;
|
||||
}
|
||||
|
||||
// the translation needs to be applied *after* applying the transform, as translation by scrolling should be within the transformed coordinate space. Same is true for the (layout) origin, to behave similar as in CSS.
|
||||
let local_translation = state.item.scroll_translation + state.item.origin.to_vec2();
|
||||
let local_translation = state.scroll_translation + state.origin.to_vec2();
|
||||
|
||||
state.item.window_transform =
|
||||
parent_window_transform * state.item.transform.then_translate(local_translation);
|
||||
state.window_transform =
|
||||
parent_window_transform * state.transform.then_translate(local_translation);
|
||||
|
||||
let local_rect = state.item.size.to_rect() + state.item.paint_insets;
|
||||
state.item.bounding_rect = state.item.window_transform.transform_rect_bbox(local_rect);
|
||||
let local_rect = state.size.to_rect() + state.paint_insets;
|
||||
state.bounding_rect = state.window_transform.transform_rect_bbox(local_rect);
|
||||
|
||||
let mut ctx = ComposeCtx {
|
||||
global_state,
|
||||
widget_state: state.item,
|
||||
widget_state_children: state.children.reborrow_mut(),
|
||||
widget_children: widget.children.reborrow_mut(),
|
||||
widget_state: state,
|
||||
children: children.reborrow_mut(),
|
||||
};
|
||||
if ctx.widget_state.request_compose {
|
||||
widget.item.compose(&mut ctx);
|
||||
widget.compose(&mut ctx);
|
||||
}
|
||||
|
||||
// We need to update the accessibility node's coordinates and repaint it at the new position.
|
||||
state.item.request_accessibility = true;
|
||||
state.item.needs_accessibility = true;
|
||||
state.item.needs_paint = true;
|
||||
state.request_accessibility = true;
|
||||
state.needs_accessibility = true;
|
||||
state.needs_paint = true;
|
||||
|
||||
state.item.needs_compose = false;
|
||||
state.item.request_compose = false;
|
||||
state.item.transform_changed = false;
|
||||
state.needs_compose = false;
|
||||
state.request_compose = false;
|
||||
state.transform_changed = false;
|
||||
|
||||
let id = state.item.id;
|
||||
let parent_transform = state.item.window_transform;
|
||||
let parent_state = state.item;
|
||||
recurse_on_children(
|
||||
id,
|
||||
widget.reborrow_mut(),
|
||||
state.children,
|
||||
properties.children,
|
||||
|widget, mut state, properties| {
|
||||
compose_widget(
|
||||
global_state,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
transformed,
|
||||
parent_transform,
|
||||
);
|
||||
let parent_bounding_rect = parent_state.bounding_rect;
|
||||
let id = state.id;
|
||||
let parent_transform = state.window_transform;
|
||||
let parent_state = state;
|
||||
recurse_on_children(id, widget, children, |widget, mut state, properties| {
|
||||
compose_widget(
|
||||
global_state,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
transformed,
|
||||
parent_transform,
|
||||
);
|
||||
let parent_bounding_rect = parent_state.bounding_rect;
|
||||
|
||||
if let Some(child_bounding_rect) = parent_state.clip_child(state.item.bounding_rect) {
|
||||
parent_state.bounding_rect = parent_bounding_rect.union(child_bounding_rect);
|
||||
}
|
||||
if let Some(child_bounding_rect) = parent_state.clip_child(state.item.bounding_rect) {
|
||||
parent_state.bounding_rect = parent_bounding_rect.union(child_bounding_rect);
|
||||
}
|
||||
|
||||
parent_state.merge_up(state.item);
|
||||
},
|
||||
);
|
||||
parent_state.merge_up(state.item);
|
||||
});
|
||||
}
|
||||
|
||||
// --- MARK: ROOT
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::app::{RenderRoot, RenderRootSignal};
|
|||
use crate::core::keyboard::{Key, KeyState, NamedKey};
|
||||
use crate::core::{
|
||||
AccessEvent, EventCtx, Handled, PointerEvent, PointerInfo, PointerUpdate, PropertiesMut,
|
||||
TextEvent, Widget, WidgetId,
|
||||
TextEvent, Widget, WidgetArenaMut, WidgetId,
|
||||
};
|
||||
use crate::debug_panic;
|
||||
use crate::dpi::{LogicalPosition, PhysicalPosition};
|
||||
|
@ -94,12 +94,15 @@ fn run_event_pass<E>(
|
|||
|
||||
if !is_handled {
|
||||
let _span = enter_span(state_mut.reborrow());
|
||||
let children = WidgetArenaMut {
|
||||
widget_children: widget_mut.children,
|
||||
widget_state_children: state_mut.children,
|
||||
properties_children: properties_mut.children.reborrow_mut(),
|
||||
};
|
||||
let mut ctx = EventCtx {
|
||||
global_state: &mut root.global_state,
|
||||
widget_state: state_mut.item,
|
||||
widget_state_children: state_mut.children,
|
||||
widget_children: widget_mut.children,
|
||||
properties_children: properties_mut.children.reborrow_mut(),
|
||||
children,
|
||||
target: original_target.unwrap(),
|
||||
allow_pointer_capture,
|
||||
is_handled: false,
|
||||
|
|
|
@ -12,7 +12,9 @@ use tree_arena::ArenaMut;
|
|||
use vello::kurbo::{Point, Rect, Size};
|
||||
|
||||
use crate::app::{RenderRoot, RenderRootSignal, WindowSizePolicy};
|
||||
use crate::core::{BoxConstraints, LayoutCtx, PropertiesMut, Widget, WidgetPod, WidgetState};
|
||||
use crate::core::{
|
||||
BoxConstraints, LayoutCtx, PropertiesMut, Widget, WidgetArenaMut, WidgetPod, WidgetState,
|
||||
};
|
||||
use crate::debug_panic;
|
||||
use crate::passes::{enter_span_if, recurse_on_children};
|
||||
use crate::util::AnyMap;
|
||||
|
@ -26,21 +28,42 @@ pub(crate) fn run_layout_on<W: Widget + ?Sized>(
|
|||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
let id = pod.id();
|
||||
let mut widget = parent_ctx.widget_children.item_mut(id).unwrap();
|
||||
let mut state = parent_ctx.widget_state_children.item_mut(id).unwrap();
|
||||
let mut properties = parent_ctx.properties_children.item_mut(id).unwrap();
|
||||
|
||||
let widget = parent_ctx.children.widget_children.item_mut(id).unwrap();
|
||||
let mut state = parent_ctx
|
||||
.children
|
||||
.widget_state_children
|
||||
.item_mut(id)
|
||||
.unwrap();
|
||||
let properties = parent_ctx
|
||||
.children
|
||||
.properties_children
|
||||
.item_mut(id)
|
||||
.unwrap();
|
||||
let trace = parent_ctx.global_state.trace.layout;
|
||||
let _span = enter_span_if(trace, state.reborrow());
|
||||
|
||||
let mut children = WidgetArenaMut {
|
||||
widget_children: widget.children,
|
||||
widget_state_children: state.children,
|
||||
properties_children: properties.children,
|
||||
};
|
||||
|
||||
let widget = &mut **widget.item;
|
||||
let state = state.item;
|
||||
let properties = properties.item;
|
||||
|
||||
let mut children_ids = SmallVec::new();
|
||||
if cfg!(debug_assertions) {
|
||||
children_ids = widget.item.children_ids();
|
||||
children_ids = widget.children_ids();
|
||||
|
||||
// We forcefully set request_layout to true for all children.
|
||||
// This is used below to check that widget.layout(..) visited all of them.
|
||||
for child_id in widget.item.children_ids() {
|
||||
let child_state = state.children.item_mut(child_id).unwrap().item;
|
||||
for child_id in widget.children_ids() {
|
||||
let child_state = children
|
||||
.widget_state_children
|
||||
.item_mut(child_id)
|
||||
.unwrap()
|
||||
.item;
|
||||
if !child_state.is_stashed {
|
||||
child_state.request_layout = true;
|
||||
}
|
||||
|
@ -53,38 +76,37 @@ pub(crate) fn run_layout_on<W: Widget + ?Sized>(
|
|||
// Note that, because this check exits before recursing, run_layout can only ever be
|
||||
// reached for a widget whose parent is not stashed, which means is_explicitly_stashed
|
||||
// being false is sufficient to know the widget is non-stashed.
|
||||
if state.item.is_explicitly_stashed {
|
||||
if state.is_explicitly_stashed {
|
||||
debug_panic!(
|
||||
"Error in '{}' {}: trying to compute layout of stashed widget.",
|
||||
widget.item.short_type_name(),
|
||||
widget.short_type_name(),
|
||||
pod.id(),
|
||||
);
|
||||
state.item.size = Size::ZERO;
|
||||
state.size = Size::ZERO;
|
||||
return Size::ZERO;
|
||||
}
|
||||
|
||||
// TODO - Not everything that has been re-laid out needs to be repainted.
|
||||
state.item.needs_paint = true;
|
||||
state.item.needs_compose = true;
|
||||
state.item.needs_accessibility = true;
|
||||
state.item.request_paint = true;
|
||||
state.item.request_compose = true;
|
||||
state.item.request_accessibility = true;
|
||||
state.needs_paint = true;
|
||||
state.needs_compose = true;
|
||||
state.needs_accessibility = true;
|
||||
state.request_paint = true;
|
||||
state.request_compose = true;
|
||||
state.request_accessibility = true;
|
||||
|
||||
bc.debug_check(widget.item.short_type_name());
|
||||
bc.debug_check(widget.short_type_name());
|
||||
if trace {
|
||||
trace!("Computing layout with constraints {:?}", bc);
|
||||
}
|
||||
|
||||
state.item.local_paint_rect = Rect::ZERO;
|
||||
state.local_paint_rect = Rect::ZERO;
|
||||
|
||||
// If children are stashed, the layout pass will not recurse over them.
|
||||
// We reset need_layout and request_layout to false directly instead.
|
||||
recurse_on_children(
|
||||
pod.id(),
|
||||
widget.reborrow_mut(),
|
||||
state.children.reborrow_mut(),
|
||||
properties.children.reborrow_mut(),
|
||||
widget,
|
||||
children.reborrow_mut(),
|
||||
|widget, state, properties| {
|
||||
if state.item.is_stashed {
|
||||
clear_layout_flags(widget, state, properties);
|
||||
|
@ -94,10 +116,8 @@ pub(crate) fn run_layout_on<W: Widget + ?Sized>(
|
|||
|
||||
let new_size = {
|
||||
let mut inner_ctx = LayoutCtx {
|
||||
widget_state: state.item,
|
||||
widget_state_children: state.children.reborrow_mut(),
|
||||
widget_children: widget.children,
|
||||
properties_children: properties.children.reborrow_mut(),
|
||||
widget_state: state,
|
||||
children: children.reborrow_mut(),
|
||||
default_properties: parent_ctx.default_properties,
|
||||
global_state: parent_ctx.global_state,
|
||||
};
|
||||
|
@ -106,40 +126,41 @@ pub(crate) fn run_layout_on<W: Widget + ?Sized>(
|
|||
// skip calling layout
|
||||
inner_ctx.widget_state.request_layout = false;
|
||||
let mut props = PropertiesMut {
|
||||
map: properties.item,
|
||||
default_map: parent_ctx
|
||||
.default_properties
|
||||
.for_widget(widget.item.type_id()),
|
||||
map: properties,
|
||||
default_map: parent_ctx.default_properties.for_widget(widget.type_id()),
|
||||
};
|
||||
widget.item.layout(&mut inner_ctx, &mut props, bc)
|
||||
widget.layout(&mut inner_ctx, &mut props, bc)
|
||||
};
|
||||
if state.item.request_layout {
|
||||
if state.request_layout {
|
||||
debug_panic!(
|
||||
"Error in '{}' {}: layout request flag was set during layout pass",
|
||||
widget.item.short_type_name(),
|
||||
widget.short_type_name(),
|
||||
pod.id(),
|
||||
);
|
||||
}
|
||||
if trace {
|
||||
trace!(
|
||||
"Computed layout: size={}, baseline={}, insets={:?}",
|
||||
new_size, state.item.baseline_offset, state.item.paint_insets,
|
||||
new_size, state.baseline_offset, state.paint_insets,
|
||||
);
|
||||
}
|
||||
|
||||
state.item.needs_layout = false;
|
||||
state.item.is_expecting_place_child_call = true;
|
||||
state.needs_layout = false;
|
||||
state.is_expecting_place_child_call = true;
|
||||
|
||||
state.item.local_paint_rect = state
|
||||
.item
|
||||
state.local_paint_rect = state
|
||||
.local_paint_rect
|
||||
.union(new_size.to_rect() + state.item.paint_insets);
|
||||
.union(new_size.to_rect() + state.paint_insets);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
let name = widget.item.short_type_name();
|
||||
for child_id in widget.item.children_ids() {
|
||||
let child_state = state.children.item_mut(child_id).unwrap().item;
|
||||
let name = widget.short_type_name();
|
||||
for child_id in widget.children_ids() {
|
||||
let child_state = children
|
||||
.widget_state_children
|
||||
.item_mut(child_id)
|
||||
.unwrap()
|
||||
.item;
|
||||
|
||||
if child_state.is_stashed {
|
||||
continue;
|
||||
|
@ -166,8 +187,8 @@ pub(crate) fn run_layout_on<W: Widget + ?Sized>(
|
|||
}
|
||||
}
|
||||
|
||||
let new_children_ids = widget.item.children_ids();
|
||||
if children_ids != new_children_ids && !state.item.children_changed {
|
||||
let new_children_ids = widget.children_ids();
|
||||
if children_ids != new_children_ids && !state.children_changed {
|
||||
debug_panic!(
|
||||
"Error in '{}' {}: children changed during layout pass",
|
||||
name,
|
||||
|
@ -185,7 +206,11 @@ pub(crate) fn run_layout_on<W: Widget + ?Sized>(
|
|||
}
|
||||
}
|
||||
|
||||
let state_mut = parent_ctx.widget_state_children.item_mut(id).unwrap();
|
||||
let state_mut = parent_ctx
|
||||
.children
|
||||
.widget_state_children
|
||||
.item_mut(id)
|
||||
.unwrap();
|
||||
parent_ctx.widget_state.merge_up(state_mut.item);
|
||||
state_mut.item.size = new_size;
|
||||
new_size
|
||||
|
@ -195,23 +220,26 @@ pub(crate) fn run_layout_on<W: Widget + ?Sized>(
|
|||
// This function is called on stashed widgets and their children
|
||||
// to set all layout flags to false.
|
||||
fn clear_layout_flags(
|
||||
mut widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
state: ArenaMut<'_, WidgetState>,
|
||||
properties: ArenaMut<'_, AnyMap>,
|
||||
) {
|
||||
state.item.needs_layout = false;
|
||||
state.item.request_layout = false;
|
||||
let children = WidgetArenaMut {
|
||||
widget_children: widget.children,
|
||||
widget_state_children: state.children,
|
||||
properties_children: properties.children,
|
||||
};
|
||||
|
||||
let id = state.item.id;
|
||||
recurse_on_children(
|
||||
id,
|
||||
widget.reborrow_mut(),
|
||||
state.children,
|
||||
properties.children,
|
||||
|widget, state, properties| {
|
||||
clear_layout_flags(widget, state, properties);
|
||||
},
|
||||
);
|
||||
let widget = &mut **widget.item;
|
||||
let state = state.item;
|
||||
|
||||
state.needs_layout = false;
|
||||
state.request_layout = false;
|
||||
|
||||
let id = state.id;
|
||||
recurse_on_children(id, widget, children, |widget, state, properties| {
|
||||
clear_layout_flags(widget, state, properties);
|
||||
});
|
||||
}
|
||||
|
||||
// --- MARK: ROOT
|
||||
|
@ -238,9 +266,11 @@ pub(crate) fn run_layout_pass(root: &mut RenderRoot) {
|
|||
let mut ctx = LayoutCtx {
|
||||
global_state: &mut root.global_state,
|
||||
widget_state: &mut dummy_state,
|
||||
widget_state_children: root_state_token,
|
||||
widget_children: root_widget_token,
|
||||
properties_children: root_properties_token,
|
||||
children: WidgetArenaMut {
|
||||
widget_state_children: root_state_token,
|
||||
widget_children: root_widget_token,
|
||||
properties_children: root_properties_token,
|
||||
},
|
||||
default_properties: &root.default_properties,
|
||||
};
|
||||
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
//! This file includes utility functions used by multiple passes.
|
||||
|
||||
use tracing::span::EnteredSpan;
|
||||
use tree_arena::{ArenaMut, ArenaMutList, ArenaRef};
|
||||
use tree_arena::{ArenaMut, ArenaRef};
|
||||
|
||||
use crate::core::{Widget, WidgetArena, WidgetId, WidgetState};
|
||||
use crate::core::{Widget, WidgetArena, WidgetArenaMut, WidgetId, WidgetState};
|
||||
use crate::util::AnyMap;
|
||||
|
||||
pub(crate) mod accessibility;
|
||||
|
@ -37,30 +37,29 @@ pub(crate) fn enter_span(state: ArenaRef<'_, WidgetState>) -> EnteredSpan {
|
|||
|
||||
pub(crate) fn recurse_on_children(
|
||||
id: WidgetId,
|
||||
mut widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
mut state: ArenaMutList<'_, WidgetState>,
|
||||
mut properties: ArenaMutList<'_, AnyMap>,
|
||||
widget: &mut dyn Widget,
|
||||
mut children: WidgetArenaMut<'_>,
|
||||
mut callback: impl FnMut(
|
||||
ArenaMut<'_, Box<dyn Widget>>,
|
||||
ArenaMut<'_, WidgetState>,
|
||||
ArenaMut<'_, AnyMap>,
|
||||
),
|
||||
) {
|
||||
let parent_name = widget.item.short_type_name();
|
||||
let parent_name = widget.short_type_name();
|
||||
let parent_id = id;
|
||||
|
||||
for child_id in widget.item.children_ids() {
|
||||
let widget = widget.children.item_mut(child_id).unwrap_or_else(|| {
|
||||
for child_id in widget.children_ids() {
|
||||
let widget = children.widget_children.item_mut(child_id).unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Error in '{parent_name}' {parent_id}: cannot find child {child_id} returned by children_ids()"
|
||||
)
|
||||
});
|
||||
let state = state.item_mut(child_id).unwrap_or_else(|| {
|
||||
let state = children.widget_state_children.item_mut(child_id).unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Error in '{parent_name}' {parent_id}: cannot find child {child_id} returned by children_ids()"
|
||||
)
|
||||
});
|
||||
let properties = properties.item_mut(child_id).unwrap_or_else(|| {
|
||||
let properties = children.properties_children.item_mut(child_id).unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Error in '{parent_name}' {parent_id}: cannot find child {child_id} returned by children_ids()"
|
||||
)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
use tracing::info_span;
|
||||
|
||||
use crate::app::RenderRoot;
|
||||
use crate::core::{MutateCtx, PropertiesMut, Widget, WidgetId, WidgetMut};
|
||||
use crate::core::{MutateCtx, PropertiesMut, Widget, WidgetArenaMut, WidgetId, WidgetMut};
|
||||
use crate::passes::merge_state_up;
|
||||
|
||||
pub(crate) fn mutate_widget<R>(
|
||||
|
@ -13,26 +13,31 @@ pub(crate) fn mutate_widget<R>(
|
|||
mutate_fn: impl FnOnce(WidgetMut<'_, dyn Widget>) -> R,
|
||||
) -> R {
|
||||
let (widget_mut, state_mut, properties_mut) = root.widget_arena.get_all_mut(id);
|
||||
let children = WidgetArenaMut {
|
||||
widget_children: widget_mut.children,
|
||||
widget_state_children: state_mut.children,
|
||||
properties_children: properties_mut.children,
|
||||
};
|
||||
let widget = &mut **widget_mut.item;
|
||||
let state = state_mut.item;
|
||||
let properties = properties_mut.item;
|
||||
|
||||
let _span = info_span!("mutate_widget", name = widget.short_type_name()).entered();
|
||||
|
||||
let _span = info_span!("mutate_widget", name = widget_mut.item.short_type_name()).entered();
|
||||
// NOTE - we can set parent_widget_state to None here, because the loop below will merge the
|
||||
// states up to the root.
|
||||
let root_widget = WidgetMut {
|
||||
ctx: MutateCtx {
|
||||
global_state: &mut root.global_state,
|
||||
parent_widget_state: None,
|
||||
widget_state: state_mut.item,
|
||||
widget_state_children: state_mut.children,
|
||||
widget_children: widget_mut.children,
|
||||
widget_state: state,
|
||||
properties: PropertiesMut {
|
||||
map: properties_mut.item,
|
||||
default_map: root
|
||||
.default_properties
|
||||
.for_widget(widget_mut.item.type_id()),
|
||||
map: properties,
|
||||
default_map: root.default_properties.for_widget(widget.type_id()),
|
||||
},
|
||||
properties_children: properties_mut.children,
|
||||
children,
|
||||
},
|
||||
widget: &mut **widget_mut.item,
|
||||
widget,
|
||||
};
|
||||
|
||||
let result = mutate_fn(root_widget);
|
||||
|
|
|
@ -10,7 +10,9 @@ use vello::kurbo::{Affine, Rect};
|
|||
use vello::peniko::{Color, Fill, Mix};
|
||||
|
||||
use crate::app::{RenderRoot, RenderRootState};
|
||||
use crate::core::{DefaultProperties, PaintCtx, PropertiesRef, Widget, WidgetId, WidgetState};
|
||||
use crate::core::{
|
||||
DefaultProperties, PaintCtx, PropertiesRef, Widget, WidgetArenaMut, WidgetId, WidgetState,
|
||||
};
|
||||
use crate::passes::{enter_span_if, recurse_on_children};
|
||||
use crate::util::{AnyMap, get_debug_color, stroke};
|
||||
|
||||
|
@ -20,7 +22,7 @@ fn paint_widget(
|
|||
default_properties: &DefaultProperties,
|
||||
complete_scene: &mut Scene,
|
||||
scenes: &mut HashMap<WidgetId, Scene>,
|
||||
mut widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
mut state: ArenaMut<'_, WidgetState>,
|
||||
properties: ArenaMut<'_, AnyMap>,
|
||||
debug_paint: bool,
|
||||
|
@ -35,18 +37,26 @@ fn paint_widget(
|
|||
// but we deliberately avoid doing that to avoid creating zombie flags.
|
||||
// (See WidgetState doc.)
|
||||
|
||||
let mut children = WidgetArenaMut {
|
||||
widget_children: widget.children,
|
||||
widget_state_children: state.children,
|
||||
properties_children: properties.children,
|
||||
};
|
||||
let widget = &mut **widget.item;
|
||||
let state = state.item;
|
||||
let properties = properties.item;
|
||||
|
||||
// TODO - Handle damage regions
|
||||
// https://github.com/linebender/xilem/issues/789
|
||||
let mut ctx = PaintCtx {
|
||||
global_state,
|
||||
widget_state: state.item,
|
||||
widget_state_children: state.children.reborrow_mut(),
|
||||
widget_children: widget.children.reborrow_mut(),
|
||||
widget_state: state,
|
||||
children: children.reborrow_mut(),
|
||||
debug_paint,
|
||||
};
|
||||
if ctx.widget_state.request_paint && !is_stashed {
|
||||
if trace {
|
||||
trace!("Painting widget '{}' {}", widget.item.short_type_name(), id);
|
||||
trace!("Painting widget '{}' {}", widget.short_type_name(), id);
|
||||
}
|
||||
|
||||
// TODO - Reserve scene
|
||||
|
@ -54,54 +64,48 @@ fn paint_widget(
|
|||
let scene = scenes.entry(id).or_default();
|
||||
scene.reset();
|
||||
let props = PropertiesRef {
|
||||
map: properties.item,
|
||||
default_map: default_properties.for_widget(widget.item.type_id()),
|
||||
map: properties,
|
||||
default_map: default_properties.for_widget(widget.type_id()),
|
||||
};
|
||||
widget.item.paint(&mut ctx, &props, scene);
|
||||
widget.paint(&mut ctx, &props, scene);
|
||||
}
|
||||
|
||||
state.item.request_paint = false;
|
||||
state.item.needs_paint = false;
|
||||
state.request_paint = false;
|
||||
state.needs_paint = false;
|
||||
|
||||
let has_clip = state.item.clip_path.is_some();
|
||||
let has_clip = state.clip_path.is_some();
|
||||
if !is_stashed {
|
||||
let transform = state.item.window_transform;
|
||||
let transform = state.window_transform;
|
||||
let scene = scenes.get(&id).unwrap();
|
||||
|
||||
if let Some(clip) = state.item.clip_path {
|
||||
if let Some(clip) = state.clip_path {
|
||||
complete_scene.push_layer(Mix::Clip, 1., transform, &clip);
|
||||
}
|
||||
|
||||
complete_scene.append(scene, Some(transform));
|
||||
}
|
||||
|
||||
let id = state.item.id;
|
||||
let bounding_rect = state.item.bounding_rect;
|
||||
let parent_state = state.item;
|
||||
recurse_on_children(
|
||||
id,
|
||||
widget.reborrow_mut(),
|
||||
state.children,
|
||||
properties.children,
|
||||
|widget, mut state, properties| {
|
||||
// TODO: We could skip painting children outside the parent clip path.
|
||||
// There's a few things to consider if we do:
|
||||
// - Some widgets can paint outside of their layout box.
|
||||
// - Once we implement compositor layers, we may want to paint outside of the clip path anyway in anticipation of user scrolling.
|
||||
// - We still want to reset needs_paint and request_paint flags.
|
||||
paint_widget(
|
||||
global_state,
|
||||
default_properties,
|
||||
complete_scene,
|
||||
scenes,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
debug_paint,
|
||||
);
|
||||
parent_state.merge_up(state.item);
|
||||
},
|
||||
);
|
||||
let bounding_rect = state.bounding_rect;
|
||||
let parent_state = state;
|
||||
|
||||
recurse_on_children(id, widget, children, |widget, mut state, properties| {
|
||||
// TODO: We could skip painting children outside the parent clip path.
|
||||
// There's a few things to consider if we do:
|
||||
// - Some widgets can paint outside of their layout box.
|
||||
// - Once we implement compositor layers, we may want to paint outside of the clip path anyway in anticipation of user scrolling.
|
||||
// - We still want to reset needs_paint and request_paint flags.
|
||||
paint_widget(
|
||||
global_state,
|
||||
default_properties,
|
||||
complete_scene,
|
||||
scenes,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
debug_paint,
|
||||
);
|
||||
parent_state.merge_up(state.item);
|
||||
});
|
||||
|
||||
if !is_stashed {
|
||||
// draw the global axis aligned bounding rect of the widget
|
||||
|
|
|
@ -11,7 +11,8 @@ use ui_events::pointer::PointerType;
|
|||
use crate::app::{RenderRoot, RenderRootSignal, RenderRootState};
|
||||
use crate::core::{
|
||||
DefaultProperties, Ime, PointerEvent, PointerInfo, PropertiesMut, PropertiesRef, QueryCtx,
|
||||
RegisterCtx, TextEvent, Update, UpdateCtx, Widget, WidgetId, WidgetState,
|
||||
RegisterCtx, TextEvent, Update, UpdateCtx, Widget, WidgetArenaMut, WidgetArenaRef, WidgetId,
|
||||
WidgetState,
|
||||
};
|
||||
use crate::passes::event::{run_on_pointer_event_pass, run_on_text_event_pass};
|
||||
use crate::passes::{enter_span, enter_span_if, merge_state_up, recurse_on_children};
|
||||
|
@ -53,16 +54,22 @@ fn run_targeted_update_pass(
|
|||
let parent_id = root.widget_arena.parent_of(widget_id);
|
||||
let (widget_mut, state_mut, properties_mut) = root.widget_arena.get_all_mut(widget_id);
|
||||
|
||||
let widget = &mut **widget_mut.item;
|
||||
let mut ctx = UpdateCtx {
|
||||
global_state: &mut root.global_state,
|
||||
widget_state: state_mut.item,
|
||||
widget_state_children: state_mut.children,
|
||||
let children = WidgetArenaMut {
|
||||
widget_children: widget_mut.children,
|
||||
widget_state_children: state_mut.children,
|
||||
properties_children: properties_mut.children,
|
||||
};
|
||||
let widget = &mut **widget_mut.item;
|
||||
let state = state_mut.item;
|
||||
let properties = properties_mut.item;
|
||||
|
||||
let mut ctx = UpdateCtx {
|
||||
global_state: &mut root.global_state,
|
||||
widget_state: state,
|
||||
children,
|
||||
};
|
||||
let mut props = PropertiesMut {
|
||||
map: properties_mut.item,
|
||||
map: properties,
|
||||
default_map: root.default_properties.for_widget(widget.type_id()),
|
||||
};
|
||||
pass_fn(widget, &mut ctx, &mut props);
|
||||
|
@ -86,20 +93,25 @@ fn run_single_update_pass(
|
|||
|
||||
let (widget_mut, state_mut, properties_mut) = root.widget_arena.get_all_mut(target);
|
||||
|
||||
let mut ctx = UpdateCtx {
|
||||
global_state: &mut root.global_state,
|
||||
widget_state: state_mut.item,
|
||||
widget_state_children: state_mut.children,
|
||||
let children = WidgetArenaMut {
|
||||
widget_children: widget_mut.children,
|
||||
widget_state_children: state_mut.children,
|
||||
properties_children: properties_mut.children,
|
||||
};
|
||||
let mut props = PropertiesMut {
|
||||
map: properties_mut.item,
|
||||
default_map: root
|
||||
.default_properties
|
||||
.for_widget(widget_mut.item.type_id()),
|
||||
let widget = &mut **widget_mut.item;
|
||||
let state = state_mut.item;
|
||||
let properties = properties_mut.item;
|
||||
|
||||
let mut ctx = UpdateCtx {
|
||||
global_state: &mut root.global_state,
|
||||
widget_state: state,
|
||||
children,
|
||||
};
|
||||
pass_fn(&mut **widget_mut.item, &mut ctx, &mut props);
|
||||
let mut props = PropertiesMut {
|
||||
map: properties,
|
||||
default_map: root.default_properties.for_widget(widget.type_id()),
|
||||
};
|
||||
pass_fn(widget, &mut ctx, &mut props);
|
||||
|
||||
let mut current_id = Some(target);
|
||||
while let Some(widget_id) = current_id {
|
||||
|
@ -112,41 +124,48 @@ fn run_single_update_pass(
|
|||
fn update_widget_tree(
|
||||
global_state: &mut RenderRootState,
|
||||
default_properties: &DefaultProperties,
|
||||
mut widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
mut state: ArenaMut<'_, WidgetState>,
|
||||
mut properties: ArenaMut<'_, AnyMap>,
|
||||
properties: ArenaMut<'_, AnyMap>,
|
||||
) {
|
||||
let trace = global_state.trace.update_tree;
|
||||
let _span = enter_span_if(trace, state.reborrow());
|
||||
let id = state.item.id;
|
||||
|
||||
if !state.item.children_changed {
|
||||
let mut children = WidgetArenaMut {
|
||||
widget_children: widget.children,
|
||||
widget_state_children: state.children,
|
||||
properties_children: properties.children,
|
||||
};
|
||||
let widget = &mut **widget.item;
|
||||
let state = state.item;
|
||||
let properties = properties.item;
|
||||
|
||||
if !state.children_changed {
|
||||
return;
|
||||
}
|
||||
state.item.children_changed = false;
|
||||
state.children_changed = false;
|
||||
|
||||
{
|
||||
let mut ctx = RegisterCtx {
|
||||
widget_state_children: state.children.reborrow_mut(),
|
||||
widget_children: widget.children.reborrow_mut(),
|
||||
properties_children: properties.children.reborrow_mut(),
|
||||
children: children.reborrow_mut(),
|
||||
#[cfg(debug_assertions)]
|
||||
registered_ids: Vec::new(),
|
||||
};
|
||||
// The widget will call `RegisterCtx::register_child` on all its children,
|
||||
// which will add the new widgets to the arena.
|
||||
widget.item.register_children(&mut ctx);
|
||||
widget.register_children(&mut ctx);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
let children_ids = widget.item.children_ids();
|
||||
let children_ids = widget.children_ids();
|
||||
for child_id in ctx.registered_ids {
|
||||
if !children_ids.contains(&child_id) {
|
||||
panic!(
|
||||
"Error in '{}' {}: method register_children() called \
|
||||
RegisterCtx::register_child() on child {}, which isn't \
|
||||
in the list returned by children_ids()",
|
||||
widget.item.short_type_name(),
|
||||
widget.short_type_name(),
|
||||
id,
|
||||
child_id
|
||||
);
|
||||
|
@ -155,12 +174,12 @@ fn update_widget_tree(
|
|||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
for child_id in widget.item.children_ids() {
|
||||
if widget.children.item(child_id).is_none() {
|
||||
for child_id in widget.children_ids() {
|
||||
if !children.widget_children.has(child_id) {
|
||||
panic!(
|
||||
"Error in '{}' {}: method register_children() did not call \
|
||||
RegisterCtx::register_child() on child {} returned by children_ids()",
|
||||
widget.item.short_type_name(),
|
||||
widget.short_type_name(),
|
||||
id,
|
||||
child_id
|
||||
);
|
||||
|
@ -168,53 +187,40 @@ fn update_widget_tree(
|
|||
}
|
||||
}
|
||||
|
||||
if state.item.is_new {
|
||||
if state.is_new {
|
||||
let mut ctx = UpdateCtx {
|
||||
global_state,
|
||||
widget_state: state.item,
|
||||
widget_state_children: state.children.reborrow_mut(),
|
||||
widget_children: widget.children.reborrow_mut(),
|
||||
properties_children: properties.children.reborrow_mut(),
|
||||
widget_state: state,
|
||||
children: children.reborrow_mut(),
|
||||
};
|
||||
let mut props = PropertiesMut {
|
||||
map: properties.item,
|
||||
default_map: default_properties.for_widget(widget.item.type_id()),
|
||||
map: properties,
|
||||
default_map: default_properties.for_widget(widget.type_id()),
|
||||
};
|
||||
widget
|
||||
.item
|
||||
.update(&mut ctx, &mut props, &Update::WidgetAdded);
|
||||
widget.update(&mut ctx, &mut props, &Update::WidgetAdded);
|
||||
if trace {
|
||||
trace!(
|
||||
"{} received Update::WidgetAdded",
|
||||
widget.item.short_type_name()
|
||||
);
|
||||
trace!("{} received Update::WidgetAdded", widget.short_type_name());
|
||||
}
|
||||
state.item.accepts_pointer_interaction = widget.item.accepts_pointer_interaction();
|
||||
state.item.accepts_focus = widget.item.accepts_focus();
|
||||
state.item.accepts_text_input = widget.item.accepts_text_input();
|
||||
state.item.trace_span = widget.item.make_trace_span(state.item.id);
|
||||
state.item.is_new = false;
|
||||
state.accepts_pointer_interaction = widget.accepts_pointer_interaction();
|
||||
state.accepts_focus = widget.accepts_focus();
|
||||
state.accepts_text_input = widget.accepts_text_input();
|
||||
state.trace_span = widget.make_trace_span(state.id);
|
||||
state.is_new = false;
|
||||
}
|
||||
|
||||
// We can recurse on this widget's children, because they have already been added
|
||||
// to the arena above.
|
||||
let parent_state = state.item;
|
||||
recurse_on_children(
|
||||
id,
|
||||
widget.reborrow_mut(),
|
||||
state.children,
|
||||
properties.children,
|
||||
|widget, mut state, properties| {
|
||||
update_widget_tree(
|
||||
global_state,
|
||||
default_properties,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
);
|
||||
parent_state.merge_up(state.item);
|
||||
},
|
||||
);
|
||||
let parent_state = state;
|
||||
recurse_on_children(id, widget, children, |widget, mut state, properties| {
|
||||
update_widget_tree(
|
||||
global_state,
|
||||
default_properties,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
);
|
||||
parent_state.merge_up(state.item);
|
||||
});
|
||||
}
|
||||
|
||||
/// See the [passes documentation](../doc/05_pass_system.md#update-tree-pass).
|
||||
|
@ -223,9 +229,11 @@ pub(crate) fn run_update_widget_tree_pass(root: &mut RenderRoot) {
|
|||
|
||||
if root.root.incomplete() {
|
||||
let mut ctx = RegisterCtx {
|
||||
widget_state_children: root.widget_arena.states.roots_mut(),
|
||||
widget_children: root.widget_arena.widgets.roots_mut(),
|
||||
properties_children: root.widget_arena.properties.roots_mut(),
|
||||
children: WidgetArenaMut {
|
||||
widget_state_children: root.widget_arena.states.roots_mut(),
|
||||
widget_children: root.widget_arena.widgets.roots_mut(),
|
||||
properties_children: root.widget_arena.properties.roots_mut(),
|
||||
},
|
||||
#[cfg(debug_assertions)]
|
||||
registered_ids: Vec::new(),
|
||||
};
|
||||
|
@ -251,60 +259,59 @@ pub(crate) fn run_update_widget_tree_pass(root: &mut RenderRoot) {
|
|||
fn update_disabled_for_widget(
|
||||
global_state: &mut RenderRootState,
|
||||
default_properties: &DefaultProperties,
|
||||
mut widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
mut state: ArenaMut<'_, WidgetState>,
|
||||
mut properties: ArenaMut<'_, AnyMap>,
|
||||
properties: ArenaMut<'_, AnyMap>,
|
||||
parent_disabled: bool,
|
||||
) {
|
||||
let _span = enter_span(state.reborrow());
|
||||
let id = state.item.id;
|
||||
|
||||
let disabled = state.item.is_explicitly_disabled || parent_disabled;
|
||||
if !state.item.needs_update_disabled && disabled == state.item.is_disabled {
|
||||
let mut children = WidgetArenaMut {
|
||||
widget_children: widget.children,
|
||||
widget_state_children: state.children,
|
||||
properties_children: properties.children,
|
||||
};
|
||||
let widget = &mut **widget.item;
|
||||
let state = state.item;
|
||||
let properties = properties.item;
|
||||
|
||||
let disabled = state.is_explicitly_disabled || parent_disabled;
|
||||
if !state.needs_update_disabled && disabled == state.is_disabled {
|
||||
return;
|
||||
}
|
||||
|
||||
if disabled != state.item.is_disabled {
|
||||
if disabled != state.is_disabled {
|
||||
let mut ctx = UpdateCtx {
|
||||
global_state,
|
||||
widget_state: state.item,
|
||||
widget_state_children: state.children.reborrow_mut(),
|
||||
widget_children: widget.children.reborrow_mut(),
|
||||
properties_children: properties.children.reborrow_mut(),
|
||||
widget_state: state,
|
||||
children: children.reborrow_mut(),
|
||||
};
|
||||
let mut props = PropertiesMut {
|
||||
map: properties.item,
|
||||
default_map: default_properties.for_widget(widget.item.type_id()),
|
||||
map: properties,
|
||||
default_map: default_properties.for_widget(widget.type_id()),
|
||||
};
|
||||
widget
|
||||
.item
|
||||
.update(&mut ctx, &mut props, &Update::DisabledChanged(disabled));
|
||||
state.item.is_disabled = disabled;
|
||||
state.item.needs_update_focus_chain = true;
|
||||
state.item.request_accessibility = true;
|
||||
state.item.needs_accessibility = true;
|
||||
widget.update(&mut ctx, &mut props, &Update::DisabledChanged(disabled));
|
||||
state.is_disabled = disabled;
|
||||
state.needs_update_focus_chain = true;
|
||||
state.request_accessibility = true;
|
||||
state.needs_accessibility = true;
|
||||
}
|
||||
|
||||
state.item.needs_update_disabled = false;
|
||||
state.needs_update_disabled = false;
|
||||
|
||||
let parent_state = state.item;
|
||||
recurse_on_children(
|
||||
id,
|
||||
widget.reborrow_mut(),
|
||||
state.children,
|
||||
properties.children,
|
||||
|widget, mut state, properties| {
|
||||
update_disabled_for_widget(
|
||||
global_state,
|
||||
default_properties,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
disabled,
|
||||
);
|
||||
parent_state.merge_up(state.item);
|
||||
},
|
||||
);
|
||||
let parent_state = state;
|
||||
recurse_on_children(id, widget, children, |widget, mut state, properties| {
|
||||
update_disabled_for_widget(
|
||||
global_state,
|
||||
default_properties,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
disabled,
|
||||
);
|
||||
parent_state.merge_up(state.item);
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn run_update_disabled_pass(root: &mut RenderRoot) {
|
||||
|
@ -337,69 +344,68 @@ pub(crate) fn run_update_disabled_pass(root: &mut RenderRoot) {
|
|||
fn update_stashed_for_widget(
|
||||
global_state: &mut RenderRootState,
|
||||
default_properties: &DefaultProperties,
|
||||
mut widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
mut state: ArenaMut<'_, WidgetState>,
|
||||
mut properties: ArenaMut<'_, AnyMap>,
|
||||
properties: ArenaMut<'_, AnyMap>,
|
||||
parent_stashed: bool,
|
||||
) {
|
||||
let _span = enter_span(state.reborrow());
|
||||
let id = state.item.id;
|
||||
|
||||
let stashed = state.item.is_explicitly_stashed || parent_stashed;
|
||||
if !state.item.needs_update_stashed && stashed == state.item.is_stashed {
|
||||
let mut children = WidgetArenaMut {
|
||||
widget_children: widget.children,
|
||||
widget_state_children: state.children,
|
||||
properties_children: properties.children,
|
||||
};
|
||||
let widget = &mut **widget.item;
|
||||
let state = state.item;
|
||||
let properties = properties.item;
|
||||
|
||||
let stashed = state.is_explicitly_stashed || parent_stashed;
|
||||
if !state.needs_update_stashed && stashed == state.is_stashed {
|
||||
return;
|
||||
}
|
||||
|
||||
if stashed != state.item.is_stashed {
|
||||
if stashed != state.is_stashed {
|
||||
let mut ctx = UpdateCtx {
|
||||
global_state,
|
||||
widget_state: state.item,
|
||||
widget_state_children: state.children.reborrow_mut(),
|
||||
widget_children: widget.children.reborrow_mut(),
|
||||
properties_children: properties.children.reborrow_mut(),
|
||||
widget_state: state,
|
||||
children: children.reborrow_mut(),
|
||||
};
|
||||
let mut props = PropertiesMut {
|
||||
map: properties.item,
|
||||
default_map: default_properties.for_widget(widget.item.type_id()),
|
||||
map: properties,
|
||||
default_map: default_properties.for_widget(widget.type_id()),
|
||||
};
|
||||
widget
|
||||
.item
|
||||
.update(&mut ctx, &mut props, &Update::StashedChanged(stashed));
|
||||
state.item.is_stashed = stashed;
|
||||
state.item.needs_update_focus_chain = true;
|
||||
widget.update(&mut ctx, &mut props, &Update::StashedChanged(stashed));
|
||||
state.is_stashed = stashed;
|
||||
state.needs_update_focus_chain = true;
|
||||
|
||||
// Items may have been changed while they were stashed in ways that require a
|
||||
// relayout and a re-render.
|
||||
if !stashed {
|
||||
state.item.needs_layout = true;
|
||||
state.item.request_layout = true;
|
||||
state.item.request_paint = true;
|
||||
state.item.needs_paint = true;
|
||||
state.item.needs_accessibility = true;
|
||||
state.item.request_accessibility = true;
|
||||
state.needs_layout = true;
|
||||
state.request_layout = true;
|
||||
state.request_paint = true;
|
||||
state.needs_paint = true;
|
||||
state.needs_accessibility = true;
|
||||
state.request_accessibility = true;
|
||||
}
|
||||
}
|
||||
|
||||
state.item.needs_update_stashed = false;
|
||||
state.needs_update_stashed = false;
|
||||
|
||||
let parent_state = state.item;
|
||||
recurse_on_children(
|
||||
id,
|
||||
widget.reborrow_mut(),
|
||||
state.children,
|
||||
properties.children,
|
||||
|widget, mut state, properties| {
|
||||
update_stashed_for_widget(
|
||||
global_state,
|
||||
default_properties,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
stashed,
|
||||
);
|
||||
parent_state.merge_up(state.item);
|
||||
},
|
||||
);
|
||||
let parent_state = state;
|
||||
recurse_on_children(id, widget, children, |widget, mut state, properties| {
|
||||
update_stashed_for_widget(
|
||||
global_state,
|
||||
default_properties,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
stashed,
|
||||
);
|
||||
parent_state.merge_up(state.item);
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn run_update_stashed_pass(root: &mut RenderRoot) {
|
||||
|
@ -429,7 +435,7 @@ pub(crate) fn run_update_stashed_pass(root: &mut RenderRoot) {
|
|||
/// See the [passes documentation](../doc/05_pass_system.md#update-passes).
|
||||
fn update_focus_chain_for_widget(
|
||||
global_state: &mut RenderRootState,
|
||||
mut widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
mut state: ArenaMut<'_, WidgetState>,
|
||||
properties: ArenaMut<'_, AnyMap>,
|
||||
parent_focus_chain: &mut Vec<WidgetId>,
|
||||
|
@ -437,48 +443,50 @@ fn update_focus_chain_for_widget(
|
|||
let _span = enter_span(state.reborrow());
|
||||
let id = state.item.id;
|
||||
|
||||
let children = WidgetArenaMut {
|
||||
widget_children: widget.children,
|
||||
widget_state_children: state.children,
|
||||
properties_children: properties.children,
|
||||
};
|
||||
let widget = &mut **widget.item;
|
||||
let state = state.item;
|
||||
|
||||
// Replace has_focused to check if the value changed in the meantime
|
||||
state.item.has_focus_target = global_state.focused_widget == Some(id);
|
||||
let had_focus = state.item.has_focus_target;
|
||||
state.has_focus_target = global_state.focused_widget == Some(id);
|
||||
let had_focus = state.has_focus_target;
|
||||
|
||||
if state.item.needs_update_focus_chain {
|
||||
state.item.focus_chain.clear();
|
||||
if state.item.accepts_focus {
|
||||
state.item.focus_chain.push(id);
|
||||
if state.needs_update_focus_chain {
|
||||
state.focus_chain.clear();
|
||||
if state.accepts_focus {
|
||||
state.focus_chain.push(id);
|
||||
}
|
||||
state.item.needs_update_focus_chain = false;
|
||||
state.needs_update_focus_chain = false;
|
||||
|
||||
let parent_state = &mut *state.item;
|
||||
recurse_on_children(
|
||||
id,
|
||||
widget.reborrow_mut(),
|
||||
state.children,
|
||||
properties.children,
|
||||
|widget, mut state, properties| {
|
||||
update_focus_chain_for_widget(
|
||||
global_state,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
&mut parent_state.focus_chain,
|
||||
);
|
||||
parent_state.merge_up(state.item);
|
||||
},
|
||||
);
|
||||
let parent_state = &mut *state;
|
||||
recurse_on_children(id, widget, children, |widget, mut state, properties| {
|
||||
update_focus_chain_for_widget(
|
||||
global_state,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
&mut parent_state.focus_chain,
|
||||
);
|
||||
parent_state.merge_up(state.item);
|
||||
});
|
||||
}
|
||||
|
||||
if !state.item.is_disabled && !state.item.is_stashed {
|
||||
parent_focus_chain.extend(&state.item.focus_chain);
|
||||
if !state.is_disabled && !state.is_stashed {
|
||||
parent_focus_chain.extend(&state.focus_chain);
|
||||
}
|
||||
|
||||
// had_focus is the old focus value. state.has_focused was replaced with parent_ctx.is_focused().
|
||||
// Therefore if had_focus is true but state.has_focused is false then the widget which is
|
||||
// currently focused is not part of the functional tree anymore and should resign the focus.
|
||||
if had_focus && !state.item.has_focus_target {
|
||||
if had_focus && !state.has_focus_target {
|
||||
// Not sure about this logic, might remove
|
||||
global_state.next_focused_widget = None;
|
||||
}
|
||||
state.item.has_focus_target = had_focus;
|
||||
state.has_focus_target = had_focus;
|
||||
}
|
||||
|
||||
pub(crate) fn run_update_focus_chain_pass(root: &mut RenderRoot) {
|
||||
|
@ -888,23 +896,29 @@ pub(crate) fn run_update_pointer_pass(root: &mut RenderRoot) {
|
|||
|
||||
let new_icon = if let (Some(icon_source), Some(pos)) = (icon_source, pointer_pos) {
|
||||
let (widget, state, properties) = root.widget_arena.get_all(icon_source);
|
||||
let children = WidgetArenaRef {
|
||||
widget_children: widget.children,
|
||||
widget_state_children: state.children,
|
||||
properties_children: properties.children,
|
||||
};
|
||||
let widget = widget.item;
|
||||
let state = state.item;
|
||||
let properties = properties.item;
|
||||
|
||||
let ctx = QueryCtx {
|
||||
global_state: &root.global_state,
|
||||
widget_state_children: state.children,
|
||||
widget_children: widget.children,
|
||||
widget_state: state.item,
|
||||
widget_state: state,
|
||||
properties: PropertiesRef {
|
||||
map: properties.item,
|
||||
default_map: root.default_properties.for_widget(widget.item.type_id()),
|
||||
map: properties,
|
||||
default_map: root.default_properties.for_widget(widget.type_id()),
|
||||
},
|
||||
properties_children: properties.children,
|
||||
children,
|
||||
};
|
||||
|
||||
if state.item.is_disabled {
|
||||
if state.is_disabled {
|
||||
CursorIcon::Default
|
||||
} else {
|
||||
widget.item.get_cursor(&ctx, pos)
|
||||
widget.get_cursor(&ctx, pos)
|
||||
}
|
||||
} else {
|
||||
CursorIcon::Default
|
||||
|
|
|
@ -377,7 +377,7 @@ impl<'arena, T> ArenaRefList<'arena, T> {
|
|||
|
||||
impl<'arena, T> ArenaMutList<'arena, T> {
|
||||
/// Returns `true` if the list has an element with the given id.
|
||||
pub fn has(self, id: impl Into<NodeId>) -> bool {
|
||||
pub fn has(&self, id: impl Into<NodeId>) -> bool {
|
||||
let id = id.into();
|
||||
self.children.contains_key(&id)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue