mirror of https://github.com/linebender/xilem
Add arbitrary properties to widgets (#873)
Add `Properties[Mut]` argument to widget methods. Add a third TreeArena to sort per-widget arbitrary property values. For the type-to-value map, I considered the following crates: - https://docs.rs/typemap/latest/typemap/ - https://crates.io/crates/typemap_rev - https://crates.io/crates/typemap-ors - https://github.com/chris-morgan/anymap - https://github.com/reivilibre/anymap3 Of these, anymap3 is the only one actively maintained (last commit less than 12 months ago). The code source itself is extremely light and simple; we may or may not decide to roll out our own implementation down the line. Add a BackgroundBrush property used by SizedBox as a proof of concept. Note that SizedBox still has its `background` field, but we should expect future widgets to use almost *exclusively* properties; properties usually shouldn't be redundant with local fields. To get there, we'll first need to better integrate properties in Xilem.
This commit is contained in:
parent
4e23dc5425
commit
60c037dc1f
|
@ -204,6 +204,12 @@ version = "1.0.95"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
|
||||
|
||||
[[package]]
|
||||
name = "anymap3"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "170433209e817da6aae2c51aa0dd443009a613425dd041ebfb2492d1c4c11a25"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.9"
|
||||
|
@ -1879,6 +1885,7 @@ version = "0.2.0"
|
|||
dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_winit",
|
||||
"anymap3",
|
||||
"assert_matches",
|
||||
"cursor-icon",
|
||||
"dpi",
|
||||
|
|
|
@ -57,6 +57,7 @@ dpi.workspace = true
|
|||
nv-flip.workspace = true
|
||||
tracing-tracy = { version = "0.11.3", optional = true }
|
||||
wgpu-profiler = { optional = true, version = "0.19.0", default-features = false }
|
||||
anymap3 = "1.0.1"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
web-time.workspace = true
|
||||
|
|
|
@ -16,8 +16,8 @@ use accesskit::{Node, Role};
|
|||
use masonry::app::{AppDriver, DriverCtx};
|
||||
use masonry::core::{
|
||||
AccessCtx, AccessEvent, Action, BoxConstraints, EventCtx, LayoutCtx, PaintCtx, PointerEvent,
|
||||
QueryCtx, RegisterCtx, StyleProperty, TextEvent, Update, UpdateCtx, Widget, WidgetId,
|
||||
WidgetPod,
|
||||
PropertiesMut, PropertiesRef, QueryCtx, RegisterCtx, StyleProperty, TextEvent, Update,
|
||||
UpdateCtx, Widget, WidgetId, WidgetPod,
|
||||
};
|
||||
use masonry::dpi::LogicalSize;
|
||||
use masonry::kurbo::{Point, Size};
|
||||
|
@ -148,7 +148,12 @@ impl CalcButton {
|
|||
}
|
||||
|
||||
impl Widget for CalcButton {
|
||||
fn on_pointer_event(&mut self, ctx: &mut EventCtx, event: &PointerEvent) {
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
event: &PointerEvent,
|
||||
) {
|
||||
match event {
|
||||
PointerEvent::PointerDown(_, _) => {
|
||||
if !ctx.is_disabled() {
|
||||
|
@ -176,9 +181,20 @@ impl Widget for CalcButton {
|
|||
}
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_access_event(&mut self, ctx: &mut EventCtx, event: &AccessEvent) {
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
event: &AccessEvent,
|
||||
) {
|
||||
if ctx.target() == ctx.widget_id() {
|
||||
match event.action {
|
||||
accesskit::Action::Click => {
|
||||
|
@ -189,7 +205,7 @@ impl Widget for CalcButton {
|
|||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, event: &Update) {
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, event: &Update) {
|
||||
// Masonry doesn't let us change a widget's attributes directly.
|
||||
// We use `mutate_later` to get a mutable reference to the inner widget
|
||||
// and change its border color. This is a simple way to implement a
|
||||
|
@ -214,20 +230,25 @@ impl Widget for CalcButton {
|
|||
ctx.register_child(&mut self.inner);
|
||||
}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
let size = ctx.run_layout(&mut self.inner, bc);
|
||||
ctx.place_child(&mut self.inner, Point::ORIGIN);
|
||||
|
||||
size
|
||||
}
|
||||
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _scene: &mut Scene) {}
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, _scene: &mut Scene) {}
|
||||
|
||||
fn accessibility_role(&self) -> Role {
|
||||
Role::Button
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, node: &mut Node) {
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, _props: &PropertiesRef<'_>, node: &mut Node) {
|
||||
let _name = match self.action {
|
||||
CalcAction::Digit(digit) => digit.to_string(),
|
||||
CalcAction::Op(op) => op.to_string(),
|
||||
|
|
|
@ -14,7 +14,7 @@ use accesskit::{Node, Role};
|
|||
use masonry::app::{AppDriver, DriverCtx};
|
||||
use masonry::core::{
|
||||
AccessCtx, AccessEvent, Action, BoxConstraints, EventCtx, LayoutCtx, ObjectFit, PaintCtx,
|
||||
PointerEvent, QueryCtx, RegisterCtx, TextEvent, Widget, WidgetId,
|
||||
PointerEvent, PropertiesMut, PropertiesRef, QueryCtx, RegisterCtx, TextEvent, Widget, WidgetId,
|
||||
};
|
||||
use masonry::kurbo::{Affine, BezPath, Point, Rect, Size, Stroke};
|
||||
use masonry::palette;
|
||||
|
@ -37,15 +37,38 @@ impl AppDriver for Driver {
|
|||
struct CustomWidget(String);
|
||||
|
||||
impl Widget for CustomWidget {
|
||||
fn on_pointer_event(&mut self, _ctx: &mut EventCtx, _event: &PointerEvent) {}
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &PointerEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_access_event(&mut self, _ctx: &mut EventCtx, _event: &AccessEvent) {}
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &AccessEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn register_children(&mut self, _ctx: &mut RegisterCtx) {}
|
||||
|
||||
fn layout(&mut self, _layout_ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
_layout_ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
// BoxConstraints are passed by the parent widget.
|
||||
// This method can return any Size within those constraints:
|
||||
// bc.constrain(my_size)
|
||||
|
@ -68,7 +91,7 @@ impl Widget for CustomWidget {
|
|||
// The paint method gets called last, after an event flow.
|
||||
// It goes event -> update -> layout -> paint, and each method can influence the next.
|
||||
// Basically, anything that changes the appearance of a widget causes a paint.
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) {
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, scene: &mut Scene) {
|
||||
// Clear the whole widget with the color of your choice
|
||||
// (ctx.size() returns the size of the layout rect we're painting in)
|
||||
// Note: ctx also has a `clear` method, but that clears the whole context,
|
||||
|
@ -137,7 +160,7 @@ impl Widget for CustomWidget {
|
|||
Role::Window
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, node: &mut Node) {
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, _props: &PropertiesRef<'_>, node: &mut Node) {
|
||||
let text = &self.0;
|
||||
node.set_label(
|
||||
format!("This is a demo of the Masonry Widget trait. Masonry has accessibility tree support. The demo shows colored shapes with the text '{text}'."),
|
||||
|
|
|
@ -741,7 +741,8 @@ impl MasonryState<'_> {
|
|||
window.show_window_menu(position);
|
||||
}
|
||||
RenderRootSignal::WidgetSelectedInInspector(widget_id) => {
|
||||
let (widget, state) = self.render_root.widget_arena.get_pair(widget_id);
|
||||
let (widget, state, _properties) =
|
||||
self.render_root.widget_arena.get_all(widget_id);
|
||||
let widget_name = widget.item.short_type_name();
|
||||
let display_name = if let Some(debug_text) = widget.item.get_debug_text() {
|
||||
format!("{widget_name}<{debug_text}>")
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
use std::collections::{HashMap, VecDeque};
|
||||
|
||||
use accesskit::{ActionRequest, TreeUpdate};
|
||||
use anymap3::AnyMap;
|
||||
use parley::fontique::{self, Collection, CollectionOptions, SourceCache};
|
||||
use parley::{FontContext, LayoutContext};
|
||||
use tracing::{info_span, warn};
|
||||
|
@ -21,8 +22,8 @@ use web_time::Instant;
|
|||
|
||||
use crate::Handled;
|
||||
use crate::core::{
|
||||
AccessEvent, Action, BrushIndex, PointerEvent, QueryCtx, TextEvent, Widget, WidgetArena,
|
||||
WidgetId, WidgetMut, WidgetPod, WidgetRef, WidgetState, WindowEvent,
|
||||
AccessEvent, Action, BrushIndex, PointerEvent, PropertiesRef, QueryCtx, TextEvent, Widget,
|
||||
WidgetArena, WidgetId, WidgetMut, WidgetPod, WidgetRef, WidgetState, WindowEvent,
|
||||
};
|
||||
use crate::dpi::{LogicalPosition, LogicalSize, PhysicalSize};
|
||||
use crate::passes::accessibility::run_accessibility_pass;
|
||||
|
@ -294,6 +295,7 @@ impl RenderRoot {
|
|||
widget_arena: WidgetArena {
|
||||
widgets: TreeArena::new(),
|
||||
states: TreeArena::new(),
|
||||
properties: TreeArena::new(),
|
||||
},
|
||||
rebuild_access_tree: true,
|
||||
debug_paint,
|
||||
|
@ -476,21 +478,32 @@ impl RenderRoot {
|
|||
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_children: properties_ref.children,
|
||||
};
|
||||
WidgetRef { ctx, widget }
|
||||
let properties = PropertiesRef {
|
||||
map: properties_ref.item,
|
||||
};
|
||||
WidgetRef {
|
||||
ctx,
|
||||
properties,
|
||||
widget,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a [`WidgetRef`] to a specific widget.
|
||||
|
@ -501,6 +514,11 @@ impl RenderRoot {
|
|||
.widgets
|
||||
.find(id)
|
||||
.expect("found state but not widget");
|
||||
let properties_ref = self
|
||||
.widget_arena
|
||||
.properties
|
||||
.find(id)
|
||||
.expect("found state but not properties");
|
||||
|
||||
let widget = &**widget_ref.item;
|
||||
let ctx = QueryCtx {
|
||||
|
@ -508,8 +526,16 @@ impl RenderRoot {
|
|||
widget_state_children: state_ref.children,
|
||||
widget_children: widget_ref.children,
|
||||
widget_state: state_ref.item,
|
||||
properties_children: properties_ref.children,
|
||||
};
|
||||
Some(WidgetRef { ctx, widget })
|
||||
let properties = PropertiesRef {
|
||||
map: properties_ref.item,
|
||||
};
|
||||
Some(WidgetRef {
|
||||
ctx,
|
||||
properties,
|
||||
widget,
|
||||
})
|
||||
}
|
||||
|
||||
/// Get a [`WidgetMut`] to the root widget.
|
||||
|
@ -622,6 +648,7 @@ impl RenderRoot {
|
|||
fn request_render_all_in(
|
||||
mut widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
state: ArenaMut<'_, WidgetState>,
|
||||
properties: ArenaMut<'_, AnyMap>,
|
||||
) {
|
||||
state.item.needs_paint = true;
|
||||
state.item.needs_accessibility = true;
|
||||
|
@ -633,14 +660,16 @@ impl RenderRoot {
|
|||
id,
|
||||
widget.reborrow_mut(),
|
||||
state.children,
|
||||
|widget, mut state| {
|
||||
request_render_all_in(widget, state.reborrow_mut());
|
||||
properties.children,
|
||||
|widget, state, properties| {
|
||||
request_render_all_in(widget, state, properties);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
let (root_widget, mut root_state) = self.widget_arena.get_pair_mut(self.root.id());
|
||||
request_render_all_in(root_widget, root_state.reborrow_mut());
|
||||
let (root_widget, root_state, root_properties) =
|
||||
self.widget_arena.get_all_mut(self.root.id());
|
||||
request_render_all_in(root_widget, root_state, root_properties);
|
||||
self.global_state
|
||||
.emit_signal(RenderRootSignal::RequestRedraw);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
//! The context types that are passed into various widget methods.
|
||||
|
||||
use accesskit::TreeUpdate;
|
||||
use anymap3::AnyMap;
|
||||
use dpi::LogicalPosition;
|
||||
use parley::{FontContext, LayoutContext};
|
||||
use tracing::{trace, warn};
|
||||
|
@ -12,8 +13,8 @@ use winit::window::ResizeDirection;
|
|||
|
||||
use crate::app::{MutateCallback, RenderRootSignal, RenderRootState};
|
||||
use crate::core::{
|
||||
Action, AllowRawMut, BoxConstraints, BrushIndex, CreateWidget, FromDynWidget, Widget, WidgetId,
|
||||
WidgetMut, WidgetPod, WidgetRef, WidgetState,
|
||||
Action, AllowRawMut, BoxConstraints, BrushIndex, CreateWidget, FromDynWidget, PropertiesMut,
|
||||
PropertiesRef, Widget, WidgetId, WidgetMut, WidgetPod, WidgetRef, WidgetState,
|
||||
};
|
||||
use crate::kurbo::{Affine, Insets, Point, Rect, Size, Vec2};
|
||||
use crate::passes::layout::run_layout_on;
|
||||
|
@ -50,6 +51,8 @@ pub struct MutateCtx<'a> {
|
|||
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>,
|
||||
}
|
||||
|
||||
/// A context provided inside of [`WidgetRef`].
|
||||
|
@ -61,6 +64,7 @@ pub struct QueryCtx<'a> {
|
|||
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_children: ArenaRefList<'a, AnyMap>,
|
||||
}
|
||||
|
||||
/// A context provided to Widget event-handling methods.
|
||||
|
@ -69,6 +73,7 @@ pub struct EventCtx<'a> {
|
|||
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) target: WidgetId,
|
||||
pub(crate) allow_pointer_capture: bool,
|
||||
pub(crate) is_handled: bool,
|
||||
|
@ -78,6 +83,7 @@ pub struct EventCtx<'a> {
|
|||
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>,
|
||||
#[cfg(debug_assertions)]
|
||||
pub(crate) registered_ids: Vec<WidgetId>,
|
||||
}
|
||||
|
@ -88,6 +94,7 @@ pub struct UpdateCtx<'a> {
|
|||
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>,
|
||||
}
|
||||
|
||||
// TODO - Change this once other layout methods are added.
|
||||
|
@ -97,6 +104,7 @@ pub struct LayoutCtx<'a> {
|
|||
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>,
|
||||
}
|
||||
|
||||
/// A context provided to the [`Widget::compose`] method.
|
||||
|
@ -122,6 +130,7 @@ pub struct AccessCtx<'a> {
|
|||
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) tree_update: &'a mut TreeUpdate,
|
||||
pub(crate) rebuild_all: bool,
|
||||
}
|
||||
|
@ -220,12 +229,20 @@ impl MutateCtx<'_> {
|
|||
.widget_children
|
||||
.item_mut(child.id())
|
||||
.expect("get_mut: child not found");
|
||||
let child_properties = self
|
||||
.properties_children
|
||||
.item_mut(child.id())
|
||||
.expect("get_mut: child not found");
|
||||
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,
|
||||
},
|
||||
properties_children: child_properties.children,
|
||||
};
|
||||
WidgetMut {
|
||||
ctx: child_ctx,
|
||||
|
@ -243,6 +260,18 @@ impl MutateCtx<'_> {
|
|||
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(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn update_mut(&mut self) -> UpdateCtx<'_> {
|
||||
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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -265,21 +294,30 @@ impl<'w> QueryCtx<'w> {
|
|||
.widget_state_children
|
||||
.into_item(child)
|
||||
.expect("get: child not found");
|
||||
let child = self
|
||||
let child_widget = self
|
||||
.widget_children
|
||||
.into_item(child)
|
||||
.expect("get: child not found");
|
||||
let child_properties = self
|
||||
.properties_children
|
||||
.into_item(child)
|
||||
.expect("get: child not found");
|
||||
|
||||
let ctx = QueryCtx {
|
||||
global_state: self.global_state,
|
||||
widget_state_children: child_state.children,
|
||||
widget_children: child.children,
|
||||
widget_children: child_widget.children,
|
||||
widget_state: child_state.item,
|
||||
properties_children: child_properties.children,
|
||||
};
|
||||
let properties = PropertiesRef {
|
||||
map: child_properties.item,
|
||||
};
|
||||
|
||||
WidgetRef {
|
||||
ctx,
|
||||
widget: &**child.item,
|
||||
properties,
|
||||
widget: &**child_widget.item,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1185,7 +1223,12 @@ impl RegisterCtx<'_> {
|
|||
/// Container widgets should call this on all their children in
|
||||
/// their implementation of [`Widget::register_children`].
|
||||
pub fn register_child(&mut self, child: &mut WidgetPod<impl Widget + ?Sized>) {
|
||||
let Some(CreateWidget { widget, transform }) = child.take_inner() else {
|
||||
let Some(CreateWidget {
|
||||
widget,
|
||||
transform,
|
||||
properties,
|
||||
}) = child.take_inner()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
@ -1199,6 +1242,7 @@ impl RegisterCtx<'_> {
|
|||
|
||||
self.widget_children.insert(id, widget.as_box_dyn());
|
||||
self.widget_state_children.insert(id, state);
|
||||
self.properties_children.insert(id, properties.map);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1250,11 +1294,16 @@ macro_rules! impl_get_raw {
|
|||
.widget_children
|
||||
.item_mut(child.id())
|
||||
.expect("get_raw_ref: child not found");
|
||||
let child_properties = self
|
||||
.properties_children
|
||||
.item_mut(child.id())
|
||||
.expect("get_raw_ref: child not found");
|
||||
#[allow(clippy::needless_update)]
|
||||
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,
|
||||
..*self
|
||||
};
|
||||
|
@ -1283,11 +1332,16 @@ macro_rules! impl_get_raw {
|
|||
.widget_children
|
||||
.item_mut(child.id())
|
||||
.expect("get_raw_mut: child not found");
|
||||
let child_properties = self
|
||||
.properties_children
|
||||
.item_mut(child.id())
|
||||
.expect("get_raw_mut: child not found");
|
||||
#[allow(clippy::needless_update)]
|
||||
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,
|
||||
..*self
|
||||
};
|
||||
|
@ -1323,10 +1377,15 @@ impl<'s> AccessCtx<'s> {
|
|||
.widget_children
|
||||
.item_mut(child.id())
|
||||
.expect("get_raw_ref: child not found");
|
||||
let child_properties = self
|
||||
.properties_children
|
||||
.item_mut(child.id())
|
||||
.expect("get_raw_ref: child not found");
|
||||
let child_ctx = AccessCtx {
|
||||
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,
|
||||
tree_update: self.tree_update,
|
||||
rebuild_all: self.rebuild_all,
|
||||
|
|
|
@ -8,6 +8,7 @@ mod box_constraints;
|
|||
mod contexts;
|
||||
mod event;
|
||||
mod object_fit;
|
||||
mod properties;
|
||||
mod text;
|
||||
#[allow(missing_docs, reason = "TODO")]
|
||||
mod widget;
|
||||
|
@ -30,6 +31,7 @@ pub use event::{
|
|||
WindowTheme,
|
||||
};
|
||||
pub use object_fit::ObjectFit;
|
||||
pub use properties::{Properties, PropertiesMut, PropertiesRef};
|
||||
pub use text::{ArcStr, BrushIndex, StyleProperty, StyleSet, render_text};
|
||||
pub use widget::find_widget_at_pos;
|
||||
pub use widget::{AllowRawMut, FromDynWidget, Widget, WidgetId};
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
// Copyright 2025 the Xilem Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use anymap3::{AnyMap, Entry};
|
||||
|
||||
// TODO - Add PropertyValue wrapper struct that implements receiver trait.
|
||||
// Return PropertyValue<T> instead of Option<T> from methods.
|
||||
|
||||
/// A collection of properties that a widget can be created with.
|
||||
///
|
||||
/// See [properties documentation](crate::doc::doc_04b_widget_properties) for details.
|
||||
#[derive(Default)]
|
||||
pub struct Properties {
|
||||
pub(crate) map: AnyMap,
|
||||
}
|
||||
|
||||
/// Reference to a collection of properties that a widget has access to.
|
||||
///
|
||||
/// Used by the [`Widget`] trait during rendering passes and in some search methods.
|
||||
///
|
||||
/// See [properties documentation](crate::doc::doc_04b_widget_properties) for
|
||||
/// details.
|
||||
///
|
||||
/// [`Widget`]: crate::core::Widget
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct PropertiesRef<'a> {
|
||||
pub(crate) map: &'a AnyMap,
|
||||
}
|
||||
|
||||
/// Mutable reference to a collection of properties that a widget has access to.
|
||||
///
|
||||
/// Used by the [`Widget`] trait during most passes.
|
||||
///
|
||||
/// See [properties documentation](crate::doc::doc_04b_widget_properties) for
|
||||
/// details.
|
||||
///
|
||||
/// [`Widget`]: crate::core::Widget
|
||||
pub struct PropertiesMut<'a> {
|
||||
pub(crate) map: &'a mut AnyMap,
|
||||
}
|
||||
|
||||
impl Properties {
|
||||
/// Create an empty collection of properties.
|
||||
pub fn new() -> Self {
|
||||
Self { map: AnyMap::new() }
|
||||
}
|
||||
|
||||
/// Get a reference to the properties.
|
||||
pub fn ref_(&self) -> PropertiesRef<'_> {
|
||||
PropertiesRef { map: &self.map }
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the properties.
|
||||
pub fn mut_(&mut self) -> PropertiesMut<'_> {
|
||||
PropertiesMut { map: &mut self.map }
|
||||
}
|
||||
}
|
||||
|
||||
impl PropertiesRef<'_> {
|
||||
/// Returns true if the widget has a property of type `T`.
|
||||
pub fn contains<T: 'static>(&self) -> bool {
|
||||
self.map.contains::<T>()
|
||||
}
|
||||
|
||||
/// Get value of property `T`, or None if the widget has no `T` property.
|
||||
pub fn get<T: 'static>(&self) -> Option<&T> {
|
||||
self.map.get::<T>()
|
||||
}
|
||||
}
|
||||
|
||||
impl PropertiesMut<'_> {
|
||||
/// Returns true if the widget has a property of type `T`.
|
||||
pub fn contains<T: 'static>(&self) -> bool {
|
||||
self.map.contains::<T>()
|
||||
}
|
||||
|
||||
/// Get value of property `T`, or None if the widget has no `T` property.
|
||||
pub fn get<T: 'static>(&self) -> Option<&T> {
|
||||
self.map.get::<T>()
|
||||
}
|
||||
|
||||
/// Get value of property `T`, or None if the widget has no `T` property.
|
||||
///
|
||||
/// If you're using a `WidgetMut`, call [`WidgetMut::get_prop_mut`] instead.
|
||||
///
|
||||
/// [`WidgetMut::get_prop_mut`]: crate::core::WidgetMut::get_prop_mut
|
||||
pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
|
||||
self.map.get_mut::<T>()
|
||||
}
|
||||
|
||||
/// Set property `T` to given value. Returns the previous value if `T` was already set.
|
||||
///
|
||||
/// If you're using a `WidgetMut`, call [`WidgetMut::insert_prop`] instead.
|
||||
///
|
||||
/// [`WidgetMut::insert_prop`]: crate::core::WidgetMut::insert_prop
|
||||
pub fn insert<T: 'static>(&mut self, value: T) -> Option<T> {
|
||||
self.map.insert(value)
|
||||
}
|
||||
|
||||
/// Remove property `T`. Returns the previous value if `T` was set.
|
||||
///
|
||||
/// If you're using a `WidgetMut`, call [`WidgetMut::remove_prop`] instead.
|
||||
///
|
||||
/// [`WidgetMut::remove_prop`]: crate::core::WidgetMut::remove_prop
|
||||
pub fn remove<T: 'static>(&mut self) -> Option<T> {
|
||||
self.map.remove::<T>()
|
||||
}
|
||||
|
||||
/// Returns an entry that can be used to add, update, or remove a property.
|
||||
///
|
||||
/// If you're using a `WidgetMut`, call [`WidgetMut::prop_entry`] instead.
|
||||
///
|
||||
/// [`WidgetMut::prop_entry`]: crate::core::WidgetMut::prop_entry
|
||||
pub fn entry<T: 'static>(&mut self) -> Entry<'_, dyn std::any::Any, T> {
|
||||
self.map.entry::<T>()
|
||||
}
|
||||
|
||||
/// Get a `PropertiesMut` for the same underlying properties with a shorter lifetime.
|
||||
pub fn reborrow_mut(&mut self) -> PropertiesMut<'_> {
|
||||
PropertiesMut {
|
||||
map: &mut *self.map,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright 2018 the Xilem Authors and the Druid Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::any::Any;
|
||||
use std::any::{Any, TypeId};
|
||||
use std::fmt::Display;
|
||||
use std::num::NonZeroU64;
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
|
@ -16,7 +16,8 @@ use vello::Scene;
|
|||
use crate::AsAny;
|
||||
use crate::core::{
|
||||
AccessCtx, AccessEvent, BoxConstraints, ComposeCtx, EventCtx, LayoutCtx, PaintCtx,
|
||||
PointerEvent, QueryCtx, RegisterCtx, TextEvent, Update, UpdateCtx, WidgetRef,
|
||||
PointerEvent, PropertiesMut, PropertiesRef, QueryCtx, RegisterCtx, TextEvent, Update,
|
||||
UpdateCtx, WidgetRef,
|
||||
};
|
||||
use crate::kurbo::{Point, Size};
|
||||
|
||||
|
@ -128,19 +129,37 @@ pub trait Widget: AsAny + AsDynWidget {
|
|||
///
|
||||
/// Pointer events will target the widget under the pointer, and then the
|
||||
/// event will bubble to each of its parents.
|
||||
fn on_pointer_event(&mut self, ctx: &mut EventCtx, event: &PointerEvent) {}
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
event: &PointerEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
/// Handle a text event.
|
||||
///
|
||||
/// Text events will target the [focused widget], then bubble to each parent.
|
||||
///
|
||||
/// [focused widget]: crate::doc::doc_06_masonry_concepts#text-focus
|
||||
fn on_text_event(&mut self, ctx: &mut EventCtx, event: &TextEvent) {}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
/// Handle an event from the platform's accessibility API.
|
||||
///
|
||||
/// Accessibility events target a specific widget id, then bubble to each parent.
|
||||
fn on_access_event(&mut self, ctx: &mut EventCtx, event: &AccessEvent) {}
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
event: &AccessEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
/// Called at the beginning of a new animation frame.
|
||||
///
|
||||
|
@ -161,7 +180,13 @@ pub trait Widget: AsAny + AsDynWidget {
|
|||
/// For that reason, you should try to avoid doing anything computationally
|
||||
/// intensive in response to an `AnimFrame` event: it might make the app miss
|
||||
/// the monitor's refresh, causing lag or jerky animations.
|
||||
fn on_anim_frame(&mut self, ctx: &mut UpdateCtx, interval: u64) {}
|
||||
fn on_anim_frame(
|
||||
&mut self,
|
||||
ctx: &mut UpdateCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
interval: u64,
|
||||
) {
|
||||
}
|
||||
|
||||
// TODO - Reorder methods to match 02_implementing_widget.md
|
||||
|
||||
|
@ -179,7 +204,11 @@ pub trait Widget: AsAny + AsDynWidget {
|
|||
/// This method is called to notify your widget of certain special events,
|
||||
/// (available in the [`Update`] enum) that are generally related to
|
||||
/// changes in the widget graph or in the state of your specific widget.
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, event: &Update) {}
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, event: &Update) {}
|
||||
|
||||
// TODO - Remove default implementation
|
||||
/// Handle a property being added, changed, or removed.
|
||||
fn property_changed(&mut self, ctx: &mut UpdateCtx, property_type: TypeId) {}
|
||||
|
||||
/// Compute layout and return the widget's size.
|
||||
///
|
||||
|
@ -206,7 +235,12 @@ pub trait Widget: AsAny + AsDynWidget {
|
|||
/// While each widget should try to return a size that fits the input constraints,
|
||||
/// **any widget may return a size that doesn't fit its constraints**, and container
|
||||
/// widgets should handle those cases gracefully.
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size;
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size;
|
||||
|
||||
fn compose(&mut self, ctx: &mut ComposeCtx) {}
|
||||
|
||||
|
@ -216,11 +250,11 @@ pub trait Widget: AsAny + AsDynWidget {
|
|||
/// children, or annotations (for example, scrollbars) by painting
|
||||
/// afterwards. In addition, they can apply masks and transforms on
|
||||
/// the render context, which is especially useful for scrolling.
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene);
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, scene: &mut Scene);
|
||||
|
||||
fn accessibility_role(&self) -> Role;
|
||||
|
||||
fn accessibility(&mut self, ctx: &mut AccessCtx, node: &mut Node);
|
||||
fn accessibility(&mut self, ctx: &mut AccessCtx, _props: &PropertiesRef<'_>, node: &mut Node);
|
||||
|
||||
/// Return ids of this widget's children.
|
||||
///
|
||||
|
@ -315,11 +349,13 @@ pub trait Widget: AsAny + AsDynWidget {
|
|||
fn find_widget_at_pos<'c>(
|
||||
&'c self,
|
||||
ctx: QueryCtx<'c>,
|
||||
props: PropertiesRef<'c>,
|
||||
pos: Point,
|
||||
) -> Option<WidgetRef<'c, dyn Widget>> {
|
||||
find_widget_at_pos(
|
||||
&WidgetRef {
|
||||
widget: self.as_dyn(),
|
||||
properties: props,
|
||||
ctx,
|
||||
},
|
||||
pos,
|
||||
|
@ -383,7 +419,11 @@ pub fn find_widget_at_pos<'c>(
|
|||
// of overlapping children.
|
||||
for child_id in widget.children_ids().iter().rev() {
|
||||
let child_ref = widget.ctx.get(*child_id);
|
||||
if let Some(child) = child_ref.widget.find_widget_at_pos(child_ref.ctx, pos) {
|
||||
if let Some(child) =
|
||||
child_ref
|
||||
.widget
|
||||
.find_widget_at_pos(child_ref.ctx, child_ref.properties, pos)
|
||||
{
|
||||
return Some(child);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright 2024 the Xilem Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use anymap3::AnyMap;
|
||||
use tree_arena::{ArenaMut, ArenaRef, TreeArena};
|
||||
|
||||
use crate::core::{Widget, WidgetId, WidgetState};
|
||||
|
@ -8,6 +9,7 @@ use crate::core::{Widget, WidgetId, WidgetState};
|
|||
pub(crate) struct WidgetArena {
|
||||
pub(crate) widgets: TreeArena<Box<dyn Widget>>,
|
||||
pub(crate) states: TreeArena<WidgetState>,
|
||||
pub(crate) properties: TreeArena<AnyMap>,
|
||||
}
|
||||
|
||||
impl WidgetArena {
|
||||
|
@ -27,10 +29,14 @@ impl WidgetArena {
|
|||
}
|
||||
|
||||
#[track_caller]
|
||||
pub(crate) fn get_pair(
|
||||
pub(crate) fn get_all(
|
||||
&self,
|
||||
widget_id: WidgetId,
|
||||
) -> (ArenaRef<Box<dyn Widget>>, ArenaRef<WidgetState>) {
|
||||
) -> (
|
||||
ArenaRef<Box<dyn Widget>>,
|
||||
ArenaRef<WidgetState>,
|
||||
ArenaRef<AnyMap>,
|
||||
) {
|
||||
let widget = self
|
||||
.widgets
|
||||
.find(widget_id)
|
||||
|
@ -39,14 +45,22 @@ impl WidgetArena {
|
|||
.states
|
||||
.find(widget_id)
|
||||
.expect("get_pair: widget state not in widget tree");
|
||||
(widget, state)
|
||||
let properties = self
|
||||
.properties
|
||||
.find(widget_id)
|
||||
.expect("get_pair: widget properties not in widget tree");
|
||||
(widget, state, properties)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub(crate) fn get_pair_mut(
|
||||
pub(crate) fn get_all_mut(
|
||||
&mut self,
|
||||
widget_id: WidgetId,
|
||||
) -> (ArenaMut<Box<dyn Widget>>, ArenaMut<WidgetState>) {
|
||||
) -> (
|
||||
ArenaMut<Box<dyn Widget>>,
|
||||
ArenaMut<WidgetState>,
|
||||
ArenaMut<AnyMap>,
|
||||
) {
|
||||
let widget = self
|
||||
.widgets
|
||||
.find_mut(widget_id)
|
||||
|
@ -55,7 +69,11 @@ impl WidgetArena {
|
|||
.states
|
||||
.find_mut(widget_id)
|
||||
.expect("get_pair_mut: widget state not in widget tree");
|
||||
(widget, state)
|
||||
let properties = self
|
||||
.properties
|
||||
.find_mut(widget_id)
|
||||
.expect("get_pair_mut: widget properties not in widget tree");
|
||||
(widget, state, properties)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
// Copyright 2018 the Xilem Authors and the Druid Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::any::TypeId;
|
||||
|
||||
use anymap3::Entry;
|
||||
|
||||
use crate::core::{FromDynWidget, MutateCtx, Widget};
|
||||
use crate::kurbo::Affine;
|
||||
|
||||
|
@ -23,6 +27,7 @@ use crate::kurbo::Affine;
|
|||
///
|
||||
/// Once the Receiver trait is stabilized, `WidgetMut` will implement it so that custom
|
||||
/// widgets in downstream crates can use `WidgetMut` as the receiver for inherent methods.
|
||||
#[non_exhaustive]
|
||||
pub struct WidgetMut<'a, W: Widget + ?Sized> {
|
||||
pub ctx: MutateCtx<'a>,
|
||||
pub widget: &'a mut W,
|
||||
|
@ -48,6 +53,44 @@ impl<W: Widget + ?Sized> WidgetMut<'_, W> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns true if the widget has a property of type `T`.
|
||||
pub fn get_prop<T: 'static>(&self) -> Option<&T> {
|
||||
self.ctx.properties.get::<T>()
|
||||
}
|
||||
|
||||
/// Get value of property `T`, or None if the widget has no `T` property.
|
||||
pub fn contains_prop<T: 'static>(&self) -> bool {
|
||||
self.ctx.properties.contains::<T>()
|
||||
}
|
||||
|
||||
/// Get value of property `T`, or None if the widget has no `T` property.
|
||||
pub fn get_prop_mut<T: 'static>(&mut self) -> Option<&mut T> {
|
||||
self.widget
|
||||
.property_changed(&mut self.ctx.update_mut(), TypeId::of::<T>());
|
||||
self.ctx.properties.get_mut::<T>()
|
||||
}
|
||||
|
||||
/// Set property `T` to given value. Returns the previous value if `T` was already set.
|
||||
pub fn insert_prop<T: 'static>(&mut self, value: T) -> Option<T> {
|
||||
self.widget
|
||||
.property_changed(&mut self.ctx.update_mut(), TypeId::of::<T>());
|
||||
self.ctx.properties.insert(value)
|
||||
}
|
||||
|
||||
/// Remove property `T`. Returns the previous value if `T` was set.
|
||||
pub fn remove_prop<T: 'static>(&mut self) -> Option<T> {
|
||||
self.widget
|
||||
.property_changed(&mut self.ctx.update_mut(), TypeId::of::<T>());
|
||||
self.ctx.properties.remove::<T>()
|
||||
}
|
||||
|
||||
/// Returns an entry that can be used to add, update, or remove a property.
|
||||
pub fn prop_entry<T: 'static>(&mut self) -> Entry<'_, dyn std::any::Any, T> {
|
||||
self.widget
|
||||
.property_changed(&mut self.ctx.update_mut(), TypeId::of::<T>());
|
||||
self.ctx.properties.entry::<T>()
|
||||
}
|
||||
|
||||
/// Set the local transform of this widget.
|
||||
///
|
||||
/// It behaves similarly as CSS transforms.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright 2018 the Xilem Authors and the Druid Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::core::{Widget, WidgetId};
|
||||
use crate::core::{Properties, Widget, WidgetId};
|
||||
use crate::kurbo::Affine;
|
||||
|
||||
/// A container for one widget in the hierarchy.
|
||||
|
@ -25,6 +25,7 @@ pub struct WidgetPod<W: ?Sized> {
|
|||
pub(crate) struct CreateWidget<W: ?Sized> {
|
||||
pub(crate) widget: Box<W>,
|
||||
pub(crate) transform: Affine,
|
||||
pub(crate) properties: Properties,
|
||||
}
|
||||
|
||||
enum WidgetPodInner<W: ?Sized> {
|
||||
|
@ -60,9 +61,23 @@ impl<W: Widget + ?Sized> WidgetPod<W> {
|
|||
inner: WidgetPodInner::Create(CreateWidget {
|
||||
widget: inner,
|
||||
transform,
|
||||
properties: Properties::new(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
// TODO - Remove transform, have it as a special-case property instead.
|
||||
pub fn new_with(inner: Box<W>, id: WidgetId, transform: Affine, props: Properties) -> Self {
|
||||
Self {
|
||||
id,
|
||||
inner: WidgetPodInner::Create(CreateWidget {
|
||||
widget: inner,
|
||||
transform,
|
||||
properties: props,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn incomplete(&self) -> bool {
|
||||
matches!(self.inner, WidgetPodInner::Create(_))
|
||||
}
|
||||
|
@ -94,6 +109,7 @@ impl<W: Widget + ?Sized> WidgetPod<W> {
|
|||
inner: WidgetPodInner::Create(CreateWidget {
|
||||
widget: inner.widget.as_box_dyn(),
|
||||
transform: inner.transform,
|
||||
properties: inner.properties,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use std::ops::Deref;
|
|||
use smallvec::SmallVec;
|
||||
use vello::kurbo::Point;
|
||||
|
||||
use crate::core::{QueryCtx, Widget, WidgetId};
|
||||
use crate::core::{PropertiesRef, QueryCtx, Widget, WidgetId};
|
||||
|
||||
/// A rich reference to a [`Widget`].
|
||||
///
|
||||
|
@ -22,18 +22,16 @@ use crate::core::{QueryCtx, Widget, WidgetId};
|
|||
/// This is only for shared access to widgets. For widget mutation, see [`WidgetMut`](crate::core::WidgetMut).
|
||||
pub struct WidgetRef<'w, W: Widget + ?Sized> {
|
||||
pub(crate) ctx: QueryCtx<'w>,
|
||||
pub(crate) properties: PropertiesRef<'w>,
|
||||
pub(crate) widget: &'w W,
|
||||
}
|
||||
|
||||
// --- TRAIT IMPLS ---
|
||||
// --- MARK: TRAIT IMPLS ---
|
||||
|
||||
#[allow(clippy::non_canonical_clone_impl)]
|
||||
impl<W: Widget + ?Sized> Clone for WidgetRef<'_, W> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
ctx: self.ctx,
|
||||
widget: self.widget,
|
||||
}
|
||||
Self { ..*self }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,7 +68,7 @@ impl<W: Widget + ?Sized> Deref for WidgetRef<'_, W> {
|
|||
}
|
||||
}
|
||||
|
||||
// --- IMPLS ---
|
||||
// --- MARK: IMPLS ---
|
||||
|
||||
impl<'w, W: Widget + ?Sized> WidgetRef<'w, W> {
|
||||
/// Get a [`QueryCtx`] with information about the current widget.
|
||||
|
@ -88,10 +86,21 @@ impl<'w, W: Widget + ?Sized> WidgetRef<'w, W> {
|
|||
self.ctx.widget_state.id
|
||||
}
|
||||
|
||||
/// Returns true if the widget has a property of type `T`.
|
||||
pub fn get_prop<T: 'static>(&self) -> Option<&T> {
|
||||
self.properties.get::<T>()
|
||||
}
|
||||
|
||||
/// Get value of property `T`, or None if the widget has no `T` property.
|
||||
pub fn contains_prop<T: 'static>(&self) -> bool {
|
||||
self.properties.contains::<T>()
|
||||
}
|
||||
|
||||
/// Attempt to downcast to `WidgetRef` of concrete Widget type.
|
||||
pub fn downcast<W2: Widget>(&self) -> Option<WidgetRef<'w, W2>> {
|
||||
Some(WidgetRef {
|
||||
ctx: self.ctx,
|
||||
properties: self.properties,
|
||||
widget: self.widget.as_any().downcast_ref()?,
|
||||
})
|
||||
}
|
||||
|
@ -115,6 +124,12 @@ impl<'w, W: Widget + ?Sized> WidgetRef<'w, W> {
|
|||
self.widget.short_type_name()
|
||||
);
|
||||
};
|
||||
let Some(properties_ref) = self.ctx.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
|
||||
|
@ -128,9 +143,17 @@ impl<'w, W: Widget + ?Sized> WidgetRef<'w, W> {
|
|||
widget_state_children: state_ref.children,
|
||||
widget_children: widget_ref.children,
|
||||
widget_state: state_ref.item,
|
||||
properties_children: properties_ref.children,
|
||||
};
|
||||
let properties = PropertiesRef {
|
||||
map: properties_ref.item,
|
||||
};
|
||||
|
||||
WidgetRef { ctx, widget }
|
||||
WidgetRef {
|
||||
ctx,
|
||||
properties,
|
||||
widget,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
@ -141,6 +164,7 @@ impl<'w, W: Widget> WidgetRef<'w, W> {
|
|||
pub fn as_dyn(&self) -> WidgetRef<'w, dyn Widget> {
|
||||
WidgetRef {
|
||||
ctx: self.ctx,
|
||||
properties: self.properties,
|
||||
widget: self.widget,
|
||||
}
|
||||
}
|
||||
|
@ -165,7 +189,8 @@ impl WidgetRef<'_, dyn Widget> {
|
|||
/// **pos** - the position in global coordinates (e.g. `(0,0)` is the top-left corner of the
|
||||
/// window).
|
||||
pub fn find_widget_at_pos(&self, pos: Point) -> Option<Self> {
|
||||
self.widget.find_widget_at_pos(self.ctx, pos)
|
||||
self.widget
|
||||
.find_widget_at_pos(self.ctx, self.properties, pos)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,18 +25,18 @@ Widgets are types which implement the [`Widget`] trait:
|
|||
|
||||
```rust,ignore
|
||||
trait Widget {
|
||||
fn on_pointer_event(&mut self, ctx: &mut EventCtx, event: &PointerEvent);
|
||||
fn on_text_event(&mut self, ctx: &mut EventCtx, event: &TextEvent);
|
||||
fn on_access_event(&mut self, ctx: &mut EventCtx, event: &AccessEvent);
|
||||
fn on_pointer_event(&mut self, ctx: &mut EventCtx, _props: &mut PropertiesMut<'_>, event: &PointerEvent);
|
||||
fn on_text_event(&mut self, ctx: &mut EventCtx, _props: &mut PropertiesMut<'_>, event: &TextEvent);
|
||||
fn on_access_event(&mut self, ctx: &mut EventCtx, _props: &mut PropertiesMut<'_>, event: &AccessEvent);
|
||||
|
||||
fn on_anim_frame(&mut self, ctx: &mut UpdateCtx, interval: u64);
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, event: &Update);
|
||||
fn on_anim_frame(&mut self, ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, interval: u64);
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, event: &Update);
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size;
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, _props: &mut PropertiesMut<'_>, bc: &BoxConstraints) -> Size;
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene);
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, scene: &mut Scene);
|
||||
fn accessibility_role(&self) -> Role;
|
||||
fn accessibility(&mut self, ctx: &mut AccessCtx, node: &mut Node);
|
||||
fn accessibility(&mut self, ctx: &mut AccessCtx, _props: &PropertiesRef<'_>, node: &mut Node);
|
||||
|
||||
// ...
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ use masonry::core::{
|
|||
};
|
||||
|
||||
impl Widget for ColorRectangle {
|
||||
fn on_pointer_event(&mut self, ctx: &mut EventCtx, event: &PointerEvent) {
|
||||
fn on_pointer_event(&mut self, ctx: &mut EventCtx, _props: &mut PropertiesMut<'_>, event: &PointerEvent) {
|
||||
match event {
|
||||
PointerEvent::PointerDown(PointerButton::Primary, _) => {
|
||||
ctx.submit_action(Action::ButtonPressed(PointerButton::Primary));
|
||||
|
@ -99,9 +99,9 @@ impl Widget for ColorRectangle {
|
|||
}
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _props: &mut PropertiesMut<'_>, _event: &TextEvent) {}
|
||||
|
||||
fn on_access_event(&mut self, ctx: &mut EventCtx, event: &AccessEvent) {
|
||||
fn on_access_event(&mut self, ctx: &mut EventCtx, _props: &mut PropertiesMut<'_>, event: &AccessEvent) {
|
||||
match event.action {
|
||||
accesskit::Action::Default => {
|
||||
ctx.submit_action(Action::ButtonPressed(PointerButton::Primary));
|
||||
|
@ -116,7 +116,7 @@ impl Widget for ColorRectangle {
|
|||
|
||||
We handle pointer events and accessibility events the same way: we check the event type, and if it's a left-click, we submit an action.
|
||||
|
||||
Submitting an action lets Masonry that a semantically meaningful event has occurred; Masonry will call `AppDriver::on_action()` with the action before the end of the frame.
|
||||
Submitting an action lets Masonry know that a semantically meaningful event has occurred; Masonry will call `AppDriver::on_action()` with the action before the end of the frame.
|
||||
This lets higher-level frameworks like Xilem react to UI events, like a button being pressed.
|
||||
|
||||
Implementing `on_access_event` lets us emulate click behaviors for people using assistive technologies.
|
||||
|
@ -136,8 +136,8 @@ use masonry::core::{
|
|||
impl Widget for ColorRectangle {
|
||||
// ...
|
||||
|
||||
fn on_anim_frame(&mut self, _ctx: &mut UpdateCtx, _interval: u64) {}
|
||||
fn update(&mut self, _ctx: &mut UpdateCtx, _event: &Update) {}
|
||||
fn on_anim_frame(&mut self, _ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, _interval: u64) {}
|
||||
fn update(&mut self, _ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, _event: &Update) {}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ use masonry::core::{
|
|||
impl Widget for ColorRectangle {
|
||||
// ...
|
||||
|
||||
fn layout(&mut self, _ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(&mut self, _ctx: &mut LayoutCtx, _props: &mut PropertiesMut<'_>, bc: &BoxConstraints) -> Size {
|
||||
bc.constrain(self.size)
|
||||
}
|
||||
|
||||
|
@ -182,7 +182,7 @@ use accesskit::{Node, Role};
|
|||
impl Widget for ColorRectangle {
|
||||
// ...
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) {
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, scene: &mut Scene) {
|
||||
let rect = ctx.size().to_rect();
|
||||
scene.fill(
|
||||
Fill::NonZero,
|
||||
|
@ -197,7 +197,7 @@ impl Widget for ColorRectangle {
|
|||
Role::Button
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, ctx: &mut AccessCtx, node: &mut Node) {
|
||||
fn accessibility(&mut self, ctx: &mut AccessCtx, _props: &PropertiesRef<'_>, node: &mut Node) {
|
||||
node.set_default_action_verb(DefaultActionVerb::Click);
|
||||
}
|
||||
|
||||
|
@ -302,7 +302,7 @@ First, we update our paint method:
|
|||
impl Widget for ColorRectangle {
|
||||
// ...
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) {
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, scene: &mut Scene) {
|
||||
let rect = ctx.size().to_rect();
|
||||
let color = if ctx.is_hovered() {
|
||||
Color::WHITE
|
||||
|
@ -330,7 +330,7 @@ Let's re-implement the `update` method:
|
|||
impl Widget for ColorRectangle {
|
||||
// ...
|
||||
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, event: &Update) {
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, event: &Update) {
|
||||
match event {
|
||||
Update::HoveredChanged(_) => {
|
||||
ctx.request_render();
|
||||
|
@ -343,6 +343,14 @@ impl Widget for ColorRectangle {
|
|||
}
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
Most of the methods we've listed take a `props: &mut PropertiesMut<'_>` argument.
|
||||
|
||||
We won't cover properties in this chapter.
|
||||
See [Reading Widget Properties](crate::doc::doc_04b_widget_properties) for more info.
|
||||
|
||||
|
||||
## Widget mutation
|
||||
|
||||
In Masonry, widgets generally can't be mutated directly.
|
||||
|
|
|
@ -85,7 +85,7 @@ use masonry::core::{
|
|||
impl Widget for VerticalStack {
|
||||
// ...
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, _props: &mut PropertiesMut<'_>, bc: &BoxConstraints) -> Size {
|
||||
let total_width = bc.max().width;
|
||||
let total_height = bc.max().height;
|
||||
let total_child_height = total_height - self.gap * (self.children.len() - 1) as f64;
|
||||
|
@ -228,22 +228,22 @@ In the case of our `VerticalStack`, all of them can be left empty:
|
|||
|
||||
```rust,ignore
|
||||
impl Widget for VerticalStack {
|
||||
fn on_pointer_event(&mut self, _ctx: &mut EventCtx, _event: &PointerEvent) {}
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_access_event(&mut self, _ctx: &mut EventCtx, _event: &AccessEvent) {}
|
||||
fn on_pointer_event(&mut self, _ctx: &mut EventCtx, _props: &mut PropertiesMut<'_>, _event: &PointerEvent) {}
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _props: &mut PropertiesMut<'_>, _event: &TextEvent) {}
|
||||
fn on_access_event(&mut self, _ctx: &mut EventCtx, _props: &mut PropertiesMut<'_>, _event: &AccessEvent) {}
|
||||
|
||||
fn on_anim_frame(&mut self, _ctx: &mut UpdateCtx, _interval: u64) {}
|
||||
fn update(&mut self, _ctx: &mut UpdateCtx, _event: &Update) {}
|
||||
fn on_anim_frame(&mut self, _ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, _interval: u64) {}
|
||||
fn update(&mut self, _ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, _event: &Update) {}
|
||||
|
||||
// ...
|
||||
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _scene: &mut Scene) {}
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, _scene: &mut Scene) {}
|
||||
|
||||
fn accessibility_role(&self) -> Role {
|
||||
Role::GenericContainer
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, _node: &mut Node) {}
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, _props: &PropertiesRef<'_>, _node: &mut Node) {}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
# Reading Widget Properties
|
||||
|
||||
<!-- Copyright 2024 the Xilem Authors -->
|
||||
<!-- SPDX-License-Identifier: Apache-2.0 -->
|
||||
|
||||
<div class="rustdoc-hidden">
|
||||
|
||||
> 💡 Tip
|
||||
>
|
||||
> This file is intended to be read in rustdoc.
|
||||
> Use `cargo doc --open --package masonry --no-deps`.
|
||||
|
||||
</div>
|
||||
|
||||
<!-- TODO - Rewrite this chapter -->
|
||||
|
||||
**TODO - Add screenshots - see [#501](https://github.com/linebender/xilem/issues/501)**
|
||||
|
||||
Throughout the previous chapters, you may have noticed that most Widget methods take a `props: &PropertiesRef<'_>` or `props: &mut PropertiesMut<'_>` argument.
|
||||
We haven't used these arguments so far, and you can build a robust widget set without them, but they're helpful for making your widgets more customizable and modular.
|
||||
|
||||
|
||||
## What are Properties?
|
||||
|
||||
In Masonry, **Properties** (often abbreviated to **props**) are values of arbitrary static types stored alongside each widget.
|
||||
|
||||
In simpler terms, that means you can take any non-ref type (e.g. `struct RubberDuck(Color, String, Buoyancy);`) and associate a value of that type to any widget, including widgets of existing types (`Button`, `Checkbox`, `Textbox`, etc) or your own custom widget (`ColorRectangle`).
|
||||
|
||||
Code accessing the property will look like:
|
||||
|
||||
```rust,ignore
|
||||
if let Some(ducky) = props.get::<RubberDuck>() {
|
||||
let (color, name, buoyancy) = ducky;
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### When to use Properties?
|
||||
|
||||
<!-- TODO - Mention event handling -->
|
||||
<!-- I expect that properties will be used to share the same pointer event handling code between Button, SizedBox, Textbox, etc... -->
|
||||
|
||||
In practice, properties should mostly be used for styling.
|
||||
|
||||
Properties should be defined to represent self-contained values that a widget can have, that are expected to make sense for multiple types of widgets, and where code handling those values should be shared between widgets.
|
||||
|
||||
Some examples:
|
||||
|
||||
- `BackgroundColor`
|
||||
- BorderColor
|
||||
- Padding
|
||||
- TextFont
|
||||
- TextSize
|
||||
- TextWeight
|
||||
|
||||
**TODO: Most of the properties cited above do *not* exist in Masonry's codebase. They should hopefully be added quickly.**
|
||||
|
||||
Properties should *not* be used to represent an individual widget's state. The following should *not* be properties:
|
||||
|
||||
- Text contents.
|
||||
- Cached values.
|
||||
- A checkbox's status.
|
||||
|
||||
<!-- TODO - Mention properties as a unit of code sharing, once we have concrete examples of that. -->
|
||||
|
||||
|
||||
## Using properties in `ColorRectangle`
|
||||
|
||||
With that in mind, let's rewrite our `ColorRectangle` widget to use properties:
|
||||
|
||||
```rust,ignore
|
||||
use masonry::properties::BackgroundColor;
|
||||
|
||||
impl Widget for ColorRectangle {
|
||||
// ...
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, props: &PropertiesRef<'_>, scene: &mut Scene) {
|
||||
let color = props.get::<BackgroundColor>().unwrap_or(masonry::palette::css::WHITE);
|
||||
let rect = ctx.size().to_rect();
|
||||
scene.fill(
|
||||
Fill::NonZero,
|
||||
Affine::IDENTITY,
|
||||
color,
|
||||
Some(Affine::IDENTITY),
|
||||
&rect,
|
||||
);
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## Setting properties in `WidgetMut`
|
||||
|
||||
The most idiomatic way to set properties is through `WidgetMut`:
|
||||
|
||||
```rust,ignore
|
||||
let color_rectangle_mut: WidgetMut<ColorRectangle> = ...;
|
||||
|
||||
let bg = BackgroundColor { color: masonry::palette::css::BLUE };
|
||||
|
||||
color_rectangle_mut.insert_prop(bg);
|
||||
```
|
||||
|
||||
This code will set the given rectangle's `BackgroundColor` (replacing the old one if there was one) to blue.
|
||||
|
||||
You can set as many properties as you want.
|
||||
Properties are an associative map, where types are the keys.
|
||||
|
||||
But setting a property to a given value doesn't change anything by default, unless your widget code specifically reads that value and does something with it.
|
||||
|
||||
<!-- TODO - Mention "transform" property. -->
|
|
@ -100,6 +100,13 @@ A widget is considered "interactive" if it can still get text and/or pointer eve
|
|||
Stashed and disabled widget are non-interactive.
|
||||
|
||||
|
||||
## Properties / Props
|
||||
|
||||
All widgets have associated data of arbitrary types called "properties".
|
||||
These properties are mostly used for styling and event handling.
|
||||
|
||||
See [Reading Widget Properties](crate::doc::doc_04b_widget_properties) for more info.
|
||||
|
||||
## Safety rails
|
||||
|
||||
When debug assertions are on, Masonry runs a bunch of checks every frame to make sure widget code doesn't have logical errors.
|
||||
|
|
|
@ -31,6 +31,10 @@ pub mod doc_03_implementing_container_widget {}
|
|||
/// <style> .rustdoc-hidden { display: none; } </style>
|
||||
pub mod doc_04_testing_widget {}
|
||||
|
||||
#[doc = include_str!("./04b_widget_properties.md")]
|
||||
/// <style> .rustdoc-hidden { display: none; } </style>
|
||||
pub mod doc_04b_widget_properties {}
|
||||
|
||||
#[doc = include_str!("./05_pass_system.md")]
|
||||
/// <style> .rustdoc-hidden { display: none; } </style>
|
||||
pub mod doc_05_pass_system {}
|
||||
|
|
|
@ -150,6 +150,7 @@ mod passes;
|
|||
|
||||
pub mod app;
|
||||
pub mod core;
|
||||
pub mod properties;
|
||||
pub mod testing;
|
||||
pub mod theme;
|
||||
pub mod widgets;
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use accesskit::{Node, NodeId, Tree, TreeUpdate};
|
||||
use anymap3::AnyMap;
|
||||
use tracing::{debug, info_span, trace};
|
||||
use tree_arena::ArenaMut;
|
||||
use vello::kurbo::Rect;
|
||||
|
||||
use crate::app::{RenderRoot, RenderRootState};
|
||||
use crate::core::{AccessCtx, Widget, WidgetState};
|
||||
use crate::core::{AccessCtx, PropertiesRef, Widget, WidgetState};
|
||||
use crate::passes::{enter_span_if, recurse_on_children};
|
||||
|
||||
// --- MARK: BUILD TREE ---
|
||||
|
@ -16,6 +17,7 @@ fn build_accessibility_tree(
|
|||
tree_update: &mut TreeUpdate,
|
||||
mut widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
mut state: ArenaMut<'_, WidgetState>,
|
||||
mut properties: ArenaMut<'_, AnyMap>,
|
||||
rebuild_all: bool,
|
||||
scale_factor: Option<f64>,
|
||||
) {
|
||||
|
@ -24,6 +26,7 @@ fn build_accessibility_tree(
|
|||
global_state,
|
||||
widget.reborrow(),
|
||||
state.reborrow(),
|
||||
properties.reborrow(),
|
||||
);
|
||||
let id = state.item.id;
|
||||
|
||||
|
@ -45,11 +48,15 @@ fn build_accessibility_tree(
|
|||
widget_state: state.item,
|
||||
widget_state_children: state.children.reborrow_mut(),
|
||||
widget_children: widget.children.reborrow_mut(),
|
||||
properties_children: properties.children.reborrow_mut(),
|
||||
tree_update,
|
||||
rebuild_all,
|
||||
};
|
||||
let mut node = build_access_node(&mut **widget.item, &mut ctx, scale_factor);
|
||||
widget.item.accessibility(&mut ctx, &mut node);
|
||||
let props = PropertiesRef {
|
||||
map: properties.item,
|
||||
};
|
||||
widget.item.accessibility(&mut ctx, &props, &mut node);
|
||||
|
||||
let id: NodeId = ctx.widget_state.id.into();
|
||||
if ctx.global_state.trace.access {
|
||||
|
@ -67,7 +74,8 @@ fn build_accessibility_tree(
|
|||
id,
|
||||
widget.reborrow_mut(),
|
||||
state.children,
|
||||
|widget, mut state| {
|
||||
properties.children,
|
||||
|widget, mut state, properties| {
|
||||
// TODO - We don't skip updating stashed items because doing so
|
||||
// is error-prone. We may want to revisit that decision.
|
||||
build_accessibility_tree(
|
||||
|
@ -75,6 +83,7 @@ fn build_accessibility_tree(
|
|||
tree_update,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
rebuild_all,
|
||||
None,
|
||||
);
|
||||
|
@ -154,7 +163,7 @@ pub(crate) fn run_accessibility_pass(root: &mut RenderRoot, scale_factor: f64) -
|
|||
.into(),
|
||||
};
|
||||
|
||||
let (root_widget, root_state) = {
|
||||
let (root_widget, root_state, root_properties) = {
|
||||
let widget_id = root.root.id();
|
||||
let widget = root
|
||||
.widget_arena
|
||||
|
@ -166,7 +175,12 @@ pub(crate) fn run_accessibility_pass(root: &mut RenderRoot, scale_factor: f64) -
|
|||
.states
|
||||
.find_mut(widget_id)
|
||||
.expect("root_accessibility: root state not in widget tree");
|
||||
(widget, state)
|
||||
let properties = root
|
||||
.widget_arena
|
||||
.properties
|
||||
.find_mut(widget_id)
|
||||
.expect("root_accessibility: root properties not in widget tree");
|
||||
(widget, state, properties)
|
||||
};
|
||||
|
||||
if root.rebuild_access_tree {
|
||||
|
@ -177,6 +191,7 @@ pub(crate) fn run_accessibility_pass(root: &mut RenderRoot, scale_factor: f64) -
|
|||
&mut tree_update,
|
||||
root_widget,
|
||||
root_state,
|
||||
root_properties,
|
||||
root.rebuild_access_tree,
|
||||
Some(scale_factor),
|
||||
);
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
// Copyright 2024 the Xilem Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use anymap3::AnyMap;
|
||||
use tracing::info_span;
|
||||
use tree_arena::ArenaMut;
|
||||
|
||||
use crate::app::{RenderRoot, RenderRootState};
|
||||
use crate::core::{UpdateCtx, Widget, WidgetState};
|
||||
use crate::core::{PropertiesMut, UpdateCtx, Widget, WidgetState};
|
||||
use crate::passes::{enter_span_if, recurse_on_children};
|
||||
|
||||
// --- MARK: UPDATE ANIM ---
|
||||
|
@ -13,6 +14,7 @@ fn update_anim_for_widget(
|
|||
global_state: &mut RenderRootState,
|
||||
mut widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
mut state: ArenaMut<'_, WidgetState>,
|
||||
mut properties: ArenaMut<'_, AnyMap>,
|
||||
elapsed_ns: u64,
|
||||
) {
|
||||
let _span = enter_span_if(
|
||||
|
@ -20,6 +22,7 @@ fn update_anim_for_widget(
|
|||
global_state,
|
||||
widget.reborrow(),
|
||||
state.reborrow(),
|
||||
properties.reborrow(),
|
||||
);
|
||||
if !state.item.needs_anim {
|
||||
return;
|
||||
|
@ -36,8 +39,12 @@ fn update_anim_for_widget(
|
|||
widget_state: state.item,
|
||||
widget_state_children: state.children.reborrow_mut(),
|
||||
widget_children: widget.children.reborrow_mut(),
|
||||
properties_children: properties.children.reborrow_mut(),
|
||||
};
|
||||
widget.item.on_anim_frame(&mut ctx, elapsed_ns);
|
||||
let mut props = PropertiesMut {
|
||||
map: properties.item,
|
||||
};
|
||||
widget.item.on_anim_frame(&mut ctx, &mut props, elapsed_ns);
|
||||
}
|
||||
|
||||
let id = state.item.id;
|
||||
|
@ -46,8 +53,15 @@ fn update_anim_for_widget(
|
|||
id,
|
||||
widget.reborrow_mut(),
|
||||
state.children,
|
||||
|widget, mut state| {
|
||||
update_anim_for_widget(global_state, widget, state.reborrow_mut(), elapsed_ns);
|
||||
properties.children,
|
||||
|widget, mut state, properties| {
|
||||
update_anim_for_widget(
|
||||
global_state,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
elapsed_ns,
|
||||
);
|
||||
parent_state.merge_up(state.item);
|
||||
},
|
||||
);
|
||||
|
@ -63,11 +77,13 @@ fn update_anim_for_widget(
|
|||
pub(crate) fn run_update_anim_pass(root: &mut RenderRoot, elapsed_ns: u64) {
|
||||
let _span = info_span!("update_anim").entered();
|
||||
|
||||
let (root_widget, mut root_state) = root.widget_arena.get_pair_mut(root.root.id());
|
||||
let (root_widget, mut root_state, root_properties) =
|
||||
root.widget_arena.get_all_mut(root.root.id());
|
||||
update_anim_for_widget(
|
||||
&mut root.global_state,
|
||||
root_widget,
|
||||
root_state.reborrow_mut(),
|
||||
root_properties,
|
||||
elapsed_ns,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright 2024 the Xilem Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use anymap3::AnyMap;
|
||||
use tracing::info_span;
|
||||
use tree_arena::ArenaMut;
|
||||
use vello::kurbo::Affine;
|
||||
|
@ -14,6 +15,7 @@ fn compose_widget(
|
|||
global_state: &mut RenderRootState,
|
||||
mut widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
mut state: ArenaMut<'_, WidgetState>,
|
||||
mut properties: ArenaMut<'_, AnyMap>,
|
||||
parent_transformed: bool,
|
||||
parent_window_transform: Affine,
|
||||
) {
|
||||
|
@ -22,6 +24,7 @@ fn compose_widget(
|
|||
global_state,
|
||||
widget.reborrow(),
|
||||
state.reborrow(),
|
||||
properties.reborrow(),
|
||||
);
|
||||
|
||||
let transformed = parent_transformed || state.item.transform_changed;
|
||||
|
@ -65,11 +68,13 @@ fn compose_widget(
|
|||
id,
|
||||
widget.reborrow_mut(),
|
||||
state.children,
|
||||
|widget, mut state| {
|
||||
properties.children,
|
||||
|widget, mut state, properties| {
|
||||
compose_widget(
|
||||
global_state,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
transformed,
|
||||
parent_transform,
|
||||
);
|
||||
|
@ -103,11 +108,12 @@ pub(crate) fn run_compose_pass(root: &mut RenderRoot) {
|
|||
root.global_state.needs_pointer_pass = true;
|
||||
}
|
||||
|
||||
let (root_widget, root_state) = root.widget_arena.get_pair_mut(root.root.id());
|
||||
let (root_widget, root_state, root_properties) = root.widget_arena.get_all_mut(root.root.id());
|
||||
compose_widget(
|
||||
&mut root.global_state,
|
||||
root_widget,
|
||||
root_state,
|
||||
root_properties,
|
||||
false,
|
||||
Affine::IDENTITY,
|
||||
);
|
||||
|
|
|
@ -8,7 +8,9 @@ use winit::keyboard::{KeyCode, PhysicalKey};
|
|||
|
||||
use crate::Handled;
|
||||
use crate::app::{RenderRoot, RenderRootSignal};
|
||||
use crate::core::{AccessEvent, EventCtx, PointerEvent, TextEvent, Widget, WidgetId};
|
||||
use crate::core::{
|
||||
AccessEvent, EventCtx, PointerEvent, PropertiesMut, TextEvent, Widget, WidgetId,
|
||||
};
|
||||
use crate::passes::{enter_span, merge_state_up};
|
||||
|
||||
// --- MARK: HELPERS ---
|
||||
|
@ -38,7 +40,7 @@ fn run_event_pass<E>(
|
|||
target: Option<WidgetId>,
|
||||
event: &E,
|
||||
allow_pointer_capture: bool,
|
||||
pass_fn: impl FnMut(&mut dyn Widget, &mut EventCtx, &E),
|
||||
pass_fn: impl FnMut(&mut dyn Widget, &mut EventCtx, &mut PropertiesMut<'_>, &E),
|
||||
trace: bool,
|
||||
) -> Handled {
|
||||
let mut pass_fn = pass_fn;
|
||||
|
@ -48,19 +50,22 @@ fn run_event_pass<E>(
|
|||
let mut is_handled = false;
|
||||
while let Some(widget_id) = target_widget_id {
|
||||
let parent_id = root.widget_arena.parent_of(widget_id);
|
||||
let (mut widget_mut, mut state_mut) = root.widget_arena.get_pair_mut(widget_id);
|
||||
let (mut widget_mut, mut state_mut, mut properties_mut) =
|
||||
root.widget_arena.get_all_mut(widget_id);
|
||||
|
||||
if !is_handled {
|
||||
let _span = enter_span(
|
||||
&root.global_state,
|
||||
widget_mut.reborrow(),
|
||||
state_mut.reborrow(),
|
||||
properties_mut.reborrow(),
|
||||
);
|
||||
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(),
|
||||
target: original_target.unwrap(),
|
||||
allow_pointer_capture,
|
||||
is_handled: false,
|
||||
|
@ -74,7 +79,10 @@ fn run_event_pass<E>(
|
|||
);
|
||||
}
|
||||
|
||||
pass_fn(&mut **widget, &mut ctx, event);
|
||||
let mut props = PropertiesMut {
|
||||
map: properties_mut.item,
|
||||
};
|
||||
pass_fn(&mut **widget, &mut ctx, &mut props, event);
|
||||
is_handled = ctx.is_handled;
|
||||
}
|
||||
|
||||
|
@ -157,8 +165,8 @@ pub(crate) fn run_on_pointer_event_pass(root: &mut RenderRoot, event: &PointerEv
|
|||
target_widget_id,
|
||||
event,
|
||||
matches!(event, PointerEvent::PointerDown(..)),
|
||||
|widget, ctx, event| {
|
||||
widget.on_pointer_event(ctx, event);
|
||||
|widget, ctx, props, event| {
|
||||
widget.on_pointer_event(ctx, props, event);
|
||||
},
|
||||
!event.is_high_density(),
|
||||
);
|
||||
|
@ -213,8 +221,8 @@ pub(crate) fn run_on_text_event_pass(root: &mut RenderRoot, event: &TextEvent) -
|
|||
target,
|
||||
event,
|
||||
false,
|
||||
|widget, ctx, event| {
|
||||
widget.on_text_event(ctx, event);
|
||||
|widget, ctx, props, event| {
|
||||
widget.on_text_event(ctx, props, event);
|
||||
},
|
||||
!event.is_high_density(),
|
||||
);
|
||||
|
@ -279,8 +287,8 @@ pub(crate) fn run_on_access_event_pass(
|
|||
Some(target),
|
||||
event,
|
||||
false,
|
||||
|widget, ctx, event| {
|
||||
widget.on_access_event(ctx, event);
|
||||
|widget, ctx, props, event| {
|
||||
widget.on_access_event(ctx, props, event);
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
|
|
@ -11,7 +11,7 @@ use tracing::{info_span, trace};
|
|||
use vello::kurbo::{Point, Rect, Size};
|
||||
|
||||
use crate::app::{RenderRoot, RenderRootSignal, WindowSizePolicy};
|
||||
use crate::core::{BoxConstraints, LayoutCtx, Widget, WidgetPod, WidgetState};
|
||||
use crate::core::{BoxConstraints, LayoutCtx, PropertiesMut, Widget, WidgetPod, WidgetState};
|
||||
use crate::passes::{enter_span_if, recurse_on_children};
|
||||
|
||||
// --- MARK: RUN LAYOUT ---
|
||||
|
@ -25,6 +25,7 @@ pub(crate) fn run_layout_on<W: Widget + ?Sized>(
|
|||
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 trace = parent_ctx.global_state.trace.layout;
|
||||
let _span = enter_span_if(
|
||||
|
@ -32,6 +33,7 @@ pub(crate) fn run_layout_on<W: Widget + ?Sized>(
|
|||
parent_ctx.global_state,
|
||||
widget.reborrow(),
|
||||
state.reborrow(),
|
||||
properties.reborrow(),
|
||||
);
|
||||
|
||||
let mut children_ids = SmallVec::new();
|
||||
|
@ -86,7 +88,8 @@ pub(crate) fn run_layout_on<W: Widget + ?Sized>(
|
|||
pod.id(),
|
||||
widget.reborrow_mut(),
|
||||
state.children.reborrow_mut(),
|
||||
|_, state| {
|
||||
properties.children.reborrow_mut(),
|
||||
|_, state, _| {
|
||||
if state.item.is_stashed {
|
||||
state.item.needs_layout = false;
|
||||
state.item.request_layout = false;
|
||||
|
@ -99,13 +102,17 @@ pub(crate) fn run_layout_on<W: Widget + ?Sized>(
|
|||
widget_state: state.item,
|
||||
widget_state_children: state.children.reborrow_mut(),
|
||||
widget_children: widget.children,
|
||||
properties_children: properties.children.reborrow_mut(),
|
||||
global_state: parent_ctx.global_state,
|
||||
};
|
||||
|
||||
// TODO - If constraints are the same and request_layout isn't set,
|
||||
// skip calling layout
|
||||
inner_ctx.widget_state.request_layout = false;
|
||||
widget.item.layout(&mut inner_ctx, bc)
|
||||
let mut props = PropertiesMut {
|
||||
map: properties.item,
|
||||
};
|
||||
widget.item.layout(&mut inner_ctx, &mut props, bc)
|
||||
};
|
||||
if state.item.request_layout {
|
||||
debug_panic!(
|
||||
|
@ -204,11 +211,14 @@ pub(crate) fn run_layout_pass(root: &mut RenderRoot) {
|
|||
let mut dummy_state = WidgetState::synthetic(root.root.id(), root.get_kurbo_size());
|
||||
let root_state_token = root.widget_arena.states.roots_mut();
|
||||
let root_widget_token = root.widget_arena.widgets.roots_mut();
|
||||
let root_properties_token = root.widget_arena.properties.roots_mut();
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
let size = run_layout_on(&mut ctx, &mut root.root, &bc);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
//!
|
||||
//! This file includes utility functions used by multiple passes.
|
||||
|
||||
use anymap3::AnyMap;
|
||||
use tracing::span::EnteredSpan;
|
||||
use tree_arena::{ArenaMut, ArenaMutList, ArenaRef};
|
||||
|
||||
|
@ -28,9 +29,10 @@ pub(crate) fn enter_span_if(
|
|||
global_state: &RenderRootState,
|
||||
widget: ArenaRef<'_, Box<dyn Widget>>,
|
||||
state: ArenaRef<'_, WidgetState>,
|
||||
properties: ArenaRef<'_, AnyMap>,
|
||||
) -> Option<EnteredSpan> {
|
||||
if enabled {
|
||||
Some(enter_span(global_state, widget, state))
|
||||
Some(enter_span(global_state, widget, state, properties))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -41,12 +43,14 @@ pub(crate) fn enter_span(
|
|||
global_state: &RenderRootState,
|
||||
widget: ArenaRef<'_, Box<dyn Widget>>,
|
||||
state: ArenaRef<'_, WidgetState>,
|
||||
properties: ArenaRef<'_, AnyMap>,
|
||||
) -> EnteredSpan {
|
||||
let ctx = QueryCtx {
|
||||
global_state,
|
||||
widget_state: state.item,
|
||||
widget_state_children: state.children,
|
||||
widget_children: widget.children,
|
||||
properties_children: properties.children,
|
||||
};
|
||||
widget.item.make_trace_span(&ctx).entered()
|
||||
}
|
||||
|
@ -55,7 +59,12 @@ pub(crate) fn recurse_on_children(
|
|||
id: WidgetId,
|
||||
mut widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
mut state: ArenaMutList<'_, WidgetState>,
|
||||
mut callback: impl FnMut(ArenaMut<'_, Box<dyn Widget>>, ArenaMut<'_, WidgetState>),
|
||||
mut properties: ArenaMutList<'_, AnyMap>,
|
||||
mut callback: impl FnMut(
|
||||
ArenaMut<'_, Box<dyn Widget>>,
|
||||
ArenaMut<'_, WidgetState>,
|
||||
ArenaMut<'_, AnyMap>,
|
||||
),
|
||||
) {
|
||||
let parent_name = widget.item.short_type_name();
|
||||
let parent_id = id;
|
||||
|
@ -73,8 +82,14 @@ pub(crate) fn recurse_on_children(
|
|||
parent_name, parent_id, child_id
|
||||
)
|
||||
});
|
||||
let properties = properties.item_mut(child_id).unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Error in '{}' #{}: cannot find child #{} returned by children_ids()",
|
||||
parent_name, parent_id, child_id
|
||||
)
|
||||
});
|
||||
|
||||
callback(widget, state);
|
||||
callback(widget, state, properties);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
use tracing::info_span;
|
||||
|
||||
use crate::app::RenderRoot;
|
||||
use crate::core::{MutateCtx, Widget, WidgetId, WidgetMut};
|
||||
use crate::core::{MutateCtx, PropertiesMut, Widget, WidgetId, WidgetMut};
|
||||
use crate::passes::merge_state_up;
|
||||
|
||||
pub(crate) fn mutate_widget<R>(
|
||||
|
@ -12,7 +12,7 @@ pub(crate) fn mutate_widget<R>(
|
|||
id: WidgetId,
|
||||
mutate_fn: impl FnOnce(WidgetMut<'_, dyn Widget>) -> R,
|
||||
) -> R {
|
||||
let (widget_mut, state_mut) = root.widget_arena.get_pair_mut(id);
|
||||
let (widget_mut, state_mut, properties_mut) = root.widget_arena.get_all_mut(id);
|
||||
|
||||
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
|
||||
|
@ -24,6 +24,10 @@ pub(crate) fn mutate_widget<R>(
|
|||
widget_state: state_mut.item,
|
||||
widget_state_children: state_mut.children,
|
||||
widget_children: widget_mut.children,
|
||||
properties: PropertiesMut {
|
||||
map: properties_mut.item,
|
||||
},
|
||||
properties_children: properties_mut.children,
|
||||
},
|
||||
widget: &mut **widget_mut.item,
|
||||
};
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anymap3::AnyMap;
|
||||
use tracing::{info_span, trace};
|
||||
use tree_arena::ArenaMut;
|
||||
use vello::Scene;
|
||||
|
@ -10,7 +11,7 @@ use vello::kurbo::Affine;
|
|||
use vello::peniko::{Color, Fill, Mix};
|
||||
|
||||
use crate::app::{RenderRoot, RenderRootState};
|
||||
use crate::core::{PaintCtx, Widget, WidgetId, WidgetState};
|
||||
use crate::core::{PaintCtx, PropertiesRef, Widget, WidgetId, WidgetState};
|
||||
use crate::kurbo::Rect;
|
||||
use crate::passes::{enter_span_if, recurse_on_children};
|
||||
use crate::theme::get_debug_color;
|
||||
|
@ -23,10 +24,17 @@ fn paint_widget(
|
|||
scenes: &mut HashMap<WidgetId, Scene>,
|
||||
mut widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
mut state: ArenaMut<'_, WidgetState>,
|
||||
mut properties: ArenaMut<'_, AnyMap>,
|
||||
debug_paint: bool,
|
||||
) {
|
||||
let trace = global_state.trace.paint;
|
||||
let _span = enter_span_if(trace, global_state, widget.reborrow(), state.reborrow());
|
||||
let _span = enter_span_if(
|
||||
trace,
|
||||
global_state,
|
||||
widget.reborrow(),
|
||||
state.reborrow(),
|
||||
properties.reborrow(),
|
||||
);
|
||||
|
||||
let id = state.item.id;
|
||||
|
||||
|
@ -48,7 +56,10 @@ fn paint_widget(
|
|||
// https://github.com/linebender/xilem/issues/524
|
||||
let scene = scenes.entry(id).or_default();
|
||||
scene.reset();
|
||||
widget.item.paint(&mut ctx, scene);
|
||||
let props = PropertiesRef {
|
||||
map: properties.item,
|
||||
};
|
||||
widget.item.paint(&mut ctx, &props, scene);
|
||||
}
|
||||
|
||||
state.item.request_paint = false;
|
||||
|
@ -72,7 +83,8 @@ fn paint_widget(
|
|||
id,
|
||||
widget.reborrow_mut(),
|
||||
state.children,
|
||||
|widget, mut state| {
|
||||
properties.children,
|
||||
|widget, mut state, properties| {
|
||||
// TODO - We skip painting stashed items.
|
||||
// This may lead to zombie flags in rare cases, we need to fix this.
|
||||
if state.item.is_stashed {
|
||||
|
@ -88,6 +100,7 @@ fn paint_widget(
|
|||
scenes,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
debug_paint,
|
||||
);
|
||||
parent_state.merge_up(state.item);
|
||||
|
@ -116,7 +129,7 @@ pub(crate) fn run_paint_pass(root: &mut RenderRoot) -> Scene {
|
|||
// https://github.com/linebender/xilem/issues/524
|
||||
let mut complete_scene = Scene::new();
|
||||
|
||||
let (root_widget, root_state) = {
|
||||
let (root_widget, root_state, root_properties) = {
|
||||
let widget_id = root.root.id();
|
||||
let widget = root
|
||||
.widget_arena
|
||||
|
@ -128,7 +141,12 @@ pub(crate) fn run_paint_pass(root: &mut RenderRoot) -> Scene {
|
|||
.states
|
||||
.find_mut(widget_id)
|
||||
.expect("root_paint: root state not in widget tree");
|
||||
(widget, state)
|
||||
let properties = root
|
||||
.widget_arena
|
||||
.properties
|
||||
.find_mut(widget_id)
|
||||
.expect("root_paint: root properties not in widget tree");
|
||||
(widget, state, properties)
|
||||
};
|
||||
|
||||
// TODO - This is a bit of a hack until we refactor widget tree mutation.
|
||||
|
@ -141,6 +159,7 @@ pub(crate) fn run_paint_pass(root: &mut RenderRoot) -> Scene {
|
|||
&mut scenes,
|
||||
root_widget,
|
||||
root_state,
|
||||
root_properties,
|
||||
root.debug_paint,
|
||||
);
|
||||
root.global_state.scenes = scenes;
|
||||
|
|
|
@ -3,14 +3,15 @@
|
|||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use anymap3::AnyMap;
|
||||
use cursor_icon::CursorIcon;
|
||||
use tracing::{info_span, trace};
|
||||
use tree_arena::ArenaMut;
|
||||
|
||||
use crate::app::{RenderRoot, RenderRootSignal, RenderRootState};
|
||||
use crate::core::{
|
||||
PointerEvent, QueryCtx, RegisterCtx, TextEvent, Update, UpdateCtx, Widget, WidgetId,
|
||||
WidgetState,
|
||||
PointerEvent, PropertiesMut, QueryCtx, RegisterCtx, TextEvent, Update, UpdateCtx, Widget,
|
||||
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};
|
||||
|
@ -35,20 +36,24 @@ fn get_id_path(root: &RenderRoot, widget_id: Option<WidgetId>) -> Vec<WidgetId>
|
|||
fn run_targeted_update_pass(
|
||||
root: &mut RenderRoot,
|
||||
target: Option<WidgetId>,
|
||||
mut pass_fn: impl FnMut(&mut dyn Widget, &mut UpdateCtx),
|
||||
mut pass_fn: impl FnMut(&mut dyn Widget, &mut UpdateCtx, &mut PropertiesMut<'_>),
|
||||
) {
|
||||
let mut current_id = target;
|
||||
while let Some(widget_id) = current_id {
|
||||
let parent_id = root.widget_arena.parent_of(widget_id);
|
||||
let (widget_mut, state_mut) = root.widget_arena.get_pair_mut(widget_id);
|
||||
let (widget_mut, state_mut, properties_mut) = root.widget_arena.get_all_mut(widget_id);
|
||||
|
||||
let mut ctx = UpdateCtx {
|
||||
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,
|
||||
};
|
||||
pass_fn(&mut **widget_mut.item, &mut ctx);
|
||||
let mut props = PropertiesMut {
|
||||
map: properties_mut.item,
|
||||
};
|
||||
pass_fn(&mut **widget_mut.item, &mut ctx, &mut props);
|
||||
|
||||
merge_state_up(&mut root.widget_arena, widget_id);
|
||||
current_id = parent_id;
|
||||
|
@ -58,7 +63,7 @@ fn run_targeted_update_pass(
|
|||
fn run_single_update_pass(
|
||||
root: &mut RenderRoot,
|
||||
target: Option<WidgetId>,
|
||||
mut pass_fn: impl FnMut(&mut dyn Widget, &mut UpdateCtx),
|
||||
mut pass_fn: impl FnMut(&mut dyn Widget, &mut UpdateCtx, &mut PropertiesMut<'_>),
|
||||
) {
|
||||
let Some(target) = target else {
|
||||
return;
|
||||
|
@ -67,15 +72,19 @@ fn run_single_update_pass(
|
|||
return;
|
||||
}
|
||||
|
||||
let (widget_mut, state_mut) = root.widget_arena.get_pair_mut(target);
|
||||
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,
|
||||
widget_children: widget_mut.children,
|
||||
properties_children: properties_mut.children,
|
||||
};
|
||||
pass_fn(&mut **widget_mut.item, &mut ctx);
|
||||
let mut props = PropertiesMut {
|
||||
map: properties_mut.item,
|
||||
};
|
||||
pass_fn(&mut **widget_mut.item, &mut ctx, &mut props);
|
||||
|
||||
let mut current_id = Some(target);
|
||||
while let Some(widget_id) = current_id {
|
||||
|
@ -89,9 +98,16 @@ fn update_widget_tree(
|
|||
global_state: &mut RenderRootState,
|
||||
mut widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
mut state: ArenaMut<'_, WidgetState>,
|
||||
mut properties: ArenaMut<'_, AnyMap>,
|
||||
) {
|
||||
let trace = global_state.trace.update_tree;
|
||||
let _span = enter_span_if(trace, global_state, widget.reborrow(), state.reborrow());
|
||||
let _span = enter_span_if(
|
||||
trace,
|
||||
global_state,
|
||||
widget.reborrow(),
|
||||
state.reborrow(),
|
||||
properties.reborrow(),
|
||||
);
|
||||
let id = state.item.id;
|
||||
|
||||
if !state.item.children_changed {
|
||||
|
@ -103,6 +119,7 @@ fn update_widget_tree(
|
|||
let mut ctx = RegisterCtx {
|
||||
widget_state_children: state.children.reborrow_mut(),
|
||||
widget_children: widget.children.reborrow_mut(),
|
||||
properties_children: properties.children.reborrow_mut(),
|
||||
#[cfg(debug_assertions)]
|
||||
registered_ids: Vec::new(),
|
||||
};
|
||||
|
@ -147,8 +164,14 @@ fn update_widget_tree(
|
|||
widget_state: state.item,
|
||||
widget_state_children: state.children.reborrow_mut(),
|
||||
widget_children: widget.children.reborrow_mut(),
|
||||
properties_children: properties.children.reborrow_mut(),
|
||||
};
|
||||
widget.item.update(&mut ctx, &Update::WidgetAdded);
|
||||
let mut props = PropertiesMut {
|
||||
map: properties.item,
|
||||
};
|
||||
widget
|
||||
.item
|
||||
.update(&mut ctx, &mut props, &Update::WidgetAdded);
|
||||
if trace {
|
||||
trace!(
|
||||
"{} received Update::WidgetAdded",
|
||||
|
@ -168,8 +191,9 @@ fn update_widget_tree(
|
|||
id,
|
||||
widget.reborrow_mut(),
|
||||
state.children,
|
||||
|widget, mut state| {
|
||||
update_widget_tree(global_state, widget, state.reborrow_mut());
|
||||
properties.children,
|
||||
|widget, mut state, properties| {
|
||||
update_widget_tree(global_state, widget, state.reborrow_mut(), properties);
|
||||
parent_state.merge_up(state.item);
|
||||
},
|
||||
);
|
||||
|
@ -183,17 +207,20 @@ pub(crate) fn run_update_widget_tree_pass(root: &mut RenderRoot) {
|
|||
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(),
|
||||
#[cfg(debug_assertions)]
|
||||
registered_ids: Vec::new(),
|
||||
};
|
||||
ctx.register_child(&mut root.root);
|
||||
}
|
||||
|
||||
let (root_widget, mut root_state) = root.widget_arena.get_pair_mut(root.root.id());
|
||||
let (root_widget, mut root_state, root_properties) =
|
||||
root.widget_arena.get_all_mut(root.root.id());
|
||||
update_widget_tree(
|
||||
&mut root.global_state,
|
||||
root_widget,
|
||||
root_state.reborrow_mut(),
|
||||
root_properties,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -206,9 +233,15 @@ fn update_disabled_for_widget(
|
|||
global_state: &mut RenderRootState,
|
||||
mut widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
mut state: ArenaMut<'_, WidgetState>,
|
||||
mut properties: ArenaMut<'_, AnyMap>,
|
||||
parent_disabled: bool,
|
||||
) {
|
||||
let _span = enter_span(global_state, widget.reborrow(), state.reborrow());
|
||||
let _span = enter_span(
|
||||
global_state,
|
||||
widget.reborrow(),
|
||||
state.reborrow(),
|
||||
properties.reborrow(),
|
||||
);
|
||||
let id = state.item.id;
|
||||
|
||||
let disabled = state.item.is_explicitly_disabled || parent_disabled;
|
||||
|
@ -222,10 +255,14 @@ fn update_disabled_for_widget(
|
|||
widget_state: state.item,
|
||||
widget_state_children: state.children.reborrow_mut(),
|
||||
widget_children: widget.children.reborrow_mut(),
|
||||
properties_children: properties.children.reborrow_mut(),
|
||||
};
|
||||
let mut props = PropertiesMut {
|
||||
map: properties.item,
|
||||
};
|
||||
widget
|
||||
.item
|
||||
.update(&mut ctx, &Update::DisabledChanged(disabled));
|
||||
.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;
|
||||
|
@ -239,8 +276,15 @@ fn update_disabled_for_widget(
|
|||
id,
|
||||
widget.reborrow_mut(),
|
||||
state.children,
|
||||
|widget, mut state| {
|
||||
update_disabled_for_widget(global_state, widget, state.reborrow_mut(), disabled);
|
||||
properties.children,
|
||||
|widget, mut state, properties| {
|
||||
update_disabled_for_widget(
|
||||
global_state,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
disabled,
|
||||
);
|
||||
parent_state.merge_up(state.item);
|
||||
},
|
||||
);
|
||||
|
@ -254,8 +298,14 @@ pub(crate) fn run_update_disabled_pass(root: &mut RenderRoot) {
|
|||
root.global_state.needs_pointer_pass = true;
|
||||
}
|
||||
|
||||
let (root_widget, root_state) = root.widget_arena.get_pair_mut(root.root.id());
|
||||
update_disabled_for_widget(&mut root.global_state, root_widget, root_state, false);
|
||||
let (root_widget, root_state, root_properties) = root.widget_arena.get_all_mut(root.root.id());
|
||||
update_disabled_for_widget(
|
||||
&mut root.global_state,
|
||||
root_widget,
|
||||
root_state,
|
||||
root_properties,
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
// ----------------
|
||||
|
@ -270,9 +320,15 @@ fn update_stashed_for_widget(
|
|||
global_state: &mut RenderRootState,
|
||||
mut widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
mut state: ArenaMut<'_, WidgetState>,
|
||||
mut properties: ArenaMut<'_, AnyMap>,
|
||||
parent_stashed: bool,
|
||||
) {
|
||||
let _span = enter_span(global_state, widget.reborrow(), state.reborrow());
|
||||
let _span = enter_span(
|
||||
global_state,
|
||||
widget.reborrow(),
|
||||
state.reborrow(),
|
||||
properties.reborrow(),
|
||||
);
|
||||
let id = state.item.id;
|
||||
|
||||
let stashed = state.item.is_explicitly_stashed || parent_stashed;
|
||||
|
@ -286,10 +342,14 @@ fn update_stashed_for_widget(
|
|||
widget_state: state.item,
|
||||
widget_state_children: state.children.reborrow_mut(),
|
||||
widget_children: widget.children.reborrow_mut(),
|
||||
properties_children: properties.children.reborrow_mut(),
|
||||
};
|
||||
let mut props = PropertiesMut {
|
||||
map: properties.item,
|
||||
};
|
||||
widget
|
||||
.item
|
||||
.update(&mut ctx, &Update::StashedChanged(stashed));
|
||||
.update(&mut ctx, &mut props, &Update::StashedChanged(stashed));
|
||||
state.item.is_stashed = stashed;
|
||||
state.item.needs_update_focus_chain = true;
|
||||
// Note: We don't need request_repaint because stashing doesn't actually change
|
||||
|
@ -312,8 +372,15 @@ fn update_stashed_for_widget(
|
|||
id,
|
||||
widget.reborrow_mut(),
|
||||
state.children,
|
||||
|widget, mut state| {
|
||||
update_stashed_for_widget(global_state, widget, state.reborrow_mut(), stashed);
|
||||
properties.children,
|
||||
|widget, mut state, properties| {
|
||||
update_stashed_for_widget(
|
||||
global_state,
|
||||
widget,
|
||||
state.reborrow_mut(),
|
||||
properties,
|
||||
stashed,
|
||||
);
|
||||
parent_state.merge_up(state.item);
|
||||
},
|
||||
);
|
||||
|
@ -322,8 +389,14 @@ fn update_stashed_for_widget(
|
|||
pub(crate) fn run_update_stashed_pass(root: &mut RenderRoot) {
|
||||
let _span = info_span!("update_stashed").entered();
|
||||
|
||||
let (root_widget, root_state) = root.widget_arena.get_pair_mut(root.root.id());
|
||||
update_stashed_for_widget(&mut root.global_state, root_widget, root_state, false);
|
||||
let (root_widget, root_state, root_properties) = root.widget_arena.get_all_mut(root.root.id());
|
||||
update_stashed_for_widget(
|
||||
&mut root.global_state,
|
||||
root_widget,
|
||||
root_state,
|
||||
root_properties,
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
// ----------------
|
||||
|
@ -341,9 +414,15 @@ fn update_focus_chain_for_widget(
|
|||
global_state: &mut RenderRootState,
|
||||
mut widget: ArenaMut<'_, Box<dyn Widget>>,
|
||||
mut state: ArenaMut<'_, WidgetState>,
|
||||
mut properties: ArenaMut<'_, AnyMap>,
|
||||
parent_focus_chain: &mut Vec<WidgetId>,
|
||||
) {
|
||||
let _span = enter_span(global_state, widget.reborrow(), state.reborrow());
|
||||
let _span = enter_span(
|
||||
global_state,
|
||||
widget.reborrow(),
|
||||
state.reborrow(),
|
||||
properties.reborrow(),
|
||||
);
|
||||
let id = state.item.id;
|
||||
|
||||
if !state.item.needs_update_focus_chain {
|
||||
|
@ -365,11 +444,13 @@ fn update_focus_chain_for_widget(
|
|||
id,
|
||||
widget.reborrow_mut(),
|
||||
state.children,
|
||||
|widget, mut state| {
|
||||
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);
|
||||
|
@ -394,11 +475,12 @@ pub(crate) fn run_update_focus_chain_pass(root: &mut RenderRoot) {
|
|||
let _span = info_span!("update_focus_chain").entered();
|
||||
let mut dummy_focus_chain = Vec::new();
|
||||
|
||||
let (root_widget, mut root_state) = root.widget_arena.get_pair_mut(root.root.id());
|
||||
let (root_widget, root_state, root_properties) = root.widget_arena.get_all_mut(root.root.id());
|
||||
update_focus_chain_for_widget(
|
||||
&mut root.global_state,
|
||||
root_widget,
|
||||
root_state.reborrow_mut(),
|
||||
root_state,
|
||||
root_properties,
|
||||
&mut dummy_focus_chain,
|
||||
);
|
||||
}
|
||||
|
@ -483,11 +565,11 @@ pub(crate) fn run_update_focus_pass(root: &mut RenderRoot) {
|
|||
widget_id: WidgetId,
|
||||
focused_set: &HashSet<WidgetId>,
|
||||
) {
|
||||
run_targeted_update_pass(root, Some(widget_id), |widget, ctx| {
|
||||
run_targeted_update_pass(root, Some(widget_id), |widget, ctx, props| {
|
||||
let has_focused = focused_set.contains(&ctx.widget_id());
|
||||
|
||||
if ctx.widget_state.has_focus_target != has_focused {
|
||||
widget.update(ctx, &Update::ChildFocusChanged(has_focused));
|
||||
widget.update(ctx, props, &Update::ChildFocusChanged(has_focused));
|
||||
}
|
||||
ctx.widget_state.has_focus_target = has_focused;
|
||||
});
|
||||
|
@ -524,13 +606,13 @@ pub(crate) fn run_update_focus_pass(root: &mut RenderRoot) {
|
|||
if prev_focused != next_focused {
|
||||
// We send FocusChange event to widget that lost and the widget that gained focus.
|
||||
// We also request accessibility, because build_access_node() depends on the focus state.
|
||||
run_single_update_pass(root, prev_focused, |widget, ctx| {
|
||||
widget.update(ctx, &Update::FocusChanged(false));
|
||||
run_single_update_pass(root, prev_focused, |widget, ctx, props| {
|
||||
widget.update(ctx, props, &Update::FocusChanged(false));
|
||||
ctx.widget_state.request_accessibility = true;
|
||||
ctx.widget_state.needs_accessibility = true;
|
||||
});
|
||||
run_single_update_pass(root, next_focused, |widget, ctx| {
|
||||
widget.update(ctx, &Update::FocusChanged(true));
|
||||
run_single_update_pass(root, next_focused, |widget, ctx, props| {
|
||||
widget.update(ctx, props, &Update::FocusChanged(true));
|
||||
ctx.widget_state.request_accessibility = true;
|
||||
ctx.widget_state.needs_accessibility = true;
|
||||
});
|
||||
|
@ -568,9 +650,9 @@ pub(crate) fn run_update_scroll_pass(root: &mut RenderRoot) {
|
|||
let mut target_rect = rect;
|
||||
|
||||
// TODO - Run top-down instead of bottom-up.
|
||||
run_targeted_update_pass(root, Some(target), |widget, ctx| {
|
||||
run_targeted_update_pass(root, Some(target), |widget, ctx, props| {
|
||||
let event = Update::RequestPanToChild(rect);
|
||||
widget.update(ctx, &event);
|
||||
widget.update(ctx, props, &event);
|
||||
|
||||
// TODO - We should run the compose method after this, so
|
||||
// translations are updated and the rect passed to parents
|
||||
|
@ -660,11 +742,11 @@ pub(crate) fn run_update_pointer_pass(root: &mut RenderRoot) {
|
|||
widget_id: WidgetId,
|
||||
hovered_set: &HashSet<WidgetId>,
|
||||
) {
|
||||
run_targeted_update_pass(root, Some(widget_id), |widget, ctx| {
|
||||
run_targeted_update_pass(root, Some(widget_id), |widget, ctx, props| {
|
||||
let has_hovered = hovered_set.contains(&ctx.widget_id());
|
||||
|
||||
if ctx.widget_state.has_hovered != has_hovered {
|
||||
widget.update(ctx, &Update::ChildHoveredChanged(has_hovered));
|
||||
widget.update(ctx, props, &Update::ChildHoveredChanged(has_hovered));
|
||||
}
|
||||
ctx.widget_state.has_hovered = has_hovered;
|
||||
});
|
||||
|
@ -690,13 +772,13 @@ pub(crate) fn run_update_pointer_pass(root: &mut RenderRoot) {
|
|||
}
|
||||
|
||||
if prev_hovered_widget != next_hovered_widget {
|
||||
run_single_update_pass(root, prev_hovered_widget, |widget, ctx| {
|
||||
run_single_update_pass(root, prev_hovered_widget, |widget, ctx, props| {
|
||||
ctx.widget_state.is_hovered = false;
|
||||
widget.update(ctx, &Update::HoveredChanged(false));
|
||||
widget.update(ctx, props, &Update::HoveredChanged(false));
|
||||
});
|
||||
run_single_update_pass(root, next_hovered_widget, |widget, ctx| {
|
||||
run_single_update_pass(root, next_hovered_widget, |widget, ctx, props| {
|
||||
ctx.widget_state.is_hovered = true;
|
||||
widget.update(ctx, &Update::HoveredChanged(true));
|
||||
widget.update(ctx, props, &Update::HoveredChanged(true));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -710,13 +792,14 @@ pub(crate) fn run_update_pointer_pass(root: &mut RenderRoot) {
|
|||
.or(next_hovered_widget);
|
||||
|
||||
let new_icon = if let (Some(icon_source), Some(pos)) = (icon_source, pointer_pos) {
|
||||
let (widget, state) = root.widget_arena.get_pair(icon_source);
|
||||
let (widget, state, properties) = root.widget_arena.get_all(icon_source);
|
||||
|
||||
let ctx = QueryCtx {
|
||||
global_state: &root.global_state,
|
||||
widget_state_children: state.children,
|
||||
widget_children: widget.children,
|
||||
widget_state: state.item,
|
||||
properties_children: properties.children,
|
||||
};
|
||||
|
||||
if state.item.is_disabled {
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright 2025 the Xilem Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//! Types and logic commonly used across widgets.
|
||||
//!
|
||||
//! See [properties documentation](crate::doc::doc_03_implementing_container_widget) for details.
|
||||
|
||||
#![allow(
|
||||
missing_docs,
|
||||
reason = "A lot of properties and especially their fields are self-explanatory."
|
||||
)]
|
||||
|
||||
use std::any::TypeId;
|
||||
|
||||
use vello::peniko::color::{AlphaColor, Srgb};
|
||||
|
||||
use crate::core::UpdateCtx;
|
||||
|
||||
// TODO - Split out into files.
|
||||
|
||||
/// The background color of a widget.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct BackgroundColor {
|
||||
pub color: AlphaColor<Srgb>,
|
||||
}
|
||||
|
||||
impl BackgroundColor {
|
||||
pub(crate) fn prop_changed(ctx: &mut UpdateCtx<'_>, property_type: TypeId) {
|
||||
if property_type == TypeId::of::<Self>() {
|
||||
ctx.request_paint_only();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
//! Note: Some of these types are undocumented. They're meant to help maintainers of
|
||||
//! Masonry, not to be user-facing.
|
||||
|
||||
use std::any::TypeId;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
|
@ -20,24 +21,27 @@ use vello::Scene;
|
|||
use crate::AsAny;
|
||||
use crate::core::{
|
||||
AccessCtx, AccessEvent, BoxConstraints, ComposeCtx, EventCtx, LayoutCtx, PaintCtx,
|
||||
PointerEvent, QueryCtx, RegisterCtx, TextEvent, Update, UpdateCtx, Widget, WidgetId, WidgetPod,
|
||||
WidgetRef, find_widget_at_pos,
|
||||
PointerEvent, PropertiesMut, PropertiesRef, QueryCtx, RegisterCtx, TextEvent, Update,
|
||||
UpdateCtx, Widget, WidgetId, WidgetPod, WidgetRef, find_widget_at_pos,
|
||||
};
|
||||
use crate::kurbo::{Point, Size};
|
||||
use crate::widgets::SizedBox;
|
||||
use cursor_icon::CursorIcon;
|
||||
|
||||
pub type PointerEventFn<S> = dyn FnMut(&mut S, &mut EventCtx, &PointerEvent);
|
||||
pub type TextEventFn<S> = dyn FnMut(&mut S, &mut EventCtx, &TextEvent);
|
||||
pub type AccessEventFn<S> = dyn FnMut(&mut S, &mut EventCtx, &AccessEvent);
|
||||
pub type AnimFrameFn<S> = dyn FnMut(&mut S, &mut UpdateCtx, u64);
|
||||
pub type PointerEventFn<S> =
|
||||
dyn FnMut(&mut S, &mut EventCtx, &mut PropertiesMut<'_>, &PointerEvent);
|
||||
pub type TextEventFn<S> = dyn FnMut(&mut S, &mut EventCtx, &mut PropertiesMut<'_>, &TextEvent);
|
||||
pub type AccessEventFn<S> = dyn FnMut(&mut S, &mut EventCtx, &mut PropertiesMut<'_>, &AccessEvent);
|
||||
pub type AnimFrameFn<S> = dyn FnMut(&mut S, &mut UpdateCtx, &mut PropertiesMut<'_>, u64);
|
||||
pub type RegisterChildrenFn<S> = dyn FnMut(&mut S, &mut RegisterCtx);
|
||||
pub type UpdateFn<S> = dyn FnMut(&mut S, &mut UpdateCtx, &Update);
|
||||
pub type LayoutFn<S> = dyn FnMut(&mut S, &mut LayoutCtx, &BoxConstraints) -> Size;
|
||||
pub type UpdateFn<S> = dyn FnMut(&mut S, &mut UpdateCtx, &mut PropertiesMut<'_>, &Update);
|
||||
pub type PropertyChangeFn<S> = dyn FnMut(&mut S, &mut UpdateCtx, TypeId);
|
||||
pub type LayoutFn<S> =
|
||||
dyn FnMut(&mut S, &mut LayoutCtx, &mut PropertiesMut<'_>, &BoxConstraints) -> Size;
|
||||
pub type ComposeFn<S> = dyn FnMut(&mut S, &mut ComposeCtx);
|
||||
pub type PaintFn<S> = dyn FnMut(&mut S, &mut PaintCtx, &mut Scene);
|
||||
pub type PaintFn<S> = dyn FnMut(&mut S, &mut PaintCtx, &PropertiesRef<'_>, &mut Scene);
|
||||
pub type RoleFn<S> = dyn Fn(&S) -> Role;
|
||||
pub type AccessFn<S> = dyn FnMut(&mut S, &mut AccessCtx, &mut Node);
|
||||
pub type AccessFn<S> = dyn FnMut(&mut S, &mut AccessCtx, &PropertiesRef<'_>, &mut Node);
|
||||
pub type ChildrenFn<S> = dyn Fn(&S) -> SmallVec<[WidgetId; 16]>;
|
||||
|
||||
#[cfg(FALSE)]
|
||||
|
@ -57,6 +61,7 @@ pub struct ModularWidget<S> {
|
|||
on_anim_frame: Option<Box<AnimFrameFn<S>>>,
|
||||
register_children: Option<Box<RegisterChildrenFn<S>>>,
|
||||
update: Option<Box<UpdateFn<S>>>,
|
||||
property_change: Option<Box<PropertyChangeFn<S>>>,
|
||||
layout: Option<Box<LayoutFn<S>>>,
|
||||
compose: Option<Box<ComposeFn<S>>>,
|
||||
paint: Option<Box<PaintFn<S>>>,
|
||||
|
@ -120,6 +125,8 @@ pub enum Record {
|
|||
RC,
|
||||
/// Update
|
||||
U(Update),
|
||||
/// Property change.
|
||||
PC(TypeId),
|
||||
/// Layout. Records the size returned by the layout method.
|
||||
Layout(Size),
|
||||
/// Compose.
|
||||
|
@ -167,6 +174,7 @@ impl<S> ModularWidget<S> {
|
|||
on_anim_frame: None,
|
||||
register_children: None,
|
||||
update: None,
|
||||
property_change: None,
|
||||
layout: None,
|
||||
compose: None,
|
||||
paint: None,
|
||||
|
@ -207,7 +215,7 @@ impl<S> ModularWidget<S> {
|
|||
/// See [`Widget::on_pointer_event`]
|
||||
pub fn pointer_event_fn(
|
||||
mut self,
|
||||
f: impl FnMut(&mut S, &mut EventCtx, &PointerEvent) + 'static,
|
||||
f: impl FnMut(&mut S, &mut EventCtx, &mut PropertiesMut<'_>, &PointerEvent) + 'static,
|
||||
) -> Self {
|
||||
self.on_pointer_event = Some(Box::new(f));
|
||||
self
|
||||
|
@ -216,7 +224,7 @@ impl<S> ModularWidget<S> {
|
|||
/// See [`Widget::on_text_event`]
|
||||
pub fn text_event_fn(
|
||||
mut self,
|
||||
f: impl FnMut(&mut S, &mut EventCtx, &TextEvent) + 'static,
|
||||
f: impl FnMut(&mut S, &mut EventCtx, &mut PropertiesMut<'_>, &TextEvent) + 'static,
|
||||
) -> Self {
|
||||
self.on_text_event = Some(Box::new(f));
|
||||
self
|
||||
|
@ -225,14 +233,17 @@ impl<S> ModularWidget<S> {
|
|||
/// See [`Widget::on_access_event`]
|
||||
pub fn access_event_fn(
|
||||
mut self,
|
||||
f: impl FnMut(&mut S, &mut EventCtx, &AccessEvent) + 'static,
|
||||
f: impl FnMut(&mut S, &mut EventCtx, &mut PropertiesMut<'_>, &AccessEvent) + 'static,
|
||||
) -> Self {
|
||||
self.on_access_event = Some(Box::new(f));
|
||||
self
|
||||
}
|
||||
|
||||
/// See [`Widget::on_anim_frame`]
|
||||
pub fn anim_frame_fn(mut self, f: impl FnMut(&mut S, &mut UpdateCtx, u64) + 'static) -> Self {
|
||||
pub fn anim_frame_fn(
|
||||
mut self,
|
||||
f: impl FnMut(&mut S, &mut UpdateCtx, &mut PropertiesMut<'_>, u64) + 'static,
|
||||
) -> Self {
|
||||
self.on_anim_frame = Some(Box::new(f));
|
||||
self
|
||||
}
|
||||
|
@ -247,15 +258,27 @@ impl<S> ModularWidget<S> {
|
|||
}
|
||||
|
||||
/// See [`Widget::update`]
|
||||
pub fn update_fn(mut self, f: impl FnMut(&mut S, &mut UpdateCtx, &Update) + 'static) -> Self {
|
||||
pub fn update_fn(
|
||||
mut self,
|
||||
f: impl FnMut(&mut S, &mut UpdateCtx, &mut PropertiesMut<'_>, &Update) + 'static,
|
||||
) -> Self {
|
||||
self.update = Some(Box::new(f));
|
||||
self
|
||||
}
|
||||
|
||||
/// See [`Widget::property_changed`]
|
||||
pub fn property_change_fn(
|
||||
mut self,
|
||||
f: impl FnMut(&mut S, &mut UpdateCtx, TypeId) + 'static,
|
||||
) -> Self {
|
||||
self.property_change = Some(Box::new(f));
|
||||
self
|
||||
}
|
||||
|
||||
/// See [`Widget::layout`]
|
||||
pub fn layout_fn(
|
||||
mut self,
|
||||
f: impl FnMut(&mut S, &mut LayoutCtx, &BoxConstraints) -> Size + 'static,
|
||||
f: impl FnMut(&mut S, &mut LayoutCtx, &mut PropertiesMut<'_>, &BoxConstraints) -> Size + 'static,
|
||||
) -> Self {
|
||||
self.layout = Some(Box::new(f));
|
||||
self
|
||||
|
@ -268,7 +291,10 @@ impl<S> ModularWidget<S> {
|
|||
}
|
||||
|
||||
/// See [`Widget::paint`]
|
||||
pub fn paint_fn(mut self, f: impl FnMut(&mut S, &mut PaintCtx, &mut Scene) + 'static) -> Self {
|
||||
pub fn paint_fn(
|
||||
mut self,
|
||||
f: impl FnMut(&mut S, &mut PaintCtx, &PropertiesRef<'_>, &mut Scene) + 'static,
|
||||
) -> Self {
|
||||
self.paint = Some(Box::new(f));
|
||||
self
|
||||
}
|
||||
|
@ -280,7 +306,10 @@ impl<S> ModularWidget<S> {
|
|||
}
|
||||
|
||||
/// See [`Widget::accessibility`]
|
||||
pub fn access_fn(mut self, f: impl FnMut(&mut S, &mut AccessCtx, &mut Node) + 'static) -> Self {
|
||||
pub fn access_fn(
|
||||
mut self,
|
||||
f: impl FnMut(&mut S, &mut AccessCtx, &PropertiesRef<'_>, &mut Node) + 'static,
|
||||
) -> Self {
|
||||
self.access = Some(Box::new(f));
|
||||
self
|
||||
}
|
||||
|
@ -297,27 +326,42 @@ impl<S> ModularWidget<S> {
|
|||
|
||||
#[warn(clippy::missing_trait_methods)]
|
||||
impl<S: 'static> Widget for ModularWidget<S> {
|
||||
fn on_pointer_event(&mut self, ctx: &mut EventCtx, event: &PointerEvent) {
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
props: &mut PropertiesMut<'_>,
|
||||
event: &PointerEvent,
|
||||
) {
|
||||
if let Some(f) = self.on_pointer_event.as_mut() {
|
||||
f(&mut self.state, ctx, event);
|
||||
f(&mut self.state, ctx, props, event);
|
||||
}
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, ctx: &mut EventCtx, event: &TextEvent) {
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
props: &mut PropertiesMut<'_>,
|
||||
event: &TextEvent,
|
||||
) {
|
||||
if let Some(f) = self.on_text_event.as_mut() {
|
||||
f(&mut self.state, ctx, event);
|
||||
f(&mut self.state, ctx, props, event);
|
||||
}
|
||||
}
|
||||
|
||||
fn on_access_event(&mut self, ctx: &mut EventCtx, event: &AccessEvent) {
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
props: &mut PropertiesMut<'_>,
|
||||
event: &AccessEvent,
|
||||
) {
|
||||
if let Some(f) = self.on_access_event.as_mut() {
|
||||
f(&mut self.state, ctx, event);
|
||||
f(&mut self.state, ctx, props, event);
|
||||
}
|
||||
}
|
||||
|
||||
fn on_anim_frame(&mut self, ctx: &mut UpdateCtx, interval: u64) {
|
||||
fn on_anim_frame(&mut self, ctx: &mut UpdateCtx, props: &mut PropertiesMut<'_>, interval: u64) {
|
||||
if let Some(f) = self.on_anim_frame.as_mut() {
|
||||
f(&mut self.state, ctx, interval);
|
||||
f(&mut self.state, ctx, props, interval);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -327,17 +371,28 @@ impl<S: 'static> Widget for ModularWidget<S> {
|
|||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, event: &Update) {
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, props: &mut PropertiesMut<'_>, event: &Update) {
|
||||
if let Some(f) = self.update.as_mut() {
|
||||
f(&mut self.state, ctx, event);
|
||||
f(&mut self.state, ctx, props, event);
|
||||
}
|
||||
}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn property_changed(&mut self, ctx: &mut UpdateCtx, property_type: TypeId) {
|
||||
if let Some(f) = self.property_change.as_mut() {
|
||||
f(&mut self.state, ctx, property_type);
|
||||
}
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
let Self { state, layout, .. } = self;
|
||||
layout
|
||||
.as_mut()
|
||||
.map(|f| f(state, ctx, bc))
|
||||
.map(|f| f(state, ctx, props, bc))
|
||||
.unwrap_or_else(|| Size::new(100., 100.))
|
||||
}
|
||||
|
||||
|
@ -355,15 +410,15 @@ impl<S: 'static> Widget for ModularWidget<S> {
|
|||
}
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, ctx: &mut AccessCtx, node: &mut Node) {
|
||||
fn accessibility(&mut self, ctx: &mut AccessCtx, props: &PropertiesRef<'_>, node: &mut Node) {
|
||||
if let Some(f) = self.access.as_mut() {
|
||||
f(&mut self.state, ctx, node);
|
||||
f(&mut self.state, ctx, props, node);
|
||||
}
|
||||
}
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) {
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, props: &PropertiesRef<'_>, scene: &mut Scene) {
|
||||
if let Some(f) = self.paint.as_mut() {
|
||||
f(&mut self.state, ctx, scene);
|
||||
f(&mut self.state, ctx, props, scene);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -402,9 +457,17 @@ impl<S: 'static> Widget for ModularWidget<S> {
|
|||
fn find_widget_at_pos<'c>(
|
||||
&'c self,
|
||||
ctx: QueryCtx<'c>,
|
||||
props: PropertiesRef<'c>,
|
||||
pos: Point,
|
||||
) -> Option<WidgetRef<'c, dyn Widget>> {
|
||||
find_widget_at_pos(&WidgetRef { widget: self, ctx }, pos)
|
||||
find_widget_at_pos(
|
||||
&WidgetRef {
|
||||
widget: self,
|
||||
properties: props,
|
||||
ctx,
|
||||
},
|
||||
pos,
|
||||
)
|
||||
}
|
||||
|
||||
fn type_name(&self) -> &'static str {
|
||||
|
@ -438,7 +501,7 @@ impl ReplaceChild {
|
|||
|
||||
impl Widget for ReplaceChild {
|
||||
#[cfg(FALSE)]
|
||||
fn on_event(&mut self, ctx: &mut EventCtx, event: &Event) {
|
||||
fn on_event(&mut self, ctx: &mut EventCtx, _props: &mut PropertiesMut<'_>, event: &Event) {
|
||||
#[cfg(FALSE)]
|
||||
if let Event::Command(cmd) = event {
|
||||
if cmd.is(REPLACE_CHILD) {
|
||||
|
@ -450,31 +513,62 @@ impl Widget for ReplaceChild {
|
|||
self.child.on_event(ctx, event)
|
||||
}
|
||||
|
||||
fn on_pointer_event(&mut self, _ctx: &mut EventCtx, _event: &PointerEvent) {}
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &PointerEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_access_event(&mut self, _ctx: &mut EventCtx, _event: &AccessEvent) {}
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &AccessEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn register_children(&mut self, ctx: &mut RegisterCtx) {
|
||||
ctx.register_child(&mut self.child);
|
||||
}
|
||||
|
||||
fn update(&mut self, _ctx: &mut UpdateCtx, _event: &Update) {}
|
||||
fn update(&mut self, _ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, _event: &Update) {}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn property_changed(&mut self, _ctx: &mut UpdateCtx, _property_type: TypeId) {}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
ctx.run_layout(&mut self.child, bc)
|
||||
}
|
||||
|
||||
fn compose(&mut self, _ctx: &mut ComposeCtx) {}
|
||||
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _scene: &mut Scene) {}
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, _scene: &mut Scene) {}
|
||||
|
||||
fn accessibility_role(&self) -> Role {
|
||||
Role::GenericContainer
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, _node: &mut Node) {}
|
||||
fn accessibility(
|
||||
&mut self,
|
||||
_ctx: &mut AccessCtx,
|
||||
_props: &PropertiesRef<'_>,
|
||||
_node: &mut Node,
|
||||
) {
|
||||
}
|
||||
|
||||
fn children_ids(&self) -> SmallVec<[WidgetId; 16]> {
|
||||
todo!()
|
||||
|
@ -516,24 +610,39 @@ impl Recording {
|
|||
|
||||
#[warn(clippy::missing_trait_methods)]
|
||||
impl<W: Widget> Widget for Recorder<W> {
|
||||
fn on_pointer_event(&mut self, ctx: &mut EventCtx, event: &PointerEvent) {
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
props: &mut PropertiesMut<'_>,
|
||||
event: &PointerEvent,
|
||||
) {
|
||||
self.recording.push(Record::PE(event.clone()));
|
||||
self.child.on_pointer_event(ctx, event);
|
||||
self.child.on_pointer_event(ctx, props, event);
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, ctx: &mut EventCtx, event: &TextEvent) {
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
props: &mut PropertiesMut<'_>,
|
||||
event: &TextEvent,
|
||||
) {
|
||||
self.recording.push(Record::TE(event.clone()));
|
||||
self.child.on_text_event(ctx, event);
|
||||
self.child.on_text_event(ctx, props, event);
|
||||
}
|
||||
|
||||
fn on_access_event(&mut self, ctx: &mut EventCtx, event: &AccessEvent) {
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
props: &mut PropertiesMut<'_>,
|
||||
event: &AccessEvent,
|
||||
) {
|
||||
self.recording.push(Record::AE(event.clone()));
|
||||
self.child.on_access_event(ctx, event);
|
||||
self.child.on_access_event(ctx, props, event);
|
||||
}
|
||||
|
||||
fn on_anim_frame(&mut self, ctx: &mut UpdateCtx, interval: u64) {
|
||||
fn on_anim_frame(&mut self, ctx: &mut UpdateCtx, props: &mut PropertiesMut<'_>, interval: u64) {
|
||||
self.recording.push(Record::AF(interval));
|
||||
self.child.on_anim_frame(ctx, interval);
|
||||
self.child.on_anim_frame(ctx, props, interval);
|
||||
}
|
||||
|
||||
fn register_children(&mut self, ctx: &mut RegisterCtx) {
|
||||
|
@ -541,13 +650,23 @@ impl<W: Widget> Widget for Recorder<W> {
|
|||
self.child.register_children(ctx);
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, event: &Update) {
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, props: &mut PropertiesMut<'_>, event: &Update) {
|
||||
self.recording.push(Record::U(event.clone()));
|
||||
self.child.update(ctx, event);
|
||||
self.child.update(ctx, props, event);
|
||||
}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
let size = self.child.layout(ctx, bc);
|
||||
fn property_changed(&mut self, ctx: &mut UpdateCtx, property_type: TypeId) {
|
||||
self.recording.push(Record::PC(property_type));
|
||||
self.child.property_changed(ctx, property_type);
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
let size = self.child.layout(ctx, props, bc);
|
||||
self.recording.push(Record::Layout(size));
|
||||
size
|
||||
}
|
||||
|
@ -557,18 +676,18 @@ impl<W: Widget> Widget for Recorder<W> {
|
|||
self.child.compose(ctx);
|
||||
}
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) {
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, props: &PropertiesRef<'_>, scene: &mut Scene) {
|
||||
self.recording.push(Record::Paint);
|
||||
self.child.paint(ctx, scene);
|
||||
self.child.paint(ctx, props, scene);
|
||||
}
|
||||
|
||||
fn accessibility_role(&self) -> Role {
|
||||
self.child.accessibility_role()
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, ctx: &mut AccessCtx, node: &mut Node) {
|
||||
fn accessibility(&mut self, ctx: &mut AccessCtx, props: &PropertiesRef<'_>, node: &mut Node) {
|
||||
self.recording.push(Record::Access);
|
||||
self.child.accessibility(ctx, node);
|
||||
self.child.accessibility(ctx, props, node);
|
||||
}
|
||||
|
||||
fn children_ids(&self) -> SmallVec<[WidgetId; 16]> {
|
||||
|
@ -602,9 +721,10 @@ impl<W: Widget> Widget for Recorder<W> {
|
|||
fn find_widget_at_pos<'c>(
|
||||
&'c self,
|
||||
ctx: QueryCtx<'c>,
|
||||
props: PropertiesRef<'c>,
|
||||
pos: Point,
|
||||
) -> Option<WidgetRef<'c, dyn Widget>> {
|
||||
self.child.find_widget_at_pos(ctx, pos)
|
||||
self.child.find_widget_at_pos(ctx, props, pos)
|
||||
}
|
||||
|
||||
fn type_name(&self) -> &'static str {
|
||||
|
|
|
@ -14,8 +14,8 @@ use tracing::{Span, trace_span};
|
|||
use vello::Scene;
|
||||
|
||||
use crate::core::{
|
||||
AccessCtx, AccessEvent, BoxConstraints, EventCtx, LayoutCtx, PaintCtx, PointerEvent, QueryCtx,
|
||||
RegisterCtx, TextEvent, Widget, WidgetId, WidgetPod,
|
||||
AccessCtx, AccessEvent, BoxConstraints, EventCtx, LayoutCtx, PaintCtx, PointerEvent,
|
||||
PropertiesMut, PropertiesRef, QueryCtx, RegisterCtx, TextEvent, Widget, WidgetId, WidgetPod,
|
||||
};
|
||||
use crate::kurbo::{Rect, Size};
|
||||
use crate::util::UnitPoint;
|
||||
|
@ -86,17 +86,40 @@ impl Align {
|
|||
|
||||
// --- MARK: IMPL WIDGET ---
|
||||
impl Widget for Align {
|
||||
fn on_pointer_event(&mut self, _ctx: &mut EventCtx, _event: &PointerEvent) {}
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &PointerEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_access_event(&mut self, _ctx: &mut EventCtx, _event: &AccessEvent) {}
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &AccessEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn register_children(&mut self, ctx: &mut RegisterCtx) {
|
||||
ctx.register_child(&mut self.child);
|
||||
}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
let size = ctx.run_layout(&mut self.child, &bc.loosen());
|
||||
|
||||
log_size_warnings(size);
|
||||
|
@ -137,13 +160,19 @@ impl Widget for Align {
|
|||
my_size
|
||||
}
|
||||
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _scene: &mut Scene) {}
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, _scene: &mut Scene) {}
|
||||
|
||||
fn accessibility_role(&self) -> Role {
|
||||
Role::GenericContainer
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, _node: &mut Node) {}
|
||||
fn accessibility(
|
||||
&mut self,
|
||||
_ctx: &mut AccessCtx,
|
||||
_props: &PropertiesRef<'_>,
|
||||
_node: &mut Node,
|
||||
) {
|
||||
}
|
||||
|
||||
fn children_ids(&self) -> SmallVec<[WidgetId; 16]> {
|
||||
smallvec![self.child.id()]
|
||||
|
|
|
@ -10,8 +10,8 @@ use vello::Scene;
|
|||
|
||||
use crate::core::{
|
||||
AccessCtx, AccessEvent, Action, ArcStr, BoxConstraints, EventCtx, LayoutCtx, PaintCtx,
|
||||
PointerButton, PointerEvent, QueryCtx, TextEvent, Update, UpdateCtx, Widget, WidgetId,
|
||||
WidgetMut, WidgetPod,
|
||||
PointerButton, PointerEvent, PropertiesMut, PropertiesRef, QueryCtx, TextEvent, Update,
|
||||
UpdateCtx, Widget, WidgetId, WidgetMut, WidgetPod,
|
||||
};
|
||||
use crate::kurbo::{Insets, Size};
|
||||
use crate::theme;
|
||||
|
@ -86,7 +86,12 @@ impl Button {
|
|||
|
||||
// --- MARK: IMPL WIDGET ---
|
||||
impl Widget for Button {
|
||||
fn on_pointer_event(&mut self, ctx: &mut EventCtx, event: &PointerEvent) {
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
event: &PointerEvent,
|
||||
) {
|
||||
match event {
|
||||
PointerEvent::PointerDown(_, _) => {
|
||||
if !ctx.is_disabled() {
|
||||
|
@ -108,9 +113,20 @@ impl Widget for Button {
|
|||
}
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_access_event(&mut self, ctx: &mut EventCtx, event: &AccessEvent) {
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
event: &AccessEvent,
|
||||
) {
|
||||
if ctx.target() == ctx.widget_id() {
|
||||
match event.action {
|
||||
accesskit::Action::Click => {
|
||||
|
@ -121,7 +137,7 @@ impl Widget for Button {
|
|||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, event: &Update) {
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, event: &Update) {
|
||||
match event {
|
||||
Update::HoveredChanged(_) | Update::FocusChanged(_) | Update::DisabledChanged(_) => {
|
||||
ctx.request_paint_only();
|
||||
|
@ -134,7 +150,12 @@ impl Widget for Button {
|
|||
ctx.register_child(&mut self.label);
|
||||
}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
let padding = Size::new(LABEL_INSETS.x_value(), LABEL_INSETS.y_value());
|
||||
let label_bc = bc.shrink(padding).loosen();
|
||||
|
||||
|
@ -158,7 +179,7 @@ impl Widget for Button {
|
|||
button_size
|
||||
}
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) {
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, scene: &mut Scene) {
|
||||
let is_active = ctx.is_pointer_capture_target() && !ctx.is_disabled();
|
||||
let is_hovered = ctx.is_hovered();
|
||||
let size = ctx.size();
|
||||
|
@ -197,7 +218,7 @@ impl Widget for Button {
|
|||
Role::Button
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, ctx: &mut AccessCtx, node: &mut Node) {
|
||||
fn accessibility(&mut self, ctx: &mut AccessCtx, _props: &PropertiesRef<'_>, node: &mut Node) {
|
||||
// IMPORTANT: We don't want to merge this code in practice, because
|
||||
// the child label already has a 'name' property.
|
||||
// This is more of a proof of concept of `get_raw_ref()`.
|
||||
|
|
|
@ -11,8 +11,8 @@ use vello::kurbo::{Affine, BezPath, Cap, Join, Size, Stroke};
|
|||
|
||||
use crate::core::{
|
||||
AccessCtx, AccessEvent, Action, ArcStr, BoxConstraints, EventCtx, LayoutCtx, PaintCtx,
|
||||
PointerEvent, QueryCtx, RegisterCtx, TextEvent, Update, UpdateCtx, Widget, WidgetId, WidgetMut,
|
||||
WidgetPod,
|
||||
PointerEvent, PropertiesMut, PropertiesRef, QueryCtx, RegisterCtx, TextEvent, Update,
|
||||
UpdateCtx, Widget, WidgetId, WidgetMut, WidgetPod,
|
||||
};
|
||||
use crate::theme;
|
||||
use crate::util::{UnitPoint, fill_lin_gradient, stroke};
|
||||
|
@ -66,7 +66,12 @@ impl Checkbox {
|
|||
|
||||
// --- MARK: IMPL WIDGET ---
|
||||
impl Widget for Checkbox {
|
||||
fn on_pointer_event(&mut self, ctx: &mut EventCtx, event: &PointerEvent) {
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
event: &PointerEvent,
|
||||
) {
|
||||
match event {
|
||||
PointerEvent::PointerDown(_, _) => {
|
||||
if !ctx.is_disabled() {
|
||||
|
@ -89,9 +94,20 @@ impl Widget for Checkbox {
|
|||
}
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_access_event(&mut self, ctx: &mut EventCtx, event: &AccessEvent) {
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
event: &AccessEvent,
|
||||
) {
|
||||
if ctx.target() == ctx.widget_id() {
|
||||
match event.action {
|
||||
accesskit::Action::Click => {
|
||||
|
@ -105,7 +121,7 @@ impl Widget for Checkbox {
|
|||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, event: &Update) {
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, event: &Update) {
|
||||
match event {
|
||||
Update::HoveredChanged(_) | Update::FocusChanged(_) | Update::DisabledChanged(_) => {
|
||||
ctx.request_paint_only();
|
||||
|
@ -119,7 +135,12 @@ impl Widget for Checkbox {
|
|||
ctx.register_child(&mut self.label);
|
||||
}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
let x_padding = theme::WIDGET_CONTROL_COMPONENT_PADDING;
|
||||
let check_size = theme::BASIC_WIDGET_HEIGHT;
|
||||
|
||||
|
@ -137,7 +158,7 @@ impl Widget for Checkbox {
|
|||
our_size
|
||||
}
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) {
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, scene: &mut Scene) {
|
||||
let check_size = theme::BASIC_WIDGET_HEIGHT;
|
||||
let border_width = 1.;
|
||||
|
||||
|
@ -193,7 +214,7 @@ impl Widget for Checkbox {
|
|||
Role::CheckBox
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, ctx: &mut AccessCtx, node: &mut Node) {
|
||||
fn accessibility(&mut self, ctx: &mut AccessCtx, _props: &PropertiesRef<'_>, node: &mut Node) {
|
||||
// IMPORTANT: We don't want to merge this code in practice, because
|
||||
// the child label already has a 'name' property.
|
||||
// This is more of a proof of concept of `get_raw_ref()`.
|
||||
|
|
|
@ -11,8 +11,8 @@ use vello::kurbo::common::FloatExt;
|
|||
use vello::kurbo::{Affine, Line, Stroke, Vec2};
|
||||
|
||||
use crate::core::{
|
||||
AccessCtx, AccessEvent, BoxConstraints, EventCtx, LayoutCtx, PaintCtx, PointerEvent, QueryCtx,
|
||||
TextEvent, Widget, WidgetId, WidgetMut, WidgetPod,
|
||||
AccessCtx, AccessEvent, BoxConstraints, EventCtx, LayoutCtx, PaintCtx, PointerEvent,
|
||||
PropertiesMut, PropertiesRef, QueryCtx, TextEvent, Widget, WidgetId, WidgetMut, WidgetPod,
|
||||
};
|
||||
use crate::kurbo::{Point, Rect, Size};
|
||||
|
||||
|
@ -911,11 +911,29 @@ fn new_flex_child(params: FlexParams, widget: WidgetPod<dyn Widget>) -> Child {
|
|||
|
||||
// --- MARK: IMPL WIDGET---
|
||||
impl Widget for Flex {
|
||||
fn on_pointer_event(&mut self, _ctx: &mut EventCtx, _event: &PointerEvent) {}
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &PointerEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_access_event(&mut self, _ctx: &mut EventCtx, _event: &AccessEvent) {}
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &AccessEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn register_children(&mut self, ctx: &mut crate::core::RegisterCtx) {
|
||||
for child in self.children.iter_mut().filter_map(|x| x.widget_mut()) {
|
||||
|
@ -923,7 +941,12 @@ impl Widget for Flex {
|
|||
}
|
||||
}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
// we loosen our constraints when passing to children.
|
||||
let loosened_bc = bc.loosen();
|
||||
|
||||
|
@ -1177,7 +1200,7 @@ impl Widget for Flex {
|
|||
my_size
|
||||
}
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) {
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, scene: &mut Scene) {
|
||||
// paint the baseline if we're debugging layout
|
||||
if ctx.debug_paint_enabled() && ctx.baseline_offset() != 0.0 {
|
||||
let color = ctx.debug_color();
|
||||
|
@ -1193,7 +1216,13 @@ impl Widget for Flex {
|
|||
Role::GenericContainer
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, _node: &mut Node) {}
|
||||
fn accessibility(
|
||||
&mut self,
|
||||
_ctx: &mut AccessCtx,
|
||||
_props: &PropertiesRef<'_>,
|
||||
_node: &mut Node,
|
||||
) {
|
||||
}
|
||||
|
||||
fn children_ids(&self) -> SmallVec<[WidgetId; 16]> {
|
||||
self.children
|
||||
|
|
|
@ -8,8 +8,8 @@ use vello::Scene;
|
|||
use vello::kurbo::{Affine, Line, Stroke};
|
||||
|
||||
use crate::core::{
|
||||
AccessCtx, AccessEvent, BoxConstraints, EventCtx, LayoutCtx, PaintCtx, PointerEvent, QueryCtx,
|
||||
TextEvent, Widget, WidgetId, WidgetMut, WidgetPod,
|
||||
AccessCtx, AccessEvent, BoxConstraints, EventCtx, LayoutCtx, PaintCtx, PointerEvent,
|
||||
PropertiesMut, PropertiesRef, QueryCtx, TextEvent, Widget, WidgetId, WidgetMut, WidgetPod,
|
||||
};
|
||||
use crate::kurbo::{Point, Size};
|
||||
|
||||
|
@ -242,11 +242,29 @@ impl Grid {
|
|||
|
||||
// --- MARK: IMPL WIDGET---
|
||||
impl Widget for Grid {
|
||||
fn on_pointer_event(&mut self, _ctx: &mut EventCtx, _event: &PointerEvent) {}
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &PointerEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_access_event(&mut self, _ctx: &mut EventCtx, _event: &AccessEvent) {}
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &AccessEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn register_children(&mut self, ctx: &mut crate::core::RegisterCtx) {
|
||||
for child in self.children.iter_mut().filter_map(|x| x.widget_mut()) {
|
||||
|
@ -254,7 +272,12 @@ impl Widget for Grid {
|
|||
}
|
||||
}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
let total_size = bc.max();
|
||||
if !total_size.is_finite() {
|
||||
debug_panic!(
|
||||
|
@ -279,7 +302,7 @@ impl Widget for Grid {
|
|||
total_size
|
||||
}
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) {
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, scene: &mut Scene) {
|
||||
// paint the baseline if we're debugging layout
|
||||
if ctx.debug_paint_enabled() && ctx.baseline_offset() != 0.0 {
|
||||
let color = ctx.debug_color();
|
||||
|
@ -295,7 +318,13 @@ impl Widget for Grid {
|
|||
Role::GenericContainer
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, _node: &mut Node) {}
|
||||
fn accessibility(
|
||||
&mut self,
|
||||
_ctx: &mut AccessCtx,
|
||||
_props: &PropertiesRef<'_>,
|
||||
_node: &mut Node,
|
||||
) {
|
||||
}
|
||||
|
||||
fn children_ids(&self) -> SmallVec<[WidgetId; 16]> {
|
||||
self.children
|
||||
|
|
|
@ -13,7 +13,8 @@ use vello::peniko::{BlendMode, Image as ImageBuf};
|
|||
|
||||
use crate::core::{
|
||||
AccessCtx, AccessEvent, BoxConstraints, EventCtx, LayoutCtx, ObjectFit, PaintCtx, PointerEvent,
|
||||
QueryCtx, RegisterCtx, TextEvent, Update, UpdateCtx, Widget, WidgetId, WidgetMut,
|
||||
PropertiesMut, PropertiesRef, QueryCtx, RegisterCtx, TextEvent, Update, UpdateCtx, Widget,
|
||||
WidgetId, WidgetMut,
|
||||
};
|
||||
use crate::kurbo::Size;
|
||||
|
||||
|
@ -71,17 +72,40 @@ impl Image {
|
|||
|
||||
// --- MARK: IMPL WIDGET ---
|
||||
impl Widget for Image {
|
||||
fn on_pointer_event(&mut self, _ctx: &mut EventCtx, _event: &PointerEvent) {}
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &PointerEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_access_event(&mut self, _ctx: &mut EventCtx, _event: &AccessEvent) {}
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &AccessEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn register_children(&mut self, _ctx: &mut RegisterCtx) {}
|
||||
|
||||
fn update(&mut self, _ctx: &mut UpdateCtx, _event: &Update) {}
|
||||
fn update(&mut self, _ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, _event: &Update) {}
|
||||
|
||||
fn layout(&mut self, _ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
_ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
// If either the width or height is constrained calculate a value so that the image fits
|
||||
// in the size exactly. If it is unconstrained by both width and height take the size of
|
||||
// the image.
|
||||
|
@ -112,7 +136,7 @@ impl Widget for Image {
|
|||
}
|
||||
}
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) {
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, scene: &mut Scene) {
|
||||
let image_size = Size::new(self.image_data.width as f64, self.image_data.height as f64);
|
||||
let transform = self.object_fit.affine_to_fill(ctx.size(), image_size);
|
||||
|
||||
|
@ -126,7 +150,12 @@ impl Widget for Image {
|
|||
Role::Image
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, _node: &mut Node) {
|
||||
fn accessibility(
|
||||
&mut self,
|
||||
_ctx: &mut AccessCtx,
|
||||
_props: &PropertiesRef<'_>,
|
||||
_node: &mut Node,
|
||||
) {
|
||||
// TODO - Handle alt text and such.
|
||||
}
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@ use vello::peniko::{BlendMode, Brush};
|
|||
|
||||
use crate::core::{
|
||||
AccessCtx, AccessEvent, ArcStr, BoxConstraints, BrushIndex, EventCtx, LayoutCtx, PaintCtx,
|
||||
PointerEvent, QueryCtx, RegisterCtx, StyleProperty, StyleSet, TextEvent, Update, UpdateCtx,
|
||||
Widget, WidgetId, WidgetMut, default_styles, render_text,
|
||||
PointerEvent, PropertiesMut, PropertiesRef, QueryCtx, RegisterCtx, StyleProperty, StyleSet,
|
||||
TextEvent, Update, UpdateCtx, Widget, WidgetId, WidgetMut, default_styles, render_text,
|
||||
};
|
||||
use crate::theme;
|
||||
|
||||
|
@ -311,19 +311,37 @@ impl Label {
|
|||
|
||||
// --- MARK: IMPL WIDGET ---
|
||||
impl Widget for Label {
|
||||
fn on_pointer_event(&mut self, _ctx: &mut EventCtx, _event: &PointerEvent) {}
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &PointerEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn accepts_pointer_interaction(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_access_event(&mut self, _ctx: &mut EventCtx, _event: &AccessEvent) {}
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &AccessEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn register_children(&mut self, _ctx: &mut RegisterCtx) {}
|
||||
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, event: &Update) {
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, event: &Update) {
|
||||
match event {
|
||||
Update::DisabledChanged(_) => {
|
||||
if self.disabled_brush.is_some() {
|
||||
|
@ -334,7 +352,12 @@ impl Widget for Label {
|
|||
}
|
||||
}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
let available_width = if bc.max().width.is_finite() {
|
||||
Some(bc.max().width as f32 - 2. * LABEL_X_PADDING as f32)
|
||||
} else {
|
||||
|
@ -397,7 +420,7 @@ impl Widget for Label {
|
|||
bc.constrain(label_size)
|
||||
}
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) {
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, scene: &mut Scene) {
|
||||
if self.line_break_mode == LineBreaking::Clip {
|
||||
let clip_rect = ctx.size().to_rect();
|
||||
scene.push_layer(BlendMode::default(), 1., Affine::IDENTITY, &clip_rect);
|
||||
|
@ -422,7 +445,7 @@ impl Widget for Label {
|
|||
Role::Label
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, ctx: &mut AccessCtx, node: &mut Node) {
|
||||
fn accessibility(&mut self, ctx: &mut AccessCtx, _props: &PropertiesRef<'_>, node: &mut Node) {
|
||||
let window_origin = ctx.window_origin();
|
||||
self.accessibility.build_nodes(
|
||||
self.text.as_ref(),
|
||||
|
|
|
@ -13,8 +13,8 @@ use vello::kurbo::{Point, Rect, Size, Vec2};
|
|||
|
||||
use crate::core::{
|
||||
AccessCtx, AccessEvent, BoxConstraints, ComposeCtx, EventCtx, FromDynWidget, LayoutCtx,
|
||||
PaintCtx, PointerEvent, QueryCtx, RegisterCtx, TextEvent, Update, UpdateCtx, Widget, WidgetId,
|
||||
WidgetMut, WidgetPod,
|
||||
PaintCtx, PointerEvent, PropertiesMut, PropertiesRef, QueryCtx, RegisterCtx, TextEvent, Update,
|
||||
UpdateCtx, Widget, WidgetId, WidgetMut, WidgetPod,
|
||||
};
|
||||
use crate::widgets::{Axis, ScrollBar};
|
||||
|
||||
|
@ -260,7 +260,12 @@ impl<W: Widget + FromDynWidget + ?Sized> Portal<W> {
|
|||
|
||||
// --- MARK: IMPL WIDGET ---
|
||||
impl<W: Widget + FromDynWidget + ?Sized> Widget for Portal<W> {
|
||||
fn on_pointer_event(&mut self, ctx: &mut EventCtx, event: &PointerEvent) {
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
event: &PointerEvent,
|
||||
) {
|
||||
const SCROLLING_SPEED: f64 = 10.0;
|
||||
|
||||
let portal_size = ctx.size();
|
||||
|
@ -321,10 +326,22 @@ impl<W: Widget + FromDynWidget + ?Sized> Widget for Portal<W> {
|
|||
}
|
||||
|
||||
// TODO - handle Home/End keys, etc
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
// TODO - Handle scroll-related events?
|
||||
fn on_access_event(&mut self, _ctx: &mut EventCtx, _event: &AccessEvent) {}
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &AccessEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn register_children(&mut self, ctx: &mut RegisterCtx) {
|
||||
ctx.register_child(&mut self.child);
|
||||
|
@ -332,7 +349,7 @@ impl<W: Widget + FromDynWidget + ?Sized> Widget for Portal<W> {
|
|||
ctx.register_child(&mut self.scrollbar_vertical);
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, event: &Update) {
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, event: &Update) {
|
||||
match event {
|
||||
Update::RequestPanToChild(target) => {
|
||||
let portal_size = ctx.size();
|
||||
|
@ -361,7 +378,12 @@ impl<W: Widget + FromDynWidget + ?Sized> Widget for Portal<W> {
|
|||
}
|
||||
}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
// TODO - How Portal handles BoxConstraints is due for a rework
|
||||
let min_child_size = if self.must_fill { bc.min() } else { Size::ZERO };
|
||||
let max_child_size = bc.max();
|
||||
|
@ -432,13 +454,13 @@ impl<W: Widget + FromDynWidget + ?Sized> Widget for Portal<W> {
|
|||
ctx.set_child_scroll_translation(&mut self.child, Vec2::new(0.0, -self.viewport_pos.y));
|
||||
}
|
||||
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _scene: &mut Scene) {}
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, _scene: &mut Scene) {}
|
||||
|
||||
fn accessibility_role(&self) -> Role {
|
||||
Role::GenericContainer
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, ctx: &mut AccessCtx, node: &mut Node) {
|
||||
fn accessibility(&mut self, ctx: &mut AccessCtx, _props: &PropertiesRef<'_>, node: &mut Node) {
|
||||
// TODO - Double check this code
|
||||
// Not sure about these values
|
||||
if false {
|
||||
|
|
|
@ -10,7 +10,8 @@ use vello::Scene;
|
|||
|
||||
use crate::core::{
|
||||
AccessCtx, AccessEvent, ArcStr, BoxConstraints, EventCtx, LayoutCtx, PaintCtx, PointerEvent,
|
||||
QueryCtx, RegisterCtx, TextEvent, Update, UpdateCtx, Widget, WidgetId, WidgetMut, WidgetPod,
|
||||
PropertiesMut, PropertiesRef, QueryCtx, RegisterCtx, TextEvent, Update, UpdateCtx, Widget,
|
||||
WidgetId, WidgetMut, WidgetPod,
|
||||
};
|
||||
use crate::kurbo::{Point, Size};
|
||||
use crate::theme;
|
||||
|
@ -90,19 +91,42 @@ fn clamp_progress(progress: &mut Option<f64>) {
|
|||
|
||||
// --- MARK: IMPL WIDGET ---
|
||||
impl Widget for ProgressBar {
|
||||
fn on_pointer_event(&mut self, _ctx: &mut EventCtx, _event: &PointerEvent) {}
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &PointerEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_access_event(&mut self, _ctx: &mut EventCtx, _event: &AccessEvent) {}
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &AccessEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn register_children(&mut self, ctx: &mut RegisterCtx) {
|
||||
ctx.register_child(&mut self.label);
|
||||
}
|
||||
|
||||
fn update(&mut self, _ctx: &mut UpdateCtx, _event: &Update) {}
|
||||
fn update(&mut self, _ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, _event: &Update) {}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
const DEFAULT_WIDTH: f64 = 400.;
|
||||
// TODO: Clearer constraints here
|
||||
let label_size = ctx.run_layout(&mut self.label, &bc.loosen());
|
||||
|
@ -121,7 +145,7 @@ impl Widget for ProgressBar {
|
|||
final_size
|
||||
}
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) {
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, scene: &mut Scene) {
|
||||
let border_width = 1.;
|
||||
|
||||
let rect = ctx
|
||||
|
@ -163,7 +187,7 @@ impl Widget for ProgressBar {
|
|||
Role::ProgressIndicator
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, node: &mut Node) {
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, _props: &PropertiesRef<'_>, node: &mut Node) {
|
||||
node.set_value(self.value_accessibility());
|
||||
if let Some(value) = self.progress {
|
||||
node.set_numeric_value(value * 100.0);
|
||||
|
|
|
@ -10,8 +10,9 @@ use vello::Scene;
|
|||
use vello::kurbo::{Point, Rect, Size};
|
||||
|
||||
use crate::core::{
|
||||
AccessCtx, AccessEvent, BoxConstraints, EventCtx, LayoutCtx, PaintCtx, PointerEvent, QueryCtx,
|
||||
RegisterCtx, TextEvent, Update, UpdateCtx, Widget, WidgetId, WidgetMut, WidgetPod,
|
||||
AccessCtx, AccessEvent, BoxConstraints, EventCtx, LayoutCtx, PaintCtx, PointerEvent,
|
||||
PropertiesMut, PropertiesRef, QueryCtx, RegisterCtx, TextEvent, Update, UpdateCtx, Widget,
|
||||
WidgetId, WidgetMut, WidgetPod,
|
||||
};
|
||||
use crate::widgets::{Padding, TextArea};
|
||||
|
||||
|
@ -111,19 +112,42 @@ impl Prose {
|
|||
|
||||
// --- MARK: IMPL WIDGET ---
|
||||
impl Widget for Prose {
|
||||
fn on_pointer_event(&mut self, _: &mut EventCtx, _: &PointerEvent) {}
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
_: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_: &PointerEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_access_event(&mut self, _ctx: &mut EventCtx, _event: &AccessEvent) {}
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &AccessEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn register_children(&mut self, ctx: &mut RegisterCtx) {
|
||||
ctx.register_child(&mut self.text);
|
||||
}
|
||||
|
||||
fn update(&mut self, _ctx: &mut UpdateCtx, _event: &Update) {}
|
||||
fn update(&mut self, _ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, _event: &Update) {}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
// TODO: Set minimum to deal with alignment
|
||||
let size = ctx.run_layout(&mut self.text, bc);
|
||||
ctx.place_child(&mut self.text, Point::ORIGIN);
|
||||
|
@ -135,7 +159,7 @@ impl Widget for Prose {
|
|||
size
|
||||
}
|
||||
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _scene: &mut Scene) {
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, _scene: &mut Scene) {
|
||||
// All painting is handled by the child
|
||||
}
|
||||
|
||||
|
@ -143,7 +167,13 @@ impl Widget for Prose {
|
|||
Role::GenericContainer
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, _node: &mut Node) {}
|
||||
fn accessibility(
|
||||
&mut self,
|
||||
_ctx: &mut AccessCtx,
|
||||
_props: &PropertiesRef<'_>,
|
||||
_node: &mut Node,
|
||||
) {
|
||||
}
|
||||
|
||||
fn children_ids(&self) -> SmallVec<[WidgetId; 16]> {
|
||||
smallvec![self.text.id()]
|
||||
|
|
|
@ -9,7 +9,8 @@ use vello::kurbo::Point;
|
|||
|
||||
use crate::core::{
|
||||
AccessCtx, AccessEvent, BoxConstraints, EventCtx, FromDynWidget, LayoutCtx, PaintCtx,
|
||||
PointerEvent, QueryCtx, RegisterCtx, TextEvent, Widget, WidgetId, WidgetMut, WidgetPod,
|
||||
PointerEvent, PropertiesMut, PropertiesRef, QueryCtx, RegisterCtx, TextEvent, Widget, WidgetId,
|
||||
WidgetMut, WidgetPod,
|
||||
};
|
||||
use crate::kurbo::Size;
|
||||
|
||||
|
@ -40,27 +41,56 @@ impl<W: Widget + FromDynWidget + ?Sized> RootWidget<W> {
|
|||
}
|
||||
|
||||
impl<W: Widget + FromDynWidget + ?Sized> Widget for RootWidget<W> {
|
||||
fn on_pointer_event(&mut self, _ctx: &mut EventCtx, _event: &PointerEvent) {}
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_access_event(&mut self, _ctx: &mut EventCtx, _event: &AccessEvent) {}
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &PointerEvent,
|
||||
) {
|
||||
}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &AccessEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn register_children(&mut self, ctx: &mut RegisterCtx) {
|
||||
ctx.register_child(&mut self.pod);
|
||||
}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
let size = ctx.run_layout(&mut self.pod, bc);
|
||||
ctx.place_child(&mut self.pod, Point::ORIGIN);
|
||||
size
|
||||
}
|
||||
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _scene: &mut Scene) {}
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, _scene: &mut Scene) {}
|
||||
|
||||
fn accessibility_role(&self) -> Role {
|
||||
Role::Window
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, _node: &mut Node) {}
|
||||
fn accessibility(
|
||||
&mut self,
|
||||
_ctx: &mut AccessCtx,
|
||||
_props: &PropertiesRef<'_>,
|
||||
_node: &mut Node,
|
||||
) {
|
||||
}
|
||||
|
||||
fn children_ids(&self) -> SmallVec<[WidgetId; 16]> {
|
||||
smallvec![self.pod.id()]
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1fec814423f9b67cb5be91276af1986b93aa94c7690f6618887e1667954214a4
|
||||
size 5055
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d8ad2917e49963e047743424abae12cedd4d1787870cfddcb1208b251861baf3
|
||||
size 5029
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:55b6d1b0cad21653601bd5c8b1324812e0550c76567bf0f71592702ce037db4c
|
||||
size 5055
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6024649cc7f1d2716150dbba737ecfd9319635e41126d9da9668f35d8fb16332
|
||||
size 4371
|
|
@ -11,7 +11,8 @@ use vello::kurbo::Rect;
|
|||
|
||||
use crate::core::{
|
||||
AccessCtx, AccessEvent, AllowRawMut, BoxConstraints, EventCtx, LayoutCtx, PaintCtx,
|
||||
PointerEvent, QueryCtx, RegisterCtx, TextEvent, Update, UpdateCtx, Widget, WidgetId, WidgetMut,
|
||||
PointerEvent, PropertiesMut, PropertiesRef, QueryCtx, RegisterCtx, TextEvent, Update,
|
||||
UpdateCtx, Widget, WidgetId, WidgetMut,
|
||||
};
|
||||
use crate::kurbo::{Point, Size};
|
||||
use crate::theme;
|
||||
|
@ -121,7 +122,12 @@ impl ScrollBar {
|
|||
|
||||
// --- MARK: IMPL WIDGET ---
|
||||
impl Widget for ScrollBar {
|
||||
fn on_pointer_event(&mut self, ctx: &mut EventCtx, event: &PointerEvent) {
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
event: &PointerEvent,
|
||||
) {
|
||||
match event {
|
||||
PointerEvent::PointerDown(_, _) => {
|
||||
ctx.capture_pointer();
|
||||
|
@ -162,17 +168,33 @@ impl Widget for ScrollBar {
|
|||
}
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_access_event(&mut self, _ctx: &mut EventCtx, _event: &AccessEvent) {
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &AccessEvent,
|
||||
) {
|
||||
// TODO - Handle scroll-related events?
|
||||
}
|
||||
|
||||
fn register_children(&mut self, _ctx: &mut RegisterCtx) {}
|
||||
|
||||
fn update(&mut self, _ctx: &mut UpdateCtx, _event: &Update) {}
|
||||
fn update(&mut self, _ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, _event: &Update) {}
|
||||
|
||||
fn layout(&mut self, _ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
_ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
// TODO - handle resize
|
||||
|
||||
let scrollbar_width = theme::SCROLLBAR_WIDTH;
|
||||
|
@ -185,7 +207,7 @@ impl Widget for ScrollBar {
|
|||
.into()
|
||||
}
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) {
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, scene: &mut Scene) {
|
||||
let radius = theme::SCROLLBAR_RADIUS;
|
||||
let edge_width = theme::SCROLLBAR_EDGE_WIDTH;
|
||||
let cursor_padding = theme::SCROLLBAR_PAD;
|
||||
|
@ -210,7 +232,12 @@ impl Widget for ScrollBar {
|
|||
Role::ScrollBar
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, _node: &mut Node) {
|
||||
fn accessibility(
|
||||
&mut self,
|
||||
_ctx: &mut AccessCtx,
|
||||
_props: &PropertiesRef<'_>,
|
||||
_node: &mut Node,
|
||||
) {
|
||||
// TODO
|
||||
// Use set_scroll_x/y_min/max?
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
//! A widget with predefined size.
|
||||
|
||||
use std::any::TypeId;
|
||||
|
||||
use accesskit::{Node, Role};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use tracing::{Span, trace_span, warn};
|
||||
|
@ -11,10 +13,12 @@ use vello::kurbo::{Affine, RoundedRectRadii};
|
|||
use vello::peniko::{Brush, Fill};
|
||||
|
||||
use crate::core::{
|
||||
AccessCtx, AccessEvent, BoxConstraints, EventCtx, LayoutCtx, PaintCtx, PointerEvent, QueryCtx,
|
||||
RegisterCtx, TextEvent, Widget, WidgetId, WidgetMut, WidgetPod,
|
||||
AccessCtx, AccessEvent, BoxConstraints, EventCtx, LayoutCtx, PaintCtx, PointerEvent,
|
||||
PropertiesMut, PropertiesRef, QueryCtx, RegisterCtx, TextEvent, UpdateCtx, Widget, WidgetId,
|
||||
WidgetMut, WidgetPod,
|
||||
};
|
||||
use crate::kurbo::{Point, Size};
|
||||
use crate::properties::BackgroundColor;
|
||||
use crate::util::stroke;
|
||||
|
||||
// FIXME - Improve all doc in this module ASAP.
|
||||
|
@ -453,11 +457,29 @@ impl SizedBox {
|
|||
|
||||
// --- MARK: IMPL WIDGET ---
|
||||
impl Widget for SizedBox {
|
||||
fn on_pointer_event(&mut self, _ctx: &mut EventCtx, _event: &PointerEvent) {}
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &PointerEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_access_event(&mut self, _ctx: &mut EventCtx, _event: &AccessEvent) {}
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &AccessEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn register_children(&mut self, ctx: &mut RegisterCtx) {
|
||||
if let Some(ref mut child) = self.child {
|
||||
|
@ -465,7 +487,16 @@ impl Widget for SizedBox {
|
|||
}
|
||||
}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn property_changed(&mut self, ctx: &mut UpdateCtx, property_type: TypeId) {
|
||||
BackgroundColor::prop_changed(ctx, property_type);
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
// Shrink constraints by border offset
|
||||
let border_width = match &self.border {
|
||||
Some(border) => border.width,
|
||||
|
@ -510,17 +541,25 @@ impl Widget for SizedBox {
|
|||
size
|
||||
}
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) {
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, props: &PropertiesRef<'_>, scene: &mut Scene) {
|
||||
let corner_radius = self.corner_radius;
|
||||
|
||||
if let Some(background) = self.background.as_mut() {
|
||||
// TODO - Handle properties more gracefully.
|
||||
// This is more of a proof of concept.
|
||||
let background = self.background.clone().or_else(|| {
|
||||
props
|
||||
.get::<BackgroundColor>()
|
||||
.map(|background| background.color.into())
|
||||
});
|
||||
|
||||
if let Some(background) = background {
|
||||
let panel = ctx.size().to_rounded_rect(corner_radius);
|
||||
|
||||
trace_span!("paint background").in_scope(|| {
|
||||
scene.fill(
|
||||
Fill::NonZero,
|
||||
Affine::IDENTITY,
|
||||
&*background,
|
||||
&background,
|
||||
Some(Affine::IDENTITY),
|
||||
&panel,
|
||||
);
|
||||
|
@ -542,7 +581,13 @@ impl Widget for SizedBox {
|
|||
Role::GenericContainer
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, _node: &mut Node) {}
|
||||
fn accessibility(
|
||||
&mut self,
|
||||
_ctx: &mut AccessCtx,
|
||||
_props: &PropertiesRef<'_>,
|
||||
_node: &mut Node,
|
||||
) {
|
||||
}
|
||||
|
||||
fn children_ids(&self) -> SmallVec<[WidgetId; 16]> {
|
||||
if let Some(child) = &self.child {
|
||||
|
@ -709,4 +754,44 @@ mod tests {
|
|||
}
|
||||
|
||||
// TODO - add screenshot tests for different brush types
|
||||
|
||||
// --- MARK: PROP TESTS ---
|
||||
|
||||
#[test]
|
||||
fn background_brush_property() {
|
||||
let widget = SizedBox::empty().width(40.).height(40.).rounded(20.);
|
||||
|
||||
let mut harness = TestHarness::create(widget);
|
||||
|
||||
harness.edit_root_widget(|mut sized_box| {
|
||||
let brush = BackgroundColor {
|
||||
color: palette::css::RED,
|
||||
};
|
||||
sized_box.insert_prop(brush);
|
||||
});
|
||||
assert_render_snapshot!(harness, "background_brush_red");
|
||||
|
||||
harness.edit_root_widget(|mut sized_box| {
|
||||
let brush = BackgroundColor {
|
||||
color: palette::css::GREEN,
|
||||
};
|
||||
*sized_box.get_prop_mut().unwrap() = brush;
|
||||
});
|
||||
assert_render_snapshot!(harness, "background_brush_green");
|
||||
|
||||
harness.edit_root_widget(|mut sized_box| {
|
||||
let brush = BackgroundColor {
|
||||
color: palette::css::BLUE,
|
||||
};
|
||||
sized_box.prop_entry().and_modify(|entry| {
|
||||
*entry = brush;
|
||||
});
|
||||
});
|
||||
assert_render_snapshot!(harness, "background_brush_blue");
|
||||
|
||||
harness.edit_root_widget(|mut sized_box| {
|
||||
sized_box.remove_prop::<BackgroundColor>();
|
||||
});
|
||||
assert_render_snapshot!(harness, "background_brush_removed");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,8 +12,9 @@ use vello::Scene;
|
|||
use vello::kurbo::{Affine, Cap, Line, Stroke};
|
||||
|
||||
use crate::core::{
|
||||
AccessCtx, AccessEvent, BoxConstraints, EventCtx, LayoutCtx, PaintCtx, PointerEvent, QueryCtx,
|
||||
RegisterCtx, TextEvent, Update, UpdateCtx, Widget, WidgetId, WidgetMut,
|
||||
AccessCtx, AccessEvent, BoxConstraints, EventCtx, LayoutCtx, PaintCtx, PointerEvent,
|
||||
PropertiesMut, PropertiesRef, QueryCtx, RegisterCtx, TextEvent, Update, UpdateCtx, Widget,
|
||||
WidgetId, WidgetMut,
|
||||
};
|
||||
use crate::kurbo::{Point, Size, Vec2};
|
||||
use crate::peniko::Color;
|
||||
|
@ -73,13 +74,36 @@ impl Spinner {
|
|||
|
||||
// --- MARK: IMPL WIDGET ---
|
||||
impl Widget for Spinner {
|
||||
fn on_pointer_event(&mut self, _ctx: &mut EventCtx, _event: &PointerEvent) {}
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &PointerEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_access_event(&mut self, _ctx: &mut EventCtx, _event: &AccessEvent) {}
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &AccessEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_anim_frame(&mut self, ctx: &mut UpdateCtx, interval: u64) {
|
||||
fn on_anim_frame(
|
||||
&mut self,
|
||||
ctx: &mut UpdateCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
interval: u64,
|
||||
) {
|
||||
self.t += (interval as f64) * 1e-9;
|
||||
if self.t >= 1.0 {
|
||||
self.t = self.t.rem_euclid(1.0);
|
||||
|
@ -90,7 +114,7 @@ impl Widget for Spinner {
|
|||
|
||||
fn register_children(&mut self, _ctx: &mut RegisterCtx) {}
|
||||
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, event: &Update) {
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, event: &Update) {
|
||||
match event {
|
||||
Update::WidgetAdded => {
|
||||
ctx.request_anim_frame();
|
||||
|
@ -99,7 +123,12 @@ impl Widget for Spinner {
|
|||
}
|
||||
}
|
||||
|
||||
fn layout(&mut self, _ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
_ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
if bc.is_width_bounded() && bc.is_height_bounded() {
|
||||
bc.max()
|
||||
} else {
|
||||
|
@ -110,7 +139,7 @@ impl Widget for Spinner {
|
|||
}
|
||||
}
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) {
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, scene: &mut Scene) {
|
||||
let t = self.t;
|
||||
let (width, height) = (ctx.size().width, ctx.size().height);
|
||||
let center = Point::new(width / 2.0, height / 2.0);
|
||||
|
@ -141,7 +170,13 @@ impl Widget for Spinner {
|
|||
Role::Unknown
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, _node: &mut Node) {}
|
||||
fn accessibility(
|
||||
&mut self,
|
||||
_ctx: &mut AccessCtx,
|
||||
_props: &PropertiesRef<'_>,
|
||||
_node: &mut Node,
|
||||
) {
|
||||
}
|
||||
|
||||
fn children_ids(&self) -> SmallVec<[WidgetId; 16]> {
|
||||
SmallVec::new()
|
||||
|
|
|
@ -10,7 +10,8 @@ use vello::Scene;
|
|||
|
||||
use crate::core::{
|
||||
AccessCtx, AccessEvent, BoxConstraints, EventCtx, LayoutCtx, PaintCtx, PointerButton,
|
||||
PointerEvent, QueryCtx, RegisterCtx, TextEvent, Widget, WidgetId, WidgetMut, WidgetPod,
|
||||
PointerEvent, PropertiesMut, PropertiesRef, QueryCtx, RegisterCtx, TextEvent, Widget, WidgetId,
|
||||
WidgetMut, WidgetPod,
|
||||
};
|
||||
use crate::kurbo::{Line, Point, Rect, Size};
|
||||
use crate::peniko::Color;
|
||||
|
@ -367,7 +368,12 @@ impl Split {
|
|||
|
||||
// --- MARK: IMPL WIDGET ---
|
||||
impl Widget for Split {
|
||||
fn on_pointer_event(&mut self, ctx: &mut EventCtx, event: &PointerEvent) {
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
event: &PointerEvent,
|
||||
) {
|
||||
if self.draggable {
|
||||
match event {
|
||||
PointerEvent::PointerDown(PointerButton::Primary, state) => {
|
||||
|
@ -403,16 +409,33 @@ impl Widget for Split {
|
|||
}
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_access_event(&mut self, _ctx: &mut EventCtx, _event: &AccessEvent) {}
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &AccessEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn register_children(&mut self, ctx: &mut RegisterCtx) {
|
||||
ctx.register_child(&mut self.child1);
|
||||
ctx.register_child(&mut self.child2);
|
||||
}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
match self.split_axis {
|
||||
Axis::Horizontal => {
|
||||
if !bc.is_width_bounded() {
|
||||
|
@ -510,7 +533,7 @@ impl Widget for Split {
|
|||
my_size
|
||||
}
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) {
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, scene: &mut Scene) {
|
||||
// TODO - Paint differently if the bar is draggable and hovered.
|
||||
if self.solid {
|
||||
self.paint_solid_bar(ctx, scene);
|
||||
|
@ -537,7 +560,13 @@ impl Widget for Split {
|
|||
Role::Splitter
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, _node: &mut Node) {}
|
||||
fn accessibility(
|
||||
&mut self,
|
||||
_ctx: &mut AccessCtx,
|
||||
_props: &PropertiesRef<'_>,
|
||||
_node: &mut Node,
|
||||
) {
|
||||
}
|
||||
|
||||
fn children_ids(&self) -> SmallVec<[WidgetId; 16]> {
|
||||
smallvec![self.child1.id(), self.child2.id()]
|
||||
|
|
|
@ -45,7 +45,7 @@ fn layout_insets() {
|
|||
|
||||
let [child_id, parent_id] = widget_ids();
|
||||
|
||||
let child_widget = ModularWidget::new(()).layout_fn(|_, ctx, _| {
|
||||
let child_widget = ModularWidget::new(()).layout_fn(|_, ctx, _, _| {
|
||||
// this widget paints twenty points above below its layout bounds
|
||||
ctx.set_paint_insets(Insets::uniform_xy(0., 20.));
|
||||
Size::new(BOX_WIDTH, BOX_WIDTH)
|
||||
|
|
|
@ -14,7 +14,7 @@ fn make_parent_widget<W: Widget>(child: W) -> ModularWidget<WidgetPod<W>> {
|
|||
.register_children_fn(move |child, ctx| {
|
||||
ctx.register_child(child);
|
||||
})
|
||||
.layout_fn(move |child, ctx, bc| {
|
||||
.layout_fn(move |child, ctx, _, bc| {
|
||||
let size = ctx.run_layout(child, bc);
|
||||
ctx.place_child(child, Point::ZERO);
|
||||
size
|
||||
|
@ -26,7 +26,7 @@ fn make_parent_widget<W: Widget>(child: W) -> ModularWidget<WidgetPod<W>> {
|
|||
#[should_panic(expected = "not visited in method on_text_event")]
|
||||
#[test]
|
||||
fn check_forget_to_recurse_text_event() {
|
||||
let widget = make_parent_widget(Flex::row()).text_event_fn(|_child, _ctx, _event| {
|
||||
let widget = make_parent_widget(Flex::row()).text_event_fn(|_child, _ctx, _, _event| {
|
||||
// We forget to call child.on_text_event();
|
||||
});
|
||||
|
||||
|
@ -101,7 +101,7 @@ fn check_register_invalid_child() {
|
|||
ignore = "This test doesn't work without debug assertions (i.e. in release mode). See https://github.com/linebender/xilem/issues/477"
|
||||
)]
|
||||
fn check_pointer_capture_outside_pointer_down() {
|
||||
let widget = ModularWidget::new(()).pointer_event_fn(|_, ctx, _event| {
|
||||
let widget = ModularWidget::new(()).pointer_event_fn(|_, ctx, _, _event| {
|
||||
ctx.capture_pointer();
|
||||
});
|
||||
|
||||
|
@ -120,7 +120,7 @@ fn check_pointer_capture_text_event() {
|
|||
let id = WidgetId::next();
|
||||
let widget = ModularWidget::new(())
|
||||
.accepts_focus(true)
|
||||
.text_event_fn(|_, ctx, _event| {
|
||||
.text_event_fn(|_, ctx, _, _event| {
|
||||
ctx.capture_pointer();
|
||||
})
|
||||
.with_id(id);
|
||||
|
@ -137,7 +137,7 @@ fn check_pointer_capture_text_event() {
|
|||
ignore = "This test doesn't work without debug assertions (i.e. in release mode). See https://github.com/linebender/xilem/issues/477"
|
||||
)]
|
||||
fn check_forget_to_recurse_layout() {
|
||||
let widget = make_parent_widget(Flex::row()).layout_fn(|_child, _ctx, _| {
|
||||
let widget = make_parent_widget(Flex::row()).layout_fn(|_child, _ctx, _, _| {
|
||||
// We forget to call ctx.run_layout();
|
||||
Size::ZERO
|
||||
});
|
||||
|
@ -152,7 +152,7 @@ fn check_forget_to_recurse_layout() {
|
|||
ignore = "This test doesn't work without debug assertions (i.e. in release mode). See https://github.com/linebender/xilem/issues/477"
|
||||
)]
|
||||
fn check_forget_to_call_place_child() {
|
||||
let widget = make_parent_widget(Flex::row()).layout_fn(|child, ctx, bc| {
|
||||
let widget = make_parent_widget(Flex::row()).layout_fn(|child, ctx, _, bc| {
|
||||
// We call ctx.run_layout(), but forget place_child
|
||||
ctx.run_layout(child, bc)
|
||||
});
|
||||
|
@ -168,11 +168,11 @@ fn check_forget_to_call_place_child() {
|
|||
#[test]
|
||||
fn allow_non_recurse_event_handled() {
|
||||
let widget = make_parent_widget(Flex::row())
|
||||
.pointer_event_fn(|_child, ctx, _event| {
|
||||
.pointer_event_fn(|_child, ctx, _, _event| {
|
||||
// Event handled, we don't need to recurse
|
||||
ctx.set_handled();
|
||||
})
|
||||
.text_event_fn(|_child, ctx, _event| {
|
||||
.text_event_fn(|_child, ctx, _, _event| {
|
||||
// Event handled, we don't need to recurse
|
||||
ctx.set_handled();
|
||||
});
|
||||
|
@ -185,12 +185,12 @@ fn allow_non_recurse_event_handled() {
|
|||
#[test]
|
||||
fn allow_non_recurse_cursor_oob() {
|
||||
let widget = make_parent_widget(Flex::row())
|
||||
.pointer_event_fn(|child, ctx, event| {
|
||||
.pointer_event_fn(|child, ctx, _, event| {
|
||||
if !matches!(event, PointerEvent::PointerMove(_)) {
|
||||
child.on_pointer_event(ctx, event);
|
||||
}
|
||||
})
|
||||
.layout_fn(|child, ctx, bc| {
|
||||
.layout_fn(|child, ctx, _, bc| {
|
||||
let _size = ctx.run_layout(child, bc);
|
||||
ctx.place_child(child, Point::ZERO);
|
||||
Size::new(6000.0, 6000.0)
|
||||
|
@ -207,7 +207,7 @@ fn allow_non_recurse_oob_paint() {
|
|||
.paint_fn(|_child, _ctx, _| {
|
||||
// We forget to call child.paint();
|
||||
})
|
||||
.layout_fn(|child, ctx, bc| {
|
||||
.layout_fn(|child, ctx, _, bc| {
|
||||
let _size = ctx.run_layout(child, bc);
|
||||
ctx.place_child(child, Point::new(500.0, 500.0));
|
||||
Size::new(600.0, 600.0)
|
||||
|
@ -242,7 +242,7 @@ fn check_forget_children_changed() {
|
|||
child.lifecycle(ctx, event);
|
||||
}
|
||||
})
|
||||
.layout_fn(|child, ctx, bc| {
|
||||
.layout_fn(|child, ctx, _, bc| {
|
||||
if let Some(child) = child {
|
||||
let size = ctx.run_layout(child, bc);
|
||||
ctx.place_child(child, Point::ZERO);
|
||||
|
@ -274,7 +274,7 @@ fn check_forget_children_changed() {
|
|||
#[should_panic]
|
||||
#[test]
|
||||
fn check_recurse_event_twice() {
|
||||
let widget = make_parent_widget(Flex::row()).pointer_event_fn(|child, ctx, event| {
|
||||
let widget = make_parent_widget(Flex::row()).pointer_event_fn(|child, ctx, _, event| {
|
||||
child.on_pointer_event(ctx, event);
|
||||
child.on_pointer_event(ctx, event);
|
||||
});
|
||||
|
@ -299,7 +299,7 @@ fn check_recurse_lifecycle_twice() {
|
|||
#[should_panic]
|
||||
#[test]
|
||||
fn check_recurse_layout_twice() {
|
||||
let widget = make_parent_widget(Flex::row()).layout_fn(|child, ctx, bc| {
|
||||
let widget = make_parent_widget(Flex::row()).layout_fn(|child, ctx, _, bc| {
|
||||
let size = ctx.run_layout(child, bc);
|
||||
let _ = ctx.run_layout(child, bc);
|
||||
ctx.place_child(child, Point::ZERO);
|
||||
|
@ -328,12 +328,12 @@ fn check_recurse_paint_twice() {
|
|||
#[test]
|
||||
fn check_layout_stashed() {
|
||||
let widget = make_parent_widget(Flex::row())
|
||||
.update_fn(|child, ctx, event| {
|
||||
.update_fn(|child, ctx, _, event| {
|
||||
if matches!(event, Update::WidgetAdded) {
|
||||
ctx.set_stashed(child, true);
|
||||
}
|
||||
})
|
||||
.layout_fn(|child, ctx, bc| {
|
||||
.layout_fn(|child, ctx, _, bc| {
|
||||
let size = ctx.run_layout(child, bc);
|
||||
ctx.place_child(child, Point::ZERO);
|
||||
size
|
||||
|
@ -351,7 +351,7 @@ fn check_layout_stashed() {
|
|||
#[test]
|
||||
fn check_paint_rect_includes_children() {
|
||||
use crate::widgets::Label;
|
||||
let widget = make_parent_widget(Label::new("Hello world")).layout_fn(|child, ctx, bc| {
|
||||
let widget = make_parent_widget(Label::new("Hello world")).layout_fn(|child, ctx, _, bc| {
|
||||
let _size = ctx.run_layout(child, bc);
|
||||
ctx.place_child(child, Point::ZERO);
|
||||
Size::ZERO
|
||||
|
|
|
@ -19,8 +19,9 @@ use winit::keyboard::{Key, NamedKey};
|
|||
|
||||
use crate::core::{
|
||||
AccessCtx, AccessEvent, BoxConstraints, BrushIndex, EventCtx, LayoutCtx, PaintCtx,
|
||||
PointerButton, PointerEvent, QueryCtx, RegisterCtx, StyleProperty, TextEvent, Update,
|
||||
UpdateCtx, Widget, WidgetId, WidgetMut, default_styles, render_text,
|
||||
PointerButton, PointerEvent, PropertiesMut, PropertiesRef, QueryCtx, RegisterCtx,
|
||||
StyleProperty, TextEvent, Update, UpdateCtx, Widget, WidgetId, WidgetMut, default_styles,
|
||||
render_text,
|
||||
};
|
||||
use crate::widgets::Padding;
|
||||
use crate::{palette, theme};
|
||||
|
@ -507,7 +508,12 @@ impl<const EDITABLE: bool> TextArea<EDITABLE> {
|
|||
|
||||
// --- MARK: IMPL WIDGET ---
|
||||
impl<const EDITABLE: bool> Widget for TextArea<EDITABLE> {
|
||||
fn on_pointer_event(&mut self, ctx: &mut EventCtx, event: &PointerEvent) {
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
event: &PointerEvent,
|
||||
) {
|
||||
if self.editor.is_composing() {
|
||||
return;
|
||||
}
|
||||
|
@ -567,7 +573,12 @@ impl<const EDITABLE: bool> Widget for TextArea<EDITABLE> {
|
|||
}
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, ctx: &mut EventCtx, event: &TextEvent) {
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
event: &TextEvent,
|
||||
) {
|
||||
match event {
|
||||
TextEvent::KeyboardKey(key_event, modifiers_state) => {
|
||||
if !key_event.state.is_pressed() || self.editor.is_composing() {
|
||||
|
@ -836,7 +847,12 @@ impl<const EDITABLE: bool> Widget for TextArea<EDITABLE> {
|
|||
EDITABLE
|
||||
}
|
||||
|
||||
fn on_access_event(&mut self, ctx: &mut EventCtx, event: &AccessEvent) {
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
event: &AccessEvent,
|
||||
) {
|
||||
if event.action == accesskit::Action::SetTextSelection {
|
||||
if self.editor.is_composing() {
|
||||
return;
|
||||
|
@ -859,7 +875,7 @@ impl<const EDITABLE: bool> Widget for TextArea<EDITABLE> {
|
|||
|
||||
fn register_children(&mut self, _ctx: &mut RegisterCtx) {}
|
||||
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, event: &Update) {
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, event: &Update) {
|
||||
match event {
|
||||
Update::FocusChanged(_) => {
|
||||
ctx.request_render();
|
||||
|
@ -872,7 +888,12 @@ impl<const EDITABLE: bool> Widget for TextArea<EDITABLE> {
|
|||
}
|
||||
}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
// Shrink constraints by padding inset
|
||||
let padding_size = Size::new(
|
||||
self.padding.leading + self.padding.trailing,
|
||||
|
@ -914,7 +935,7 @@ impl<const EDITABLE: bool> Widget for TextArea<EDITABLE> {
|
|||
bc.constrain(area_size)
|
||||
}
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) {
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, scene: &mut Scene) {
|
||||
let layout = if let Some(layout) = self.editor.try_layout() {
|
||||
layout
|
||||
} else {
|
||||
|
@ -968,7 +989,7 @@ impl<const EDITABLE: bool> Widget for TextArea<EDITABLE> {
|
|||
}
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, ctx: &mut AccessCtx, node: &mut Node) {
|
||||
fn accessibility(&mut self, ctx: &mut AccessCtx, _props: &PropertiesRef<'_>, node: &mut Node) {
|
||||
if !EDITABLE {
|
||||
node.set_read_only();
|
||||
}
|
||||
|
|
|
@ -10,8 +10,9 @@ use vello::Scene;
|
|||
use vello::kurbo::{Affine, Insets, Point, Rect, Size, Stroke};
|
||||
|
||||
use crate::core::{
|
||||
AccessCtx, AccessEvent, BoxConstraints, EventCtx, LayoutCtx, PaintCtx, PointerEvent, QueryCtx,
|
||||
RegisterCtx, TextEvent, Update, UpdateCtx, Widget, WidgetId, WidgetMut, WidgetPod,
|
||||
AccessCtx, AccessEvent, BoxConstraints, EventCtx, LayoutCtx, PaintCtx, PointerEvent,
|
||||
PropertiesMut, PropertiesRef, QueryCtx, RegisterCtx, TextEvent, Update, UpdateCtx, Widget,
|
||||
WidgetId, WidgetMut, WidgetPod,
|
||||
};
|
||||
use crate::peniko::Color;
|
||||
use crate::widgets::{Padding, TextArea};
|
||||
|
@ -110,19 +111,42 @@ impl Textbox {
|
|||
|
||||
// --- MARK: IMPL WIDGET ---
|
||||
impl Widget for Textbox {
|
||||
fn on_pointer_event(&mut self, _: &mut EventCtx, _: &PointerEvent) {}
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
_: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_: &PointerEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_access_event(&mut self, _ctx: &mut EventCtx, _event: &AccessEvent) {}
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &AccessEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn register_children(&mut self, ctx: &mut RegisterCtx) {
|
||||
ctx.register_child(&mut self.text);
|
||||
}
|
||||
|
||||
fn update(&mut self, _ctx: &mut UpdateCtx, _event: &Update) {}
|
||||
fn update(&mut self, _ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, _event: &Update) {}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
let margin = TEXTBOX_MARGIN;
|
||||
// Shrink constraints by padding inset
|
||||
let margin_size = Size::new(margin.leading + margin.trailing, margin.top + margin.bottom);
|
||||
|
@ -137,7 +161,7 @@ impl Widget for Textbox {
|
|||
size + margin_size
|
||||
}
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) {
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, scene: &mut Scene) {
|
||||
let size = ctx.size();
|
||||
let outline_rect = size.to_rect().inset(Insets::new(
|
||||
-TEXTBOX_MARGIN.leading,
|
||||
|
@ -158,7 +182,13 @@ impl Widget for Textbox {
|
|||
Role::GenericContainer
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, _node: &mut Node) {}
|
||||
fn accessibility(
|
||||
&mut self,
|
||||
_ctx: &mut AccessCtx,
|
||||
_props: &PropertiesRef<'_>,
|
||||
_node: &mut Node,
|
||||
) {
|
||||
}
|
||||
|
||||
fn children_ids(&self) -> SmallVec<[WidgetId; 16]> {
|
||||
smallvec![self.text.id()]
|
||||
|
|
|
@ -13,8 +13,8 @@ use vello::kurbo::{Point, Size};
|
|||
|
||||
use crate::core::{
|
||||
AccessCtx, AccessEvent, ArcStr, BoxConstraints, EventCtx, LayoutCtx, PaintCtx, PointerEvent,
|
||||
QueryCtx, RegisterCtx, StyleProperty, TextEvent, Update, UpdateCtx, Widget, WidgetId,
|
||||
WidgetMut, WidgetPod,
|
||||
PropertiesMut, PropertiesRef, QueryCtx, RegisterCtx, StyleProperty, TextEvent, Update,
|
||||
UpdateCtx, Widget, WidgetId, WidgetMut, WidgetPod,
|
||||
};
|
||||
use crate::parley::style::FontWeight;
|
||||
use crate::widgets::Label;
|
||||
|
@ -173,23 +173,46 @@ impl VariableLabel {
|
|||
|
||||
// --- MARK: IMPL WIDGET ---
|
||||
impl Widget for VariableLabel {
|
||||
fn on_pointer_event(&mut self, _ctx: &mut EventCtx, _event: &PointerEvent) {}
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &PointerEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn accepts_pointer_interaction(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_access_event(&mut self, _ctx: &mut EventCtx, _event: &AccessEvent) {}
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &AccessEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn update(&mut self, _ctx: &mut UpdateCtx, _event: &Update) {}
|
||||
fn update(&mut self, _ctx: &mut UpdateCtx, _props: &mut PropertiesMut<'_>, _event: &Update) {}
|
||||
|
||||
fn register_children(&mut self, ctx: &mut RegisterCtx) {
|
||||
ctx.register_child(&mut self.label);
|
||||
}
|
||||
|
||||
fn on_anim_frame(&mut self, ctx: &mut UpdateCtx, interval: u64) {
|
||||
fn on_anim_frame(
|
||||
&mut self,
|
||||
ctx: &mut UpdateCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
interval: u64,
|
||||
) {
|
||||
let millis = (interval as f64 / 1_000_000.) as f32;
|
||||
let result = self.weight.advance(millis);
|
||||
let new_weight = self.weight.value;
|
||||
|
@ -212,19 +235,30 @@ impl Widget for VariableLabel {
|
|||
}
|
||||
}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
let size = ctx.run_layout(&mut self.label, bc);
|
||||
ctx.place_child(&mut self.label, Point::ORIGIN);
|
||||
size
|
||||
}
|
||||
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _scene: &mut Scene) {}
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, _scene: &mut Scene) {}
|
||||
|
||||
fn accessibility_role(&self) -> Role {
|
||||
Role::GenericContainer
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, _node: &mut Node) {}
|
||||
fn accessibility(
|
||||
&mut self,
|
||||
_ctx: &mut AccessCtx,
|
||||
_props: &PropertiesRef<'_>,
|
||||
_node: &mut Node,
|
||||
) {
|
||||
}
|
||||
|
||||
fn children_ids(&self) -> SmallVec<[WidgetId; 16]> {
|
||||
smallvec![self.label.id()]
|
||||
|
|
|
@ -8,8 +8,8 @@ use smallvec::SmallVec;
|
|||
use tracing::trace_span;
|
||||
|
||||
use crate::core::{
|
||||
AccessCtx, BoxConstraints, LayoutCtx, PaintCtx, QueryCtx, RegisterCtx, Widget, WidgetId,
|
||||
WidgetMut, WidgetPod,
|
||||
AccessCtx, BoxConstraints, LayoutCtx, PaintCtx, PropertiesMut, PropertiesRef, QueryCtx,
|
||||
RegisterCtx, Widget, WidgetId, WidgetMut, WidgetPod,
|
||||
};
|
||||
use crate::kurbo::{Point, Size};
|
||||
use crate::vello::Scene;
|
||||
|
@ -298,7 +298,12 @@ impl ZStack {
|
|||
|
||||
// --- MARK: IMPL WIDGET---
|
||||
impl Widget for ZStack {
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
// First pass: calculate the smallest bounds needed to layout the children.
|
||||
let mut max_size = bc.min();
|
||||
let loosened_bc = bc.loosen();
|
||||
|
@ -341,7 +346,7 @@ impl Widget for ZStack {
|
|||
max_size
|
||||
}
|
||||
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _scene: &mut Scene) {}
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, _scene: &mut Scene) {}
|
||||
|
||||
fn register_children(&mut self, ctx: &mut RegisterCtx) {
|
||||
for child in self.children.iter_mut().map(|x| &mut x.widget) {
|
||||
|
@ -361,7 +366,13 @@ impl Widget for ZStack {
|
|||
Role::GenericContainer
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, _node: &mut Node) {}
|
||||
fn accessibility(
|
||||
&mut self,
|
||||
_ctx: &mut AccessCtx,
|
||||
_props: &PropertiesRef<'_>,
|
||||
_node: &mut Node,
|
||||
) {
|
||||
}
|
||||
|
||||
fn make_trace_span(&self, ctx: &QueryCtx<'_>) -> tracing::Span {
|
||||
trace_span!("ZStack", id = ctx.widget_id().trace())
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
use accesskit::{Node, Role};
|
||||
use masonry::core::{
|
||||
AccessCtx, AccessEvent, BoxConstraints, EventCtx, FromDynWidget, LayoutCtx, PaintCtx,
|
||||
PointerEvent, QueryCtx, RegisterCtx, TextEvent, Widget, WidgetId, WidgetMut, WidgetPod,
|
||||
PointerEvent, PropertiesMut, PropertiesRef, QueryCtx, RegisterCtx, TextEvent, Widget, WidgetId,
|
||||
WidgetMut, WidgetPod,
|
||||
};
|
||||
use masonry::kurbo::{Point, Size};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
@ -68,27 +69,56 @@ impl DynWidget {
|
|||
|
||||
/// Forward all events to the child widget.
|
||||
impl Widget for DynWidget {
|
||||
fn on_pointer_event(&mut self, _ctx: &mut EventCtx, _event: &PointerEvent) {}
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_access_event(&mut self, _ctx: &mut EventCtx, _event: &AccessEvent) {}
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &PointerEvent,
|
||||
) {
|
||||
}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &AccessEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn register_children(&mut self, ctx: &mut RegisterCtx) {
|
||||
ctx.register_child(&mut self.inner);
|
||||
}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
let size = ctx.run_layout(&mut self.inner, bc);
|
||||
ctx.place_child(&mut self.inner, Point::ORIGIN);
|
||||
size
|
||||
}
|
||||
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _scene: &mut Scene) {}
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, _scene: &mut Scene) {}
|
||||
|
||||
fn accessibility_role(&self) -> Role {
|
||||
Role::GenericContainer
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, _node: &mut Node) {}
|
||||
fn accessibility(
|
||||
&mut self,
|
||||
_ctx: &mut AccessCtx,
|
||||
_props: &PropertiesRef<'_>,
|
||||
_node: &mut Node,
|
||||
) {
|
||||
}
|
||||
|
||||
fn children_ids(&self) -> SmallVec<[WidgetId; 16]> {
|
||||
smallvec![self.inner.id()]
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
use accesskit::{Node, Role};
|
||||
use masonry::core::{
|
||||
AccessCtx, AccessEvent, BoxConstraints, EventCtx, FromDynWidget, LayoutCtx, PaintCtx,
|
||||
PointerEvent, RegisterCtx, TextEvent, Widget, WidgetId, WidgetPod,
|
||||
PointerEvent, PropertiesMut, PropertiesRef, RegisterCtx, TextEvent, Widget, WidgetId,
|
||||
WidgetPod,
|
||||
};
|
||||
use masonry::kurbo::{Point, Size};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
@ -182,9 +183,27 @@ impl<
|
|||
I: Widget + FromDynWidget + ?Sized,
|
||||
> Widget for OneOfWidget<A, B, C, D, E, F, G, H, I>
|
||||
{
|
||||
fn on_pointer_event(&mut self, _ctx: &mut EventCtx, _event: &PointerEvent) {}
|
||||
fn on_text_event(&mut self, _ctx: &mut EventCtx, _event: &TextEvent) {}
|
||||
fn on_access_event(&mut self, _ctx: &mut EventCtx, _event: &AccessEvent) {}
|
||||
fn on_pointer_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &PointerEvent,
|
||||
) {
|
||||
}
|
||||
fn on_text_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &TextEvent,
|
||||
) {
|
||||
}
|
||||
fn on_access_event(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
_event: &AccessEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn register_children(&mut self, ctx: &mut RegisterCtx) {
|
||||
match self {
|
||||
|
@ -200,7 +219,12 @@ impl<
|
|||
}
|
||||
}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
match self {
|
||||
Self::A(w) => {
|
||||
let size = ctx.run_layout(w, bc);
|
||||
|
@ -250,13 +274,19 @@ impl<
|
|||
}
|
||||
}
|
||||
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _scene: &mut Scene) {}
|
||||
fn paint(&mut self, _ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, _scene: &mut Scene) {}
|
||||
|
||||
fn accessibility_role(&self) -> Role {
|
||||
Role::GenericContainer
|
||||
}
|
||||
|
||||
fn accessibility(&mut self, _ctx: &mut AccessCtx, _node: &mut Node) {}
|
||||
fn accessibility(
|
||||
&mut self,
|
||||
_ctx: &mut AccessCtx,
|
||||
_props: &PropertiesRef<'_>,
|
||||
_node: &mut Node,
|
||||
) {
|
||||
}
|
||||
|
||||
fn children_ids(&self) -> SmallVec<[WidgetId; 16]> {
|
||||
match self {
|
||||
|
|
Loading…
Reference in New Issue