Skip to content

Commit

Permalink
wip: refactor WidgetRef to consist of Widget + QueryCtx
Browse files Browse the repository at this point in the history
  • Loading branch information
tomcur committed Sep 10, 2024
1 parent 61c2c79 commit 381d996
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 67 deletions.
7 changes: 6 additions & 1 deletion masonry/src/contexts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,10 +423,15 @@ impl<'w> QueryCtx<'w> {
.get_child(child.to_raw())
.expect("get: child not found");

WidgetRef {
let ctx = QueryCtx {
global_state: self.global_state,
widget_state_children: child_state.children,
widget_children: child.children,
widget_state: child_state.item,
};

WidgetRef {
ctx,
widget: child.item,
}
}
Expand Down
37 changes: 32 additions & 5 deletions masonry/src/render_root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ use crate::tree_arena::TreeArena;
use crate::widget::WidgetArena;
use crate::widget::{WidgetMut, WidgetRef, WidgetState};
use crate::{
AccessEvent, Action, BoxConstraints, CursorIcon, Handled, InternalLifeCycle, LifeCycle, Widget,
WidgetId, WidgetPod,
AccessEvent, Action, BoxConstraints, CursorIcon, Handled, InternalLifeCycle, LifeCycle,
QueryCtx, Widget, WidgetId, WidgetPod,
};

// --- MARK: STRUCTS ---
Expand Down Expand Up @@ -299,6 +299,7 @@ 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.widget_states.root_token();
let root_widget_token = self.widget_arena.widgets.root_token();
Expand All @@ -318,12 +319,38 @@ impl RenderRoot {
.downcast_ref::<Box<dyn Widget>>()
.unwrap();

WidgetRef {
let ctx = QueryCtx {
global_state: &self.state,
widget_state_children: state_ref.children,
widget_children: widget_ref.children,
widget_state: state_ref.item,
widget,
}
};

WidgetRef { ctx, widget }
}

/// Get a [`WidgetRef`] to a specific widget.
pub fn get_widget(&self, id: WidgetId) -> Option<WidgetRef<dyn Widget>> {
let state_ref = self.widget_arena.widget_states.find(id.to_raw())?;
let widget_ref = self
.widget_arena
.widgets
.find(id.to_raw())
.expect("found state but not widget");

// 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 ctx = QueryCtx {
global_state: &self.state,
widget_state_children: state_ref.children,
widget_children: widget_ref.children,
widget_state: state_ref.item,
};
Some(WidgetRef { ctx, widget })
}

/// Get a [`WidgetMut`] to the root widget.
Expand Down
8 changes: 3 additions & 5 deletions masonry/src/testing/harness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,14 +456,13 @@ impl TestHarness {
#[track_caller]
pub fn get_widget(&self, id: WidgetId) -> WidgetRef<'_, dyn Widget> {
self.render_root
.widget_arena
.try_get_widget_ref(id)
.get_widget(id)
.unwrap_or_else(|| panic!("could not find widget #{}", id.to_raw()))
}

/// Try to return the widget with the given id.
pub fn try_get_widget(&self, id: WidgetId) -> Option<WidgetRef<'_, dyn Widget>> {
self.render_root.widget_arena.try_get_widget_ref(id)
self.render_root.get_widget(id)
}

// TODO - link to focus documentation.
Expand All @@ -476,8 +475,7 @@ impl TestHarness {
// TODO - Multiple pointers
pub fn pointer_capture_target(&self) -> Option<WidgetRef<'_, dyn Widget>> {
self.render_root
.widget_arena
.try_get_widget_ref(self.render_root.state.pointer_capture_target?)
.get_widget(self.render_root.state.pointer_capture_target?)
}

// TODO - This is kinda redundant with the above
Expand Down
22 changes: 0 additions & 22 deletions masonry/src/widget/widget_arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0

use crate::tree_arena::{ArenaMut, ArenaRef, TreeArena};
use crate::widget::WidgetRef;
use crate::{Widget, WidgetId, WidgetState};

pub(crate) struct WidgetArena {
Expand Down Expand Up @@ -87,25 +86,4 @@ impl WidgetArena {
.find_mut(widget_id.to_raw())
.expect("get_state_mut: widget state not in widget tree")
}

pub fn try_get_widget_ref(&self, id: WidgetId) -> Option<WidgetRef<dyn Widget>> {
let state_ref = self.widget_states.find(id.to_raw())?;
let widget_ref = self
.widgets
.find(id.to_raw())
.expect("found state but not widget");

// 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;
Some(WidgetRef {
widget_state_children: state_ref.children,
widget_children: widget_ref.children,
widget_state: state_ref.item,
widget,
})
}
}
57 changes: 23 additions & 34 deletions masonry/src/widget/widget_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ use std::ops::Deref;
use smallvec::SmallVec;
use vello::kurbo::Point;

use crate::render_root::RenderRoot;
use crate::tree_arena::ArenaRefChildren;
use crate::{QueryCtx, Widget, WidgetId, WidgetState};
use crate::{render_root::RenderRoot, QueryCtx, Widget, WidgetId, WidgetState};

/// A rich reference to a [`Widget`].
///
Expand All @@ -24,9 +22,7 @@ use crate::{QueryCtx, Widget, WidgetId, WidgetState};
/// This is only for shared access to widgets. For widget mutation, see [`WidgetMut`](crate::widget::WidgetMut).

pub struct WidgetRef<'w, W: Widget + ?Sized> {
pub(crate) widget_state_children: ArenaRefChildren<'w, WidgetState>,
pub(crate) widget_children: ArenaRefChildren<'w, Box<dyn Widget>>,
pub(crate) widget_state: &'w WidgetState,
pub(crate) ctx: QueryCtx<'w>,
pub(crate) widget: &'w W,
}

Expand All @@ -36,9 +32,7 @@ pub struct WidgetRef<'w, W: Widget + ?Sized> {
impl<'w, W: Widget + ?Sized> Clone for WidgetRef<'w, W> {
fn clone(&self) -> Self {
Self {
widget_state_children: self.widget_state_children,
widget_children: self.widget_children,
widget_state: self.widget_state,
ctx: self.ctx,
widget: self.widget,
}
}
Expand Down Expand Up @@ -83,7 +77,7 @@ impl<'w, W: Widget + ?Sized> WidgetRef<'w, W> {
// TODO - Replace with individual methods from WidgetState
/// Get the [`WidgetState`] of the current widget.
pub fn state(self) -> &'w WidgetState {
self.widget_state
self.ctx.widget_state
}

/// Get the actual referenced `Widget`.
Expand All @@ -93,34 +87,32 @@ impl<'w, W: Widget + ?Sized> WidgetRef<'w, W> {

/// Get the [`WidgetId`] of the current widget.
pub fn id(&self) -> WidgetId {
self.widget_state.id
self.ctx.widget_state.id
}

/// Attempt to downcast to `WidgetRef` of concrete Widget type.
pub fn downcast<W2: Widget>(&self) -> Option<WidgetRef<'w, W2>> {
Some(WidgetRef {
widget_state_children: self.widget_state_children,
widget_children: self.widget_children,
widget_state: self.widget_state,
ctx: self.ctx,
widget: self.widget.as_any().downcast_ref()?,
})
}

/// Return widget's children.
pub fn children(&self) -> SmallVec<[WidgetRef<'w, dyn Widget>; 16]> {
let parent_id = self.widget_state.id.to_raw();
let parent_id = self.ctx.widget_state.id.to_raw();
self.widget
.children_ids()
.iter()
.map(|id| {
let id = id.to_raw();
let Some(state_ref) = self.widget_state_children.into_child(id) else {
let Some(state_ref) = self.ctx.widget_state_children.into_child(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.widget_children.into_child(id) else {
let Some(widget_ref) = self.ctx.widget_children.into_child(id) else {
panic!(
"Error in '{}' #{parent_id}: child #{id} has not been added to tree",
self.widget.short_type_name()
Expand All @@ -134,12 +126,14 @@ impl<'w, W: Widget + ?Sized> WidgetRef<'w, W> {
let widget = widget_ref.item;
let widget: &dyn Widget = &**widget;

WidgetRef {
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,
}
};

WidgetRef { ctx, widget }
})
.collect()
}
Expand All @@ -149,9 +143,7 @@ impl<'w, W: Widget> WidgetRef<'w, W> {
/// Return a type-erased `WidgetRef`.
pub fn as_dyn(&self) -> WidgetRef<'w, dyn Widget> {
WidgetRef {
widget_state_children: self.widget_state_children,
widget_children: self.widget_children,
widget_state: self.widget_state,
ctx: self.ctx,
widget: self.widget,
}
}
Expand Down Expand Up @@ -180,7 +172,7 @@ impl<'w> WidgetRef<'w, dyn Widget> {
) -> Option<WidgetRef<'a, dyn Widget>> {
// Get self from the widget arena to bind it to the arena's lifetime. Is there a way around
// this? Also see the comment inside the loop rebinding child to the arena's lifetime.
let mut innermost_widget = root.widget_arena.try_get_widget_ref(self.id()).unwrap();
let mut innermost_widget = root.get_widget(self.id()).unwrap();
let mut pos = pos;

if !self.state().layout_rect().contains(pos) {
Expand All @@ -196,16 +188,13 @@ impl<'w> WidgetRef<'w, dyn Widget> {
}
}

let (widget, state) = root.widget_arena.get_pair(innermost_widget.id());
let ctx = QueryCtx {
global_state: &root.state,
widget_state: state.item,
widget_state_children: state.children,
widget_children: widget.children,
};

if let Some(child) = innermost_widget.widget.get_child_at_pos(&ctx, pos) {
let child = root.widget_arena.try_get_widget_ref(child.id()).unwrap();
if let Some(child) = innermost_widget
.widget
.get_child_at_pos(&innermost_widget.ctx, pos)
{
// Get child from the widget arena to bind it to the arena's lifetime. Is there a
// way around this?
let child = root.get_widget(child.id()).unwrap();
innermost_widget = child;
} else {
break;
Expand Down

0 comments on commit 381d996

Please sign in to comment.