Widget docs + refactoring

- MakeWidgetWithId::make_with_id -> MakeWidgetWithTag::make_With_tag
- ManagedWidget -> MountedWidget
- *_refresh -> *_redraw, standardized on terminology
- get_tracked -> get_tracking_redraw
This commit is contained in:
Jonathan Johnson 2023-12-17 07:38:31 -08:00
parent 01e04a4eb9
commit 02d6b343f1
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
25 changed files with 376 additions and 199 deletions

22
Cargo.lock generated
View file

@ -1181,13 +1181,13 @@ dependencies = [
[[package]] [[package]]
name = "lyon_tessellation" name = "lyon_tessellation"
version = "1.0.12" version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f5bcf02928361d18e6edb8ad3bc5b93cba8aa57e2508deb072c2d2ade8bbd0d" checksum = "8c7c67b5bc8123b352b2e7e742b47d1f236a13fe77619433be9568fbd888e9c0"
dependencies = [ dependencies = [
"float_next_after", "float_next_after",
"lyon_path", "lyon_path",
"thiserror", "num-traits",
] ]
[[package]] [[package]]
@ -1271,9 +1271,9 @@ dependencies = [
[[package]] [[package]]
name = "memmap2" name = "memmap2"
version = "0.9.0" version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "deaba38d7abf1d4cca21cc89e932e542ba2b9258664d2a9ef0e61512039c9375" checksum = "39a69c7c189ae418f83003da62820aca28d15a07725ce51fb924999335d622ff"
dependencies = [ dependencies = [
"libc", "libc",
] ]
@ -2064,7 +2064,7 @@ dependencies = [
"cursor-icon", "cursor-icon",
"libc", "libc",
"log", "log",
"memmap2 0.9.0", "memmap2 0.9.2",
"rustix", "rustix",
"thiserror", "thiserror",
"wayland-backend", "wayland-backend",
@ -2164,18 +2164,18 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.50" version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.50" version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2982,7 +2982,7 @@ dependencies = [
"js-sys", "js-sys",
"libc", "libc",
"log", "log",
"memmap2 0.9.0", "memmap2 0.9.2",
"ndk", "ndk",
"ndk-sys", "ndk-sys",
"objc2", "objc2",

View file

@ -2,7 +2,7 @@
//! traits or using the [`Custom`] widget with callbacks. //! traits or using the [`Custom`] widget with callbacks.
use gooey::value::Dynamic; use gooey::value::Dynamic;
use gooey::widget::{MakeWidget, MakeWidgetWithId, Widget, WidgetInstance, WidgetTag, HANDLED}; use gooey::widget::{MakeWidget, MakeWidgetWithTag, Widget, WidgetInstance, WidgetTag, HANDLED};
use gooey::widgets::Custom; use gooey::widgets::Custom;
use gooey::Run; use gooey::Run;
use kludgine::figures::units::{Lp, UPx}; use kludgine::figures::units::{Lp, UPx};
@ -29,7 +29,7 @@ fn main() -> gooey::Result {
/// ///
/// This approach was added to make it easy to create one-off widgets in a /// This approach was added to make it easy to create one-off widgets in a
/// hierarchy to handle events or other purpose-built functions. /// hierarchy to handle events or other purpose-built functions.
fn callback_widget() -> impl MakeWidgetWithId { fn callback_widget() -> impl MakeWidgetWithTag {
// This implementation and the impl `Widget` implementation both use the // This implementation and the impl `Widget` implementation both use the
// same Dynamic value setup. // same Dynamic value setup.
let toggle = Toggle::default(); let toggle = Toggle::default();
@ -44,7 +44,7 @@ fn callback_widget() -> impl MakeWidgetWithId {
.height(Lp::inches(1)) .height(Lp::inches(1))
} }
/// A second approach is to implement [`MakeWidgetWithId`] for a type. This /// A second approach is to implement [`MakeWidgetWithTag`] for a type. This
/// allows any type to be used when composing your UI that know how to create a /// allows any type to be used when composing your UI that know how to create a
/// widget. /// widget.
/// ///
@ -52,7 +52,7 @@ fn callback_widget() -> impl MakeWidgetWithId {
/// widgets) in a reusable fashion. /// widgets) in a reusable fashion.
/// ///
/// [`MakeWidget`] is implemented automatically for all types that implement /// [`MakeWidget`] is implemented automatically for all types that implement
/// [`MakeWidgetWithId`]. The difference between the traits is purely whether /// [`MakeWidgetWithTag`]. The difference between the traits is purely whether
/// allowing a caller instantiating your custom widget to provide an id for the /// allowing a caller instantiating your custom widget to provide an id for the
/// widget. These IDs are used when configuring custom tab orders, so if your /// widget. These IDs are used when configuring custom tab orders, so if your
/// widget or any of its children aren't focusable, implementing [`MakeWidget`] /// widget or any of its children aren't focusable, implementing [`MakeWidget`]
@ -60,10 +60,10 @@ fn callback_widget() -> impl MakeWidgetWithId {
#[derive(Default)] #[derive(Default)]
struct ToggleMakeWidget(Toggle); struct ToggleMakeWidget(Toggle);
impl MakeWidgetWithId for ToggleMakeWidget { impl MakeWidgetWithTag for ToggleMakeWidget {
fn make_with_id(self, id: WidgetTag) -> WidgetInstance { fn make_with_tag(self, id: WidgetTag) -> WidgetInstance {
// In a real code base, the contents of callback_widget() would go here // In a real code base, the contents of callback_widget() would go here
callback_widget().make_with_id(id) callback_widget().make_with_tag(id)
} }
} }
@ -71,7 +71,7 @@ impl MakeWidgetWithId for ToggleMakeWidget {
/// ///
/// This is the lowest-level way to implement a Widget, but it also provides the /// This is the lowest-level way to implement a Widget, but it also provides the
/// most power and flexibility. /// most power and flexibility.
fn impl_widget() -> impl MakeWidgetWithId { fn impl_widget() -> impl MakeWidgetWithTag {
Toggle::default() Toggle::default()
} }
@ -91,7 +91,7 @@ impl Default for Toggle {
impl Widget for Toggle { impl Widget for Toggle {
fn redraw(&mut self, context: &mut gooey::context::GraphicsContext<'_, '_, '_, '_, '_>) { fn redraw(&mut self, context: &mut gooey::context::GraphicsContext<'_, '_, '_, '_, '_>) {
context.fill(self.color.get_tracking_refresh(context)); context.fill(self.color.get_tracking_redraw(context));
} }
fn layout( fn layout(

View file

@ -1,7 +1,7 @@
use std::process::exit; use std::process::exit;
use gooey::value::{Dynamic, MapEach}; use gooey::value::{Dynamic, MapEach};
use gooey::widget::{MakeWidget, MakeWidgetWithId, WidgetTag}; use gooey::widget::{MakeWidget, MakeWidgetWithTag, WidgetTag};
use gooey::widgets::grid::{Grid, GridDimension, GridWidgets}; use gooey::widgets::grid::{Grid, GridDimension, GridWidgets};
use gooey::widgets::input::{InputValue, MaskedString}; use gooey::widgets::input::{InputValue, MaskedString};
use gooey::widgets::Expand; use gooey::widgets::Expand;
@ -24,7 +24,7 @@ fn main() -> gooey::Result {
let username_row = ( let username_row = (
"Username", "Username",
username.clone().into_input().make_with_id(username_tag), username.clone().into_input().make_with_tag(username_tag),
); );
let password_row = ( let password_row = (
@ -38,7 +38,7 @@ fn main() -> gooey::Result {
eprintln!("Login cancelled"); eprintln!("Login cancelled");
exit(0) exit(0)
}) })
.make_with_id(cancel_tag) .make_with_tag(cancel_tag)
.into_escape() .into_escape()
.with_next_focus(username_id) .with_next_focus(username_id)
.and(Expand::empty()) .and(Expand::empty())
@ -49,7 +49,7 @@ fn main() -> gooey::Result {
println!("Welcome, {}", username.get()); println!("Welcome, {}", username.get());
exit(0); exit(0);
}) })
.make_with_id(login_tag) .make_with_tag(login_tag)
.with_enabled(valid) .with_enabled(valid)
.into_default() .into_default()
.with_next_focus(cancel_id), .with_next_focus(cancel_id),

View file

@ -1,6 +1,6 @@
use std::panic::UnwindSafe; use std::panic::UnwindSafe;
use gooey::widget::{MakeWidget, MakeWidgetWithId, WidgetTag}; use gooey::widget::{MakeWidget, MakeWidgetWithTag, WidgetTag};
use gooey::widgets::container::ContainerShadow; use gooey::widgets::container::ContainerShadow;
use gooey::widgets::layers::{OverlayBuilder, OverlayLayer}; use gooey::widgets::layers::{OverlayBuilder, OverlayLayer};
use gooey::Run; use gooey::Run;
@ -48,7 +48,7 @@ fn test_widget(overlay: &OverlayLayer, is_root: bool) -> impl MakeWidget {
); );
} }
buttons.pad().make_with_id(my_tag) buttons.pad().make_with_tag(my_tag)
} }
fn show_overlay_button( fn show_overlay_button(

View file

@ -25,7 +25,7 @@ use crate::styles::{ComponentDefinition, Styles, Theme, ThemePair};
use crate::utils::IgnorePoison; use crate::utils::IgnorePoison;
use crate::value::{IntoValue, Value}; use crate::value::{IntoValue, Value};
use crate::widget::{ use crate::widget::{
EventHandling, ManagedWidget, RootBehavior, WidgetId, WidgetInstance, WidgetRef, EventHandling, MountedWidget, RootBehavior, WidgetId, WidgetInstance, WidgetRef,
}; };
use crate::window::{CursorState, RunningWindow, ThemeMode}; use crate::window::{CursorState, RunningWindow, ThemeMode};
use crate::ConstraintLimit; use crate::ConstraintLimit;
@ -350,7 +350,7 @@ impl<'context, 'window> EventContext<'context, 'window> {
} }
} }
fn next_focus_after(&mut self, mut focus: ManagedWidget, advance: bool) -> Option<WidgetId> { fn next_focus_after(&mut self, mut focus: MountedWidget, advance: bool) -> Option<WidgetId> {
// First, look within the current focus for any focusable children. // First, look within the current focus for any focusable children.
let stop_at = focus.id(); let stop_at = focus.id();
if let Some(focus) = self.next_focus_within(&focus, None, stop_at, advance) { if let Some(focus) = self.next_focus_within(&focus, None, stop_at, advance) {
@ -375,7 +375,7 @@ impl<'context, 'window> EventContext<'context, 'window> {
fn next_focus_sibling( fn next_focus_sibling(
&mut self, &mut self,
focus: &ManagedWidget, focus: &MountedWidget,
stop_at: WidgetId, stop_at: WidgetId,
advance: bool, advance: bool,
) -> Option<WidgetId> { ) -> Option<WidgetId> {
@ -387,7 +387,7 @@ impl<'context, 'window> EventContext<'context, 'window> {
/// that returns true from `accept_focus`. /// that returns true from `accept_focus`.
fn next_focus_within( fn next_focus_within(
&mut self, &mut self,
focus: &ManagedWidget, focus: &MountedWidget,
start_at: Option<WidgetId>, start_at: Option<WidgetId>,
stop_at: WidgetId, stop_at: WidgetId,
advance: bool, advance: bool,
@ -782,7 +782,7 @@ impl<'context, 'window, 'clip, 'gfx, 'pass> LayoutContext<'context, 'window, 'cl
/// Sets the layout for `child` to `layout`. /// Sets the layout for `child` to `layout`.
/// ///
/// `layout` is relative to the current widget's controls. /// `layout` is relative to the current widget's controls.
pub fn set_child_layout(&mut self, child: &ManagedWidget, layout: Rect<Px>) { pub fn set_child_layout(&mut self, child: &MountedWidget, layout: Rect<Px>) {
// TODO verify that `child` belongs to the current node. // TODO verify that `child` belongs to the current node.
if self.persist_layout { if self.persist_layout {
child.set_layout(layout); child.set_layout(layout);
@ -824,7 +824,7 @@ pub trait AsEventContext<'window> {
/// Pushes a new child widget into the widget hierarchy beneathq the /// Pushes a new child widget into the widget hierarchy beneathq the
/// context's widget. /// context's widget.
#[must_use] #[must_use]
fn push_child(&mut self, child: WidgetInstance) -> ManagedWidget { fn push_child(&mut self, child: WidgetInstance) -> MountedWidget {
let mut context = self.as_event_context(); let mut context = self.as_event_context();
let pushed_widget = context let pushed_widget = context
.current_node .current_node
@ -838,7 +838,7 @@ pub trait AsEventContext<'window> {
} }
/// Removes a widget from the hierarchy. /// Removes a widget from the hierarchy.
fn remove_child(&mut self, child: &ManagedWidget) { fn remove_child(&mut self, child: &MountedWidget) {
let mut context = self.as_event_context(); let mut context = self.as_event_context();
child child
.lock() .lock()
@ -868,7 +868,7 @@ impl<'window> AsEventContext<'window> for GraphicsContext<'_, 'window, '_, '_, '
/// This type provides access to the widget hierarchy from the perspective of a /// This type provides access to the widget hierarchy from the perspective of a
/// specific widget. /// specific widget.
pub struct WidgetContext<'context, 'window> { pub struct WidgetContext<'context, 'window> {
current_node: ManagedWidget, current_node: MountedWidget,
redraw_status: &'context InvalidationStatus, redraw_status: &'context InvalidationStatus,
window: &'context mut RunningWindow<'window>, window: &'context mut RunningWindow<'window>,
theme: Cow<'context, ThemePair>, theme: Cow<'context, ThemePair>,
@ -880,7 +880,7 @@ pub struct WidgetContext<'context, 'window> {
impl<'context, 'window> WidgetContext<'context, 'window> { impl<'context, 'window> WidgetContext<'context, 'window> {
pub(crate) fn new( pub(crate) fn new(
current_node: ManagedWidget, current_node: MountedWidget,
redraw_status: &'context InvalidationStatus, redraw_status: &'context InvalidationStatus,
theme: &'context ThemePair, theme: &'context ThemePair,
window: &'context mut RunningWindow<'window>, window: &'context mut RunningWindow<'window>,
@ -942,12 +942,12 @@ impl<'context, 'window> WidgetContext<'context, 'window> {
widget.manage(self).map(|current_node| { widget.manage(self).map(|current_node| {
let (effective_styles, theme, theme_mode) = current_node.overidden_theme(); let (effective_styles, theme, theme_mode) = current_node.overidden_theme();
let theme = if let Some(theme) = theme { let theme = if let Some(theme) = theme {
Cow::Owned(theme.get_tracked(self)) Cow::Owned(theme.get_tracking_redraw(self))
} else { } else {
Cow::Borrowed(self.theme.as_ref()) Cow::Borrowed(self.theme.as_ref())
}; };
let theme_mode = if let Some(mode) = theme_mode { let theme_mode = if let Some(mode) = theme_mode {
mode.get_tracked(self) mode.get_tracking_redraw(self)
} else { } else {
self.cache.theme_mode self.cache.theme_mode
}; };
@ -981,7 +981,7 @@ impl<'context, 'window> WidgetContext<'context, 'window> {
self.cache.enabled self.cache.enabled
} }
pub(crate) fn parent(&self) -> Option<ManagedWidget> { pub(crate) fn parent(&self) -> Option<MountedWidget> {
self.current_node.parent() self.current_node.parent()
} }
@ -1096,7 +1096,7 @@ impl<'context, 'window> WidgetContext<'context, 'window> {
#[must_use] #[must_use]
pub fn focused(&self, check_window: bool) -> bool { pub fn focused(&self, check_window: bool) -> bool {
self.pending_state.focus == Some(self.current_node.id()) self.pending_state.focus == Some(self.current_node.id())
&& (!check_window || self.window.focused().get_tracking_refresh(self)) && (!check_window || self.window.focused().get_tracking_redraw(self))
} }
/// Returns true if this widget is the target to activate when the user /// Returns true if this widget is the target to activate when the user
@ -1123,7 +1123,7 @@ impl<'context, 'window> WidgetContext<'context, 'window> {
/// Returns the widget this context is for. /// Returns the widget this context is for.
#[must_use] #[must_use]
pub const fn widget(&self) -> &ManagedWidget { pub const fn widget(&self) -> &MountedWidget {
&self.current_node &self.current_node
} }
@ -1315,18 +1315,18 @@ impl InvalidationStatus {
} }
} }
/// A type chat can convert to a [`ManagedWidget`] through a [`WidgetContext`]. /// A type chat can convert to a [`MountedWidget`] through a [`WidgetContext`].
pub trait ManageWidget { pub trait ManageWidget {
/// The managed type, which can be `Option<ManagedWidget>` or /// The managed type, which can be `Option<MountedWidget>` or
/// `ManagedWidget`. /// `MountedWidget`.
type Managed: MapManagedWidget<ManagedWidget>; type Managed: MapManagedWidget<MountedWidget>;
/// Resolve `self` into a [`ManagedWidget`]. /// Resolve `self` into a [`MountedWidget`].
fn manage(&self, context: &WidgetContext<'_, '_>) -> Self::Managed; fn manage(&self, context: &WidgetContext<'_, '_>) -> Self::Managed;
} }
impl ManageWidget for WidgetId { impl ManageWidget for WidgetId {
type Managed = Option<ManagedWidget>; type Managed = Option<MountedWidget>;
fn manage(&self, context: &WidgetContext<'_, '_>) -> Self::Managed { fn manage(&self, context: &WidgetContext<'_, '_>) -> Self::Managed {
context.current_node.tree.widget(*self) context.current_node.tree.widget(*self)
@ -1334,7 +1334,7 @@ impl ManageWidget for WidgetId {
} }
impl ManageWidget for WidgetInstance { impl ManageWidget for WidgetInstance {
type Managed = Option<ManagedWidget>; type Managed = Option<MountedWidget>;
fn manage(&self, context: &WidgetContext<'_, '_>) -> Self::Managed { fn manage(&self, context: &WidgetContext<'_, '_>) -> Self::Managed {
context.current_node.tree.widget(self.id()) context.current_node.tree.widget(self.id())
@ -1342,7 +1342,7 @@ impl ManageWidget for WidgetInstance {
} }
impl ManageWidget for WidgetRef { impl ManageWidget for WidgetRef {
type Managed = Option<ManagedWidget>; type Managed = Option<MountedWidget>;
fn manage(&self, context: &WidgetContext<'_, '_>) -> Self::Managed { fn manage(&self, context: &WidgetContext<'_, '_>) -> Self::Managed {
match self { match self {
@ -1352,7 +1352,7 @@ impl ManageWidget for WidgetRef {
} }
} }
impl ManageWidget for ManagedWidget { impl ManageWidget for MountedWidget {
type Managed = Self; type Managed = Self;
fn manage(&self, _context: &WidgetContext<'_, '_>) -> Self::Managed { fn manage(&self, _context: &WidgetContext<'_, '_>) -> Self::Managed {
@ -1360,27 +1360,27 @@ impl ManageWidget for ManagedWidget {
} }
} }
/// A type that can produce another type when provided a [`ManagedWidget`]. /// A type that can produce another type when provided a [`MountedWidget`].
pub trait MapManagedWidget<T> { pub trait MapManagedWidget<T> {
/// The result of the mapping operation. /// The result of the mapping operation.
type Result; type Result;
/// Call `map` with a [`ManagedWidget`]. /// Call `map` with a [`MountedWidget`].
fn map(self, map: impl FnOnce(ManagedWidget) -> T) -> Self::Result; fn map(self, map: impl FnOnce(MountedWidget) -> T) -> Self::Result;
} }
impl<T> MapManagedWidget<T> for Option<ManagedWidget> { impl<T> MapManagedWidget<T> for Option<MountedWidget> {
type Result = Option<T>; type Result = Option<T>;
fn map(self, map: impl FnOnce(ManagedWidget) -> T) -> Self::Result { fn map(self, map: impl FnOnce(MountedWidget) -> T) -> Self::Result {
self.map(map) self.map(map)
} }
} }
impl<T> MapManagedWidget<T> for ManagedWidget { impl<T> MapManagedWidget<T> for MountedWidget {
type Result = T; type Result = T;
fn map(self, map: impl FnOnce(ManagedWidget) -> T) -> Self::Result { fn map(self, map: impl FnOnce(MountedWidget) -> T) -> Self::Result {
map(self) map(self)
} }
} }

View file

@ -125,24 +125,6 @@ pub trait Run: Sized {
fn run(self) -> crate::Result; fn run(self) -> crate::Result;
} }
/// Creates a [`Children`](crate::widget::Children) instance with the given list
/// of widgets.
#[macro_export]
#[deprecated = "use MakeWidget.and()/Children.and() to chain widgets without a macro"]
macro_rules! children {
() => {
$crate::widget::Children::new()
};
($($widget:expr),+) => {{
let mut widgets = $crate::widget::Children::with_capacity($crate::count!($($widget),+ ;));
$(widgets.push($widget);)+
widgets
}};
($($widget:expr),+ ,) => {{
$crate::children!($($widget),+)
}};
}
/// Counts the number of expressions passed to it. /// Counts the number of expressions passed to it.
/// ///
/// This is used inside of Gooey macros to preallocate collections. /// This is used inside of Gooey macros to preallocate collections.

View file

@ -10,7 +10,7 @@ use crate::context::sealed::WindowHandle;
use crate::styles::{Styles, ThemePair, VisualOrder}; use crate::styles::{Styles, ThemePair, VisualOrder};
use crate::utils::IgnorePoison; use crate::utils::IgnorePoison;
use crate::value::Value; use crate::value::Value;
use crate::widget::{ManagedWidget, WidgetId, WidgetInstance}; use crate::widget::{MountedWidget, WidgetId, WidgetInstance};
use crate::window::ThemeMode; use crate::window::ThemeMode;
use crate::ConstraintLimit; use crate::ConstraintLimit;
@ -23,8 +23,8 @@ impl Tree {
pub fn push_boxed( pub fn push_boxed(
&self, &self,
widget: WidgetInstance, widget: WidgetInstance,
parent: Option<&ManagedWidget>, parent: Option<&MountedWidget>,
) -> ManagedWidget { ) -> MountedWidget {
let mut data = self.data.lock().ignore_poison(); let mut data = self.data.lock().ignore_poison();
let id = widget.id(); let id = widget.id();
let (effective_styles, parent_id) = if let Some(parent) = parent { let (effective_styles, parent_id) = if let Some(parent) = parent {
@ -60,14 +60,14 @@ impl Tree {
if let Some(next_focus) = widget.next_focus() { if let Some(next_focus) = widget.next_focus() {
data.previous_focuses.insert(next_focus, id); data.previous_focuses.insert(next_focus, id);
} }
ManagedWidget { MountedWidget {
node_id, node_id,
widget, widget,
tree: self.clone(), tree: self.clone(),
} }
} }
pub fn remove_child(&self, child: &ManagedWidget, parent: &ManagedWidget) { pub fn remove_child(&self, child: &MountedWidget, parent: &MountedWidget) {
let mut data = self.data.lock().ignore_poison(); let mut data = self.data.lock().ignore_poison();
data.remove_child(child.node_id, parent.node_id); data.remove_child(child.node_id, parent.node_id);
@ -163,11 +163,11 @@ impl Tree {
&self, &self,
parent: LotId, parent: LotId,
order: VisualOrder, order: VisualOrder,
) -> Vec<ManagedWidget> { ) -> Vec<MountedWidget> {
let data = self.data.lock().ignore_poison(); let data = self.data.lock().ignore_poison();
let node = &data.nodes[parent]; let node = &data.nodes[parent];
let mut unordered = node.children.clone(); let mut unordered = node.children.clone();
let mut ordered = Vec::<ManagedWidget>::with_capacity(unordered.len()); let mut ordered = Vec::<MountedWidget>::with_capacity(unordered.len());
loop { loop {
// Identify the next "row" of widgets by finding the top of a widget that is the closest to the origin of // Identify the next "row" of widgets by finding the top of a widget that is the closest to the origin of
let mut min_vertical = order.vertical.max_px(); let mut min_vertical = order.vertical.max_px();
@ -225,13 +225,13 @@ impl Tree {
data.nodes[id].effective_styles.clone() data.nodes[id].effective_styles.clone()
} }
pub(crate) fn hover(&self, new_hover: Option<&ManagedWidget>) -> HoverResults { pub(crate) fn hover(&self, new_hover: Option<&MountedWidget>) -> HoverResults {
let mut data = self.data.lock().ignore_poison(); let mut data = self.data.lock().ignore_poison();
let hovered = new_hover let hovered = new_hover
.map(|new_hover| data.widget_hierarchy(new_hover.node_id, self)) .map(|new_hover| data.widget_hierarchy(new_hover.node_id, self))
.unwrap_or_default(); .unwrap_or_default();
let unhovered = let unhovered =
match data.update_tracked_widget(new_hover.map(ManagedWidget::id), self, |data| { match data.update_tracked_widget(new_hover.map(MountedWidget::id), self, |data| {
&mut data.hover &mut data.hover
}) { }) {
Ok(Some(old_hover)) => { Ok(Some(old_hover)) => {
@ -250,12 +250,12 @@ impl Tree {
HoverResults { unhovered, hovered } HoverResults { unhovered, hovered }
} }
pub fn focus(&self, new_focus: Option<WidgetId>) -> Result<Option<ManagedWidget>, ()> { pub fn focus(&self, new_focus: Option<WidgetId>) -> Result<Option<MountedWidget>, ()> {
let mut data = self.data.lock().ignore_poison(); let mut data = self.data.lock().ignore_poison();
data.update_tracked_widget(new_focus, self, |data| &mut data.focus) data.update_tracked_widget(new_focus, self, |data| &mut data.focus)
} }
pub fn previous_focus(&self, focus: WidgetId) -> Option<ManagedWidget> { pub fn previous_focus(&self, focus: WidgetId) -> Option<MountedWidget> {
let data = self.data.lock().ignore_poison(); let data = self.data.lock().ignore_poison();
let previous = *data.previous_focuses.get(&focus)?; let previous = *data.previous_focuses.get(&focus)?;
data.widget_from_id(previous, self) data.widget_from_id(previous, self)
@ -263,20 +263,20 @@ impl Tree {
pub fn activate( pub fn activate(
&self, &self,
new_active: Option<&ManagedWidget>, new_active: Option<&MountedWidget>,
) -> Result<Option<ManagedWidget>, ()> { ) -> Result<Option<MountedWidget>, ()> {
let mut data = self.data.lock().ignore_poison(); let mut data = self.data.lock().ignore_poison();
data.update_tracked_widget(new_active.map(ManagedWidget::id), self, |data| { data.update_tracked_widget(new_active.map(MountedWidget::id), self, |data| {
&mut data.active &mut data.active
}) })
} }
pub fn widget(&self, id: WidgetId) -> Option<ManagedWidget> { pub fn widget(&self, id: WidgetId) -> Option<MountedWidget> {
let data = self.data.lock().ignore_poison(); let data = self.data.lock().ignore_poison();
data.widget_from_id(id, self) data.widget_from_id(id, self)
} }
pub(crate) fn widget_from_node(&self, id: LotId) -> Option<ManagedWidget> { pub(crate) fn widget_from_node(&self, id: LotId) -> Option<MountedWidget> {
let data = self.data.lock().ignore_poison(); let data = self.data.lock().ignore_poison();
data.widget_from_node(id, self) data.widget_from_node(id, self)
} }
@ -333,7 +333,7 @@ impl Tree {
self.data.lock().ignore_poison().focus self.data.lock().ignore_poison().focus
} }
pub(crate) fn widgets_under_point(&self, point: Point<Px>) -> Vec<ManagedWidget> { pub(crate) fn widgets_under_point(&self, point: Point<Px>) -> Vec<MountedWidget> {
let data = self.data.lock().ignore_poison(); let data = self.data.lock().ignore_poison();
data.render_info.widgets_under_point(point, &data, self) data.render_info.widgets_under_point(point, &data, self)
} }
@ -398,8 +398,8 @@ impl Tree {
} }
pub(crate) struct HoverResults { pub(crate) struct HoverResults {
pub unhovered: Vec<ManagedWidget>, pub unhovered: Vec<MountedWidget>,
pub hovered: Vec<ManagedWidget>, pub hovered: Vec<MountedWidget>,
} }
#[derive(Default)] #[derive(Default)]
@ -416,17 +416,17 @@ struct TreeData {
} }
impl TreeData { impl TreeData {
fn widget_from_id(&self, id: WidgetId, tree: &Tree) -> Option<ManagedWidget> { fn widget_from_id(&self, id: WidgetId, tree: &Tree) -> Option<MountedWidget> {
let node_id = *self.nodes_by_id.get(&id)?; let node_id = *self.nodes_by_id.get(&id)?;
Some(ManagedWidget { Some(MountedWidget {
node_id, node_id,
widget: self.nodes[node_id].widget.clone(), widget: self.nodes[node_id].widget.clone(),
tree: tree.clone(), tree: tree.clone(),
}) })
} }
fn widget_from_node(&self, node_id: LotId, tree: &Tree) -> Option<ManagedWidget> { fn widget_from_node(&self, node_id: LotId, tree: &Tree) -> Option<MountedWidget> {
Some(ManagedWidget { Some(MountedWidget {
node_id, node_id,
widget: self.nodes.get(node_id)?.widget.clone(), widget: self.nodes.get(node_id)?.widget.clone(),
tree: tree.clone(), tree: tree.clone(),
@ -489,7 +489,7 @@ impl TreeData {
} }
} }
pub(crate) fn widget_hierarchy(&self, mut widget: LotId, tree: &Tree) -> Vec<ManagedWidget> { pub(crate) fn widget_hierarchy(&self, mut widget: LotId, tree: &Tree) -> Vec<MountedWidget> {
let mut hierarchy = Vec::new(); let mut hierarchy = Vec::new();
while let Some(managed) = self.widget_from_node(widget, tree) { while let Some(managed) = self.widget_from_node(widget, tree) {
hierarchy.push(managed); hierarchy.push(managed);
@ -509,7 +509,7 @@ impl TreeData {
new_widget: Option<WidgetId>, new_widget: Option<WidgetId>,
tree: &Tree, tree: &Tree,
property: impl FnOnce(&mut Self) -> &mut Option<LotId>, property: impl FnOnce(&mut Self) -> &mut Option<LotId>,
) -> Result<Option<ManagedWidget>, ()> { ) -> Result<Option<MountedWidget>, ()> {
let new_widget = new_widget.and_then(|w| self.widget_from_id(w, tree)); let new_widget = new_widget.and_then(|w| self.widget_from_id(w, tree));
match ( match (
mem::replace(property(self), new_widget.as_ref().map(|w| w.node_id)), mem::replace(property(self), new_widget.as_ref().map(|w| w.node_id)),
@ -555,7 +555,7 @@ impl RenderInfo {
point: Point<Px>, point: Point<Px>,
tree_data: &TreeData, tree_data: &TreeData,
tree: &Tree, tree: &Tree,
) -> Vec<ManagedWidget> { ) -> Vec<MountedWidget> {
// We pessimistically allocate a vector as if all widgets match, up to a // We pessimistically allocate a vector as if all widgets match, up to a
// reasonable limit. This should ensure minimal allocations in all but // reasonable limit. This should ensure minimal allocations in all but
// extreme circumstances where widgets are nested with a significant // extreme circumstances where widgets are nested with a significant

View file

@ -22,7 +22,7 @@ use crate::animation::{AnimationHandle, DynamicTransition, IntoAnimate, LinearIn
use crate::context::sealed::WindowHandle; use crate::context::sealed::WindowHandle;
use crate::context::{self, WidgetContext}; use crate::context::{self, WidgetContext};
use crate::utils::{run_in_bg, IgnorePoison, UnwindsafeCondvar, WithClone}; use crate::utils::{run_in_bg, IgnorePoison, UnwindsafeCondvar, WithClone};
use crate::widget::{Children, MakeWidget, MakeWidgetWithId, WidgetId, WidgetInstance}; use crate::widget::{Children, MakeWidget, MakeWidgetWithTag, WidgetId, WidgetInstance};
use crate::widgets::{Radio, Select, Space, Switcher}; use crate::widgets::{Radio, Select, Space, Switcher};
/// An instance of a value that provides APIs to observe and react to its /// An instance of a value that provides APIs to observe and react to its
@ -377,7 +377,7 @@ impl<T> Dynamic<T> {
/// This function panics if this value is already locked by the current /// This function panics if this value is already locked by the current
/// thread. /// thread.
#[must_use] #[must_use]
pub fn get_tracking_refresh(&self, context: &WidgetContext<'_, '_>) -> T pub fn get_tracking_redraw(&self, context: &WidgetContext<'_, '_>) -> T
where where
T: Clone, T: Clone,
{ {
@ -638,20 +638,20 @@ impl Dynamic<WidgetInstance> {
} }
} }
impl MakeWidgetWithId for Dynamic<WidgetInstance> { impl MakeWidgetWithTag for Dynamic<WidgetInstance> {
fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { fn make_with_tag(self, id: crate::widget::WidgetTag) -> WidgetInstance {
self.into_switcher().make_with_id(id) self.into_switcher().make_with_tag(id)
} }
} }
impl MakeWidgetWithId for Dynamic<Option<WidgetInstance>> { impl MakeWidgetWithTag for Dynamic<Option<WidgetInstance>> {
fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { fn make_with_tag(self, id: crate::widget::WidgetTag) -> WidgetInstance {
self.map_each(|widget| { self.map_each(|widget| {
widget widget
.as_ref() .as_ref()
.map_or_else(|| Space::clear().make_widget(), Clone::clone) .map_or_else(|| Space::clear().make_widget(), Clone::clone)
}) })
.make_with_id(id) .make_with_tag(id)
} }
} }
@ -1260,7 +1260,7 @@ impl<T> DynamicReader<T> {
/// This function panics if this value is already locked by the current /// This function panics if this value is already locked by the current
/// thread. /// thread.
#[must_use] #[must_use]
pub fn get_tracking_refresh(&mut self, context: &WidgetContext<'_, '_>) -> T pub fn get_tracking_redraw(&mut self, context: &WidgetContext<'_, '_>) -> T
where where
T: Clone, T: Clone,
{ {
@ -1649,7 +1649,7 @@ impl<T> Value<T> {
/// ///
/// If `self` is a dynamic, `context` will be refreshed when the value is /// If `self` is a dynamic, `context` will be refreshed when the value is
/// updated. /// updated.
pub fn get_tracked(&self, context: &WidgetContext<'_, '_>) -> T pub fn get_tracking_redraw(&self, context: &WidgetContext<'_, '_>) -> T
where where
T: Clone, T: Clone,
{ {

View file

@ -52,25 +52,214 @@ use crate::{ConstraintLimit, Run};
/// This type can go by many names in other UI frameworks: View, Component, /// This type can go by many names in other UI frameworks: View, Component,
/// Control. /// Control.
/// ///
/// # Widgets are hierarchical
///
/// Gooey's widgets are organized in a hierarchical structure: widgets can
/// contain other widgets. A window in Gooey contains a single root widget,
/// which may contain one or more additional widgets.
///
/// # How Widgets are created
///
/// Gooey offers several approaches to creating widgets. The primary trait that
/// is used to instantiate a widget is [`MakeWidget`]. This trait is
/// automatically implemented for all types that implement [`Widget`].
///
/// [`MakeWidget::make_widget`] is responsible for returning a
/// [`WidgetInstance`]. This is a wrapper for a type that implements [`Widget`]
/// that can be used without knowing the original type of the [`Widget`].
///
/// While all [`MakeWidget`] is automatically implemented for all [`Widget`]
/// types, it can also be implemented by types that do not implement [`Widget`].
/// This is a useful strategy when designing reusable widgets that are able to
/// be completely represented by composing existing widgets. The
/// [`ProgressBar`](crate::widgets::ProgressBar) type uses this strategy, as it
/// uses either a [`Spinner`](crate::widgets::progress::Spinner) or a
/// [`Slider`](crate::widgets::Slider) to show its progress.
///
/// One last convenience trait is provided to help create widgets that contain
/// exactly one child: [`WrapperWidget`]. [`WrapperWidget`] exposes most of the
/// same functions, but provides purpose-built functions for tweaking child's
/// layout and rendering behavior to minimize the amount of redundant code
/// between these types of widgets.
///
/// # Identifying Widgets
///
/// Once a widget has been instantiated as a [`WidgetInstance`], it will be
/// assigned a unique [`WidgetId`]. Sometimes, it may be helpful to pre-create a
/// [`WidgetId`] before the widget has been created. For these situations,
/// [`WidgetTag`] allows creating a tag that can be passed to
/// [`MakeWidgetWithTag::make_with_tag`] to set the returned
/// [`WidgetInstance`]'s id.
///
/// # How to "talk" to another widget
///
/// Once a widget has been wrapped inside of a [`WidgetInstance`], it is no
/// longer possible to invoke [`Widget`]/s functions directly. Instead, a
/// context must be created for that widget. In each of the [`Widget`]
/// functions, a context is provided that represents the current widget. Each
/// context type has a `for_other()` function that accepts any widget type: a
/// [`WidgetId`], a [`WidgetInstance`], a [`MountedWidget`], or a [`WidgetRef`].
/// The returned context will represent the associate widget, allowing access to
/// the exposed APIs through the context.
///
/// While [`WidgetInstance::lock`] can be used to gain access to the underlying
/// [`Widget`] type, this behavior should only be reserved for limited
/// situations. It should be preferred to pass data between widgets using
/// [`Dynamic`]s or style components if possible. This ensures that your code
/// can work with as many other widgets as possible, instead of restricting
/// features to a specific set of types.
///
/// # How layout and rendering works /// # How layout and rendering works
/// ///
/// TODO write layout + rendering docs /// When a window is rendered, the root widget has its
/// [`layout()`](Self::layout) function called with both constraints specifying
/// [`ConstraintLimit::SizeToFit`] with the window's inner size. The root widget
/// measures its content to try to fit within the specified constraints, and
/// returns its calculated size. If a widget has children, it can invoke
/// [`LayoutContext::layout()`] on a context for each of its children to
/// determine their required sizes.
/// ///
/// # Hit Testing /// Next, the window sets the root's layout. When a widget contains another
/// widget, it must call [`LayoutContext::set_child_layout`] for the child to be
/// able to be rendered. This tells Gooey the location to draw the widget. While
/// it is possible to provide any rectangle, Gooey clips all widgets and their
/// children so that they cannot draw outside of their assigned bounds.
/// ///
/// TODO write hit testing docs /// Once the layout has been determined, the window will invoke the root
/// widget's [`redraw()`](Self::redraw) function. If a widget contains one or
/// more children, it needs to invoke [`GraphicsContext::redraw()`] on a context
/// for each of its children during its own render function. This allows full
/// control over the order of drawing calls, allowing widgets to draw behind,
/// in-between, or in front of their children.
///
/// The last responsibility the window has each frame is size adjustment. The
/// window will potentially adjust its size automatically based on the root
/// widget's [`root_behavior()`](Self::root_behavior).
///
/// # Controlling Invalidation and Redrawing
///
/// Gooey only redraws window contents when requested by the operating system or
/// a tracked [`Dynamic`] is updated. Similarly, Gooey caches the known layout
/// sizes and locations for widgets unless they are *invalidated*. Invalidation
/// is done automatically when the window size changes or a tracked [`Dynamic`]
/// is updated.
///
/// These systems require Gooey to track which [`Dynamic`] values a widget
/// depends on for redrawing and invalidation. During a widget's redraw and
/// layout functions, it needs to ensure that all depended upon [`Dynamic`]s are
/// tracked using one of the various
/// `*_tracking_redraw()`/`*_tracking_invalidate()` functions. For example,
/// [`Dynamic::get_tracking_redraw()`] and
/// [`Dynamic::get_tracking_invalidate()`].
///
/// # Hover State: Hit Testing
///
/// Before any cursor-related events are sent to a widget, the cursor's position
/// is tested with [`Widget::hit_test`]. When a widget returns true for a
/// position, it is eligible to receive events such as mouse buttons.
///
/// When a widget returns false, it will not receive any cursor related events
/// with one exception: hover events. Hover events will fire for widgets whose
/// children are currently being hovered, regardless of whether
/// [`Widget::hit_test`] returned true.
///
/// The provided [`Widget::hit_test`] implementation returns false.
///
/// As the cursor moves across the window, the window will look at the render
/// information to see what widgets are positioned under the cursor and the
/// order in which they were drawn. Beginning at the topmost widget,
/// [`Widget::hit_test`] is called on each widget.
///
/// The currently hovered widget state is tracked for events that target widgets
/// beneath the current cursor.
/// ///
/// # Mouse Button Events /// # Mouse Button Events
/// ///
/// TODO write mouse button docs /// When a window receives an event for a mouse button being pressed, it calls
/// the hovered widget's [`mouse_down()`](Self::mouse_down) function. If the
/// function returns [`HANDLED`]/[`ControlFlow::Break`], the widget becomes the
/// *tracking* widget for that mouse button.
///
/// If the widget returns [`IGNORED`]/[`ControlFlow::Continue`], the window will
/// call the parent's `mouse_down()` function. This repeats until the root
/// widget is reached or a widget returns `HANDLED`.
///
/// Once a tracking widget is found, any cursor-related movements will cause
/// [`Widget::mouse_drag()`] to be called. Upon the mouse button being released,
/// the tracking widget's [`mouse_up()`](Self::mouse_up) function will be
/// called.
/// ///
/// # User Input Focus /// # User Input Focus
/// ///
/// TODO write focus docs /// A window can have a widget be *focused* for user input. For example, a text
/// [`Input`](crate::widgets::Input) only responds to keyboard input once user
/// input focus has been directed at the widget. This state is generally
/// represented by drawing the theme's highlight color around the border of the
/// widget. [`GraphicsContext::draw_focus_ring`] can be used to draw the
/// standard focus ring for rectangular-shaped widgets.
///
/// The most direct way to give a widget focus is to call
/// [`WidgetContext::focus`]. However, not all widgets can accept focus. If a
/// widget returns true from its [`accept_focus()`](Self::accept_focus)
/// function, focus will be given to it and its [`focus()`](Self::focus)
/// function will be invoked.
///
/// If a widget returns false from its `accept_focus()` function, the window
/// will perform these steps:
///
/// 1. If the widget has any children, sort its children visually and attempt to
/// focus each one until a widget accepts focus. If any of these children
/// have children, those children should also be checked.
/// 2. The widget asks its parent to find the next focus after itself. The
/// parent finds the current widget in that list and attempts to focus each
/// widget after the current widget in the visual order.
/// 3. This repeats until the root widget is reached, at which point focus is
/// attempted using this algorithm until either a focused widget is found or
/// the original widget is reached again. If no widget can be found in a full
/// cycle of the widget tree, focus will be cleared.
///
/// When a window first opens, it call [`focus()`][WidgetContext::focus] on the
/// root widget's context.
///
/// ## Losing Focus
///
/// A Widget can deny the ability for focus to be taken away from it by
/// returning `false` from [`Widget::allow_blur()`]. In general, widgets should
/// not do this. However, some user interfaces are designed to always keep focus
/// on a single widget, and this feature enables that functionality.
///
/// When a widget currently has focused and loses it, its [`blur()`](Self::blur)
/// function will be invoked.
/// ///
/// # Styling /// # Styling
/// ///
/// TODO write styling docs /// Gooey allows widgets to receive styling information through the widget
/// hierarchy using [`Styles`]. Gooey calculates the effectives styles for each
/// widget by inheriting all inheritable styles from its parent.
///
/// The [`Style`] widget allows assigining [`Styles`] to all of its children
/// widget. It works by calling [`WidgetContext::attach_styles`], and Gooey
/// takes care of the rest.
///
/// Styling in Gooey aims to be simple, easy-to-understand, and extensible.
///
/// # Color Themes
///
/// Gooey aims to make it easy for developers to customize the appearance of its
/// applications. The way color themes work in Gooey begins with the
/// [`ColorScheme`](crate::styles::ColorScheme). A color scheme is a set of
/// [`ColorSource`](crate::styles::ColorSource) that are used to generate a
/// variety of shades of colors for various roles color plays in a user
/// interface. In a way, coloring Gooey apps is a bit like paint-by-number,
/// where the number is the name of the color role.
///
/// A `ColorScheme` can be used to create a [`ThemePair`], which is theme
/// definition that a theme for light and dark mode.
///
/// In [the repository][repo], the `theme` example is a good way to explore how
/// the color system works in Gooey.
///
/// [repo]: https://github.com/khonsulabs/gooey
pub trait Widget: Send + UnwindSafe + Debug + 'static { pub trait Widget: Send + UnwindSafe + Debug + 'static {
/// Redraw the contents of this widget. /// Redraw the contents of this widget.
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>); fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>);
@ -1107,26 +1296,26 @@ pub trait MakeWidget: Sized {
/// A type that can create a [`WidgetInstance`] with a preallocated /// A type that can create a [`WidgetInstance`] with a preallocated
/// [`WidgetId`]. /// [`WidgetId`].
pub trait MakeWidgetWithId: Sized { pub trait MakeWidgetWithTag: Sized {
/// Returns a new [`WidgetInstance`] whose [`WidgetId`] is `id`. /// Returns a new [`WidgetInstance`] whose [`WidgetId`] comes from `tag`.
fn make_with_id(self, id: WidgetTag) -> WidgetInstance; fn make_with_tag(self, tag: WidgetTag) -> WidgetInstance;
} }
impl<T> MakeWidgetWithId for T impl<T> MakeWidgetWithTag for T
where where
T: Widget, T: Widget,
{ {
fn make_with_id(self, id: WidgetTag) -> WidgetInstance { fn make_with_tag(self, id: WidgetTag) -> WidgetInstance {
WidgetInstance::with_id(self, id) WidgetInstance::with_id(self, id)
} }
} }
impl<T> MakeWidget for T impl<T> MakeWidget for T
where where
T: MakeWidgetWithId, T: MakeWidgetWithTag,
{ {
fn make_widget(self) -> WidgetInstance { fn make_widget(self) -> WidgetInstance {
self.make_with_id(WidgetTag::unique()) self.make_with_tag(WidgetTag::unique())
} }
} }
@ -1136,9 +1325,9 @@ impl MakeWidget for WidgetInstance {
} }
} }
impl MakeWidgetWithId for Color { impl MakeWidgetWithTag for Color {
fn make_with_id(self, id: WidgetTag) -> WidgetInstance { fn make_with_tag(self, id: WidgetTag) -> WidgetInstance {
Space::colored(self).make_with_id(id) Space::colored(self).make_with_tag(id)
} }
} }
@ -1490,19 +1679,19 @@ where
/// A [`Widget`] that has been attached to a widget hierarchy. /// A [`Widget`] that has been attached to a widget hierarchy.
#[derive(Clone)] #[derive(Clone)]
pub struct ManagedWidget { pub struct MountedWidget {
pub(crate) node_id: LotId, pub(crate) node_id: LotId,
pub(crate) widget: WidgetInstance, pub(crate) widget: WidgetInstance,
pub(crate) tree: Tree, pub(crate) tree: Tree,
} }
impl Debug for ManagedWidget { impl Debug for MountedWidget {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Debug::fmt(&self.widget, f) Debug::fmt(&self.widget, f)
} }
} }
impl ManagedWidget { impl MountedWidget {
/// Locks the widget for exclusive access. Locking widgets should only be /// Locks the widget for exclusive access. Locking widgets should only be
/// done for brief moments of time when you are certain no deadlocks can /// done for brief moments of time when you are certain no deadlocks can
/// occur due to other widget locks being held. /// occur due to other widget locks being held.
@ -1537,7 +1726,7 @@ impl ManagedWidget {
/// This function returns the value set in /// This function returns the value set in
/// [`MakeWidget::with_next_focus()`]. /// [`MakeWidget::with_next_focus()`].
#[must_use] #[must_use]
pub fn next_focus(&self) -> Option<ManagedWidget> { pub fn next_focus(&self) -> Option<MountedWidget> {
self.widget self.widget
.next_focus() .next_focus()
.and_then(|next_focus| self.tree.widget(next_focus)) .and_then(|next_focus| self.tree.widget(next_focus))
@ -1548,14 +1737,14 @@ impl ManagedWidget {
/// There is no direct way to set this value. This relationship is created /// There is no direct way to set this value. This relationship is created
/// automatically using [`MakeWidget::with_next_focus()`]. /// automatically using [`MakeWidget::with_next_focus()`].
#[must_use] #[must_use]
pub fn previous_focus(&self) -> Option<ManagedWidget> { pub fn previous_focus(&self) -> Option<MountedWidget> {
self.tree.previous_focus(self.id()) self.tree.previous_focus(self.id())
} }
/// Returns the next or previous focus target, if one was set using /// Returns the next or previous focus target, if one was set using
/// [`MakeWidget::with_next_focus()`]. /// [`MakeWidget::with_next_focus()`].
#[must_use] #[must_use]
pub fn explicit_focus_target(&self, advance: bool) -> Option<ManagedWidget> { pub fn explicit_focus_target(&self, advance: bool) -> Option<MountedWidget> {
if advance { if advance {
self.next_focus() self.next_focus()
} else { } else {
@ -1605,7 +1794,7 @@ impl ManagedWidget {
/// Returns the parent of this widget. /// Returns the parent of this widget.
#[must_use] #[must_use]
pub fn parent(&self) -> Option<ManagedWidget> { pub fn parent(&self) -> Option<MountedWidget> {
self.tree self.tree
.parent(self.node_id) .parent(self.node_id)
.and_then(|id| self.tree.widget_from_node(id)) .and_then(|id| self.tree.widget_from_node(id))
@ -1643,24 +1832,24 @@ impl ManagedWidget {
self.tree.persist_layout(self.node_id, constraints, size); self.tree.persist_layout(self.node_id, constraints, size);
} }
pub(crate) fn visually_ordered_children(&self, order: VisualOrder) -> Vec<ManagedWidget> { pub(crate) fn visually_ordered_children(&self, order: VisualOrder) -> Vec<MountedWidget> {
self.tree.visually_ordered_children(self.node_id, order) self.tree.visually_ordered_children(self.node_id, order)
} }
} }
impl AsRef<WidgetId> for ManagedWidget { impl AsRef<WidgetId> for MountedWidget {
fn as_ref(&self) -> &WidgetId { fn as_ref(&self) -> &WidgetId {
self.widget.as_ref() self.widget.as_ref()
} }
} }
impl PartialEq for ManagedWidget { impl PartialEq for MountedWidget {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.widget == other.widget self.widget == other.widget
} }
} }
impl PartialEq<WidgetInstance> for ManagedWidget { impl PartialEq<WidgetInstance> for MountedWidget {
fn eq(&self, other: &WidgetInstance) -> bool { fn eq(&self, other: &WidgetInstance) -> bool {
&self.widget == other &self.widget == other
} }
@ -1915,7 +2104,7 @@ pub enum ChildrenSyncChange {
/// contain multiple children widgets. It is used in conjunction with a /// contain multiple children widgets. It is used in conjunction with a
/// `Value<Children>`. /// `Value<Children>`.
#[derive(Debug)] #[derive(Debug)]
pub struct MountedChildren<T = ManagedWidget> { pub struct MountedChildren<T = MountedWidget> {
generation: Option<Generation>, generation: Option<Generation>,
children: Vec<T>, children: Vec<T>,
} }
@ -1990,23 +2179,23 @@ impl<T> Default for MountedChildren<T> {
/// A child in a [`MountedChildren`] collection. /// A child in a [`MountedChildren`] collection.
pub trait MountableChild: Sized { pub trait MountableChild: Sized {
/// Returns the mounted representation of `widget`. /// Returns the mounted representation of `widget`.
fn mount(widget: ManagedWidget, into: &MountedChildren<Self>, index: usize) -> Self; fn mount(widget: MountedWidget, into: &MountedChildren<Self>, index: usize) -> Self;
/// Returns the widget and performs any other cleanup for this widget being unmounted.q /// Returns the widget and performs any other cleanup for this widget being unmounted.q
fn unmount(self) -> ManagedWidget; fn unmount(self) -> MountedWidget;
/// Returns a reference to the widget. /// Returns a reference to the widget.
fn widget(&self) -> &ManagedWidget; fn widget(&self) -> &MountedWidget;
} }
impl MountableChild for ManagedWidget { impl MountableChild for MountedWidget {
fn mount(widget: ManagedWidget, _into: &MountedChildren<Self>, _index: usize) -> Self { fn mount(widget: MountedWidget, _into: &MountedChildren<Self>, _index: usize) -> Self {
widget widget
} }
fn widget(&self) -> &ManagedWidget { fn widget(&self) -> &MountedWidget {
self self
} }
fn unmount(self) -> ManagedWidget { fn unmount(self) -> MountedWidget {
self self
} }
} }
@ -2017,7 +2206,7 @@ pub enum WidgetRef {
/// An unmounted child widget /// An unmounted child widget
Unmounted(WidgetInstance), Unmounted(WidgetInstance),
/// A mounted child widget /// A mounted child widget
Mounted(ManagedWidget), Mounted(MountedWidget),
} }
impl WidgetRef { impl WidgetRef {
@ -2037,7 +2226,7 @@ impl WidgetRef {
pub fn mounted<'window>( pub fn mounted<'window>(
&mut self, &mut self,
context: &mut impl AsEventContext<'window>, context: &mut impl AsEventContext<'window>,
) -> ManagedWidget { ) -> MountedWidget {
self.mount_if_needed(context); self.mount_if_needed(context);
let Self::Mounted(widget) = self else { let Self::Mounted(widget) = self else {
@ -2101,14 +2290,14 @@ impl WidgetId {
/// Finds this widget mounted in this window, if present. /// Finds this widget mounted in this window, if present.
#[must_use] #[must_use]
pub fn find_in(self, context: &WidgetContext<'_, '_>) -> Option<ManagedWidget> { pub fn find_in(self, context: &WidgetContext<'_, '_>) -> Option<MountedWidget> {
context.widget().tree.widget(self) context.widget().tree.widget(self)
} }
} }
/// A [`WidgetId`] that has not been assigned to a [`WidgetInstance`]. /// A [`WidgetId`] that has not been assigned to a [`WidgetInstance`].
/// ///
/// This type is passed to [`MakeWidgetWithId::make_with_id()`] to create a /// This type is passed to [`MakeWidgetWithTag::make_with_tag()`] to create a
/// [`WidgetInstance`] with a preallocated id. /// [`WidgetInstance`] with a preallocated id.
/// ///
/// This type cannot be cloned or copied to ensure only a single widget can be /// This type cannot be cloned or copied to ensure only a single widget can be

View file

@ -226,7 +226,7 @@ impl Button {
} }
fn determine_stateful_colors(&mut self, context: &mut WidgetContext<'_, '_>) -> ButtonColors { fn determine_stateful_colors(&mut self, context: &mut WidgetContext<'_, '_>) -> ButtonColors {
let kind = self.kind.get_tracked(context); let kind = self.kind.get_tracking_redraw(context);
let visual_state = Self::visual_style(context); let visual_state = Self::visual_style(context);
self.cached_state = CacheState { self.cached_state = CacheState {
@ -352,7 +352,7 @@ impl Widget for Button {
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) { fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
#![allow(clippy::similar_names)] #![allow(clippy::similar_names)]
let current_style = self.kind.get_tracked(context); let current_style = self.kind.get_tracking_redraw(context);
if self.cached_state.key != context.cache_key() || self.cached_state.kind != current_style { if self.cached_state.key != context.cache_key() || self.cached_state.kind != current_style {
self.update_colors(context, false); self.update_colors(context, false);
} }

View file

@ -11,7 +11,7 @@ use crate::context::{GraphicsContext, LayoutContext};
use crate::styles::components::{LineHeight, OutlineColor, TextColor, WidgetAccentColor}; use crate::styles::components::{LineHeight, OutlineColor, TextColor, WidgetAccentColor};
use crate::styles::Dimension; use crate::styles::Dimension;
use crate::value::{Dynamic, DynamicReader, IntoDynamic, IntoValue, Value}; use crate::value::{Dynamic, DynamicReader, IntoDynamic, IntoValue, Value};
use crate::widget::{MakeWidget, MakeWidgetWithId, Widget, WidgetInstance}; use crate::widget::{MakeWidget, MakeWidgetWithTag, Widget, WidgetInstance};
use crate::widgets::button::ButtonKind; use crate::widgets::button::ButtonKind;
use crate::ConstraintLimit; use crate::ConstraintLimit;
@ -51,8 +51,8 @@ impl Checkbox {
} }
} }
impl MakeWidgetWithId for Checkbox { impl MakeWidgetWithTag for Checkbox {
fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { fn make_with_tag(self, id: crate::widget::WidgetTag) -> WidgetInstance {
CheckboxOrnament { CheckboxOrnament {
value: self.state.create_reader(), value: self.state.create_reader(),
} }
@ -64,7 +64,7 @@ impl MakeWidgetWithId for Checkbox {
*value = !*value; *value = !*value;
}) })
.kind(self.kind) .kind(self.kind)
.make_with_id(id) .make_with_tag(id)
} }
} }
@ -192,7 +192,7 @@ impl Widget for CheckboxOrnament {
); );
let stroke_options = StrokeOptions::lp_wide(Lp::points(2)).into_px(context.gfx.scale()); let stroke_options = StrokeOptions::lp_wide(Lp::points(2)).into_px(context.gfx.scale());
match self.value.get_tracking_refresh(context) { match self.value.get_tracking_redraw(context) {
state @ (CheckboxState::Checked | CheckboxState::Indeterminant) => { state @ (CheckboxState::Checked | CheckboxState::Indeterminant) => {
let color = context.get(&WidgetAccentColor); let color = context.get(&WidgetAccentColor);
context context

View file

@ -73,7 +73,7 @@ impl Widget for ColorSourcePicker {
let loupe_size = Lp::mm(3).into_px(context.gfx.scale()); let loupe_size = Lp::mm(3).into_px(context.gfx.scale());
let size = context.gfx.region().size; let size = context.gfx.region().size;
let value = self.value.get_tracking_refresh(context); let value = self.value.get_tracking_redraw(context);
let value_pos = self.visible_rect.origin let value_pos = self.visible_rect.origin
+ Point::new( + Point::new(
if self.hue_is_360 { if self.hue_is_360 {
@ -84,7 +84,7 @@ impl Widget for ColorSourcePicker {
self.visible_rect.size.height * *value.saturation.one_minus(), self.visible_rect.size.height * *value.saturation.one_minus(),
); );
let lightness = self.lightness.get_tracked(context); let lightness = self.lightness.get_tracking_redraw(context);
let value_color = value.color(lightness); let value_color = value.color(lightness);
let outline_color = if context.focused(true) { let outline_color = if context.focused(true) {

View file

@ -544,7 +544,9 @@ impl WrapperWidget for Custom {
} }
fn background_color(&mut self, context: &WidgetContext<'_, '_>) -> Option<Color> { fn background_color(&mut self, context: &WidgetContext<'_, '_>) -> Option<Color> {
self.background.as_ref().map(|bg| bg.get_tracked(context)) self.background
.as_ref()
.map(|bg| bg.get_tracking_redraw(context))
} }
fn mounted(&mut self, context: &mut EventContext<'_, '_>) { fn mounted(&mut self, context: &mut EventContext<'_, '_>) {

View file

@ -16,7 +16,7 @@ use crate::context::{AsEventContext, EventContext, GraphicsContext, LayoutContex
use crate::styles::components::IntrinsicPadding; use crate::styles::components::IntrinsicPadding;
use crate::styles::Dimension; use crate::styles::Dimension;
use crate::value::{Generation, IntoValue, Value}; use crate::value::{Generation, IntoValue, Value};
use crate::widget::{MakeWidget, ManagedWidget, Widget, WidgetInstance}; use crate::widget::{MakeWidget, MountedWidget, Widget, WidgetInstance};
use crate::ConstraintLimit; use crate::ConstraintLimit;
/// A 2D grid of widgets. /// A 2D grid of widgets.
@ -24,7 +24,7 @@ use crate::ConstraintLimit;
pub struct Grid<const ELEMENTS: usize> { pub struct Grid<const ELEMENTS: usize> {
columns: Value<[GridDimension; ELEMENTS]>, columns: Value<[GridDimension; ELEMENTS]>,
rows: Value<GridWidgets<ELEMENTS>>, rows: Value<GridWidgets<ELEMENTS>>,
live_rows: Vec<[ManagedWidget; ELEMENTS]>, live_rows: Vec<[MountedWidget; ELEMENTS]>,
layout: GridLayout, layout: GridLayout,
layout_generation: Option<Generation>, layout_generation: Option<Generation>,
spec_generation: Option<Generation>, spec_generation: Option<Generation>,

View file

@ -1019,7 +1019,7 @@ where
} }
self.blink_state.update(context.elapsed()); self.blink_state.update(context.elapsed());
let window_focused = context.window().focused().get_tracking_refresh(context); let window_focused = context.window().focused().get_tracking_redraw(context);
if window_focused != self.window_focused { if window_focused != self.window_focused {
if window_focused { if window_focused {
self.blink_state.force_on(); self.blink_state.force_on();

View file

@ -94,9 +94,9 @@ impl Widget for Label {
macro_rules! impl_make_widget { macro_rules! impl_make_widget {
($($type:ty),*) => { ($($type:ty),*) => {
$(impl crate::widget::MakeWidgetWithId for $type { $(impl crate::widget::MakeWidgetWithTag for $type {
fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { fn make_with_tag(self, id: crate::widget::WidgetTag) -> WidgetInstance {
Label::new(self).make_with_id(id) Label::new(self).make_with_tag(id)
} }
})* })*
}; };

View file

@ -16,7 +16,7 @@ use crate::context::{AsEventContext, EventContext, GraphicsContext, LayoutContex
use crate::utils::IgnorePoison; use crate::utils::IgnorePoison;
use crate::value::{Dynamic, DynamicGuard, IntoValue, Value}; use crate::value::{Dynamic, DynamicGuard, IntoValue, Value};
use crate::widget::{ use crate::widget::{
Callback, Children, MakeWidget, ManagedWidget, MountedChildren, Widget, WidgetId, WidgetRef, Callback, Children, MakeWidget, MountedChildren, MountedWidget, Widget, WidgetId, WidgetRef,
WrapperWidget, WrapperWidget,
}; };
use crate::widgets::container::ContainerShadow; use crate::widgets::container::ContainerShadow;
@ -182,7 +182,7 @@ impl Widget for OverlayLayer {
continue; continue;
}; };
let opacity = child.opacity.get_tracking_refresh(context); let opacity = child.opacity.get_tracking_redraw(context);
let mut context = context.for_other(mounted); let mut context = context.for_other(mounted);
context.apply_opacity(opacity); context.apply_opacity(opacity);
context.redraw(); context.redraw();
@ -376,7 +376,7 @@ impl OverlayState {
fn layout_overlay_relative( fn layout_overlay_relative(
&mut self, &mut self,
index: usize, index: usize,
widget: &ManagedWidget, widget: &MountedWidget,
available_space: Size<UPx>, available_space: Size<UPx>,
context: &mut LayoutContext<'_, '_, '_, '_, '_>, context: &mut LayoutContext<'_, '_, '_, '_, '_>,
relative_to: WidgetId, relative_to: WidgetId,
@ -495,7 +495,7 @@ impl OverlayState {
fn layout_overlay( fn layout_overlay(
&mut self, &mut self,
index: usize, index: usize,
widget: &ManagedWidget, widget: &MountedWidget,
available_space: Size<UPx>, available_space: Size<UPx>,
context: &mut LayoutContext<'_, '_, '_, '_, '_>, context: &mut LayoutContext<'_, '_, '_, '_, '_>,
) -> Option<Rect<Px>> { ) -> Option<Rect<Px>> {

View file

@ -13,7 +13,7 @@ use crate::animation::{
AnimationHandle, AnimationTarget, IntoAnimate, PercentBetween, Spawn, ZeroToOne, AnimationHandle, AnimationTarget, IntoAnimate, PercentBetween, Spawn, ZeroToOne,
}; };
use crate::value::{Dynamic, IntoDynamic, IntoValue, MapEach, Value}; use crate::value::{Dynamic, IntoDynamic, IntoValue, MapEach, Value};
use crate::widget::{MakeWidget, MakeWidgetWithId, Widget, WidgetInstance}; use crate::widget::{MakeWidget, MakeWidgetWithTag, Widget, WidgetInstance};
use crate::widgets::slider::{InactiveTrackColor, Slidable, TrackColor, TrackSize}; use crate::widgets::slider::{InactiveTrackColor, Slidable, TrackColor, TrackSize};
use crate::widgets::Data; use crate::widgets::Data;
@ -60,8 +60,8 @@ pub enum Progress<T = ZeroToOne> {
Percent(T), Percent(T),
} }
impl MakeWidgetWithId for ProgressBar { impl MakeWidgetWithTag for ProgressBar {
fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { fn make_with_tag(self, id: crate::widget::WidgetTag) -> WidgetInstance {
let start = Dynamic::new(ZeroToOne::ZERO); let start = Dynamic::new(ZeroToOne::ZERO);
let end = Dynamic::new(ZeroToOne::ZERO); let end = Dynamic::new(ZeroToOne::ZERO);
let value = (&start, &end).map_each(|(start, end)| *start..=*end); let value = (&start, &end).map_each(|(start, end)| *start..=*end);
@ -76,12 +76,16 @@ impl MakeWidgetWithId for ProgressBar {
end: end.clone(), end: end.clone(),
degree_offset: degree_offset.clone(), degree_offset: degree_offset.clone(),
} }
.make_with_id(id), .make_with_tag(id),
Some(degree_offset), Some(degree_offset),
) )
} else { } else {
( (
value.slider().knobless().non_interactive().make_with_id(id), value
.slider()
.knobless()
.non_interactive()
.make_with_tag(id),
None, None,
) )
}; };
@ -332,8 +336,8 @@ impl Spinner {
impl Widget for Spinner { impl Widget for Spinner {
fn redraw(&mut self, context: &mut crate::context::GraphicsContext<'_, '_, '_, '_, '_>) { fn redraw(&mut self, context: &mut crate::context::GraphicsContext<'_, '_, '_, '_, '_>) {
let track_size = context.get(&TrackSize).into_px(context.gfx.scale()); let track_size = context.get(&TrackSize).into_px(context.gfx.scale());
let start = self.start.get_tracking_refresh(context); let start = self.start.get_tracking_redraw(context);
let end = self.end.get_tracking_refresh(context); let end = self.end.get_tracking_redraw(context);
let size = context.gfx.region().size; let size = context.gfx.region().size;
let render_size = size.width.min(size.height); let render_size = size.width.min(size.height);
let radius = render_size / 2 - track_size; let radius = render_size / 2 - track_size;

View file

@ -11,7 +11,7 @@ use crate::context::{GraphicsContext, LayoutContext};
use crate::styles::components::{LineHeight, OutlineColor, WidgetAccentColor}; use crate::styles::components::{LineHeight, OutlineColor, WidgetAccentColor};
use crate::styles::Dimension; use crate::styles::Dimension;
use crate::value::{Dynamic, DynamicReader, IntoDynamic, IntoValue, Value}; use crate::value::{Dynamic, DynamicReader, IntoDynamic, IntoValue, Value};
use crate::widget::{MakeWidget, MakeWidgetWithId, Widget, WidgetInstance}; use crate::widget::{MakeWidget, MakeWidgetWithTag, Widget, WidgetInstance};
use crate::widgets::button::ButtonKind; use crate::widgets::button::ButtonKind;
use crate::ConstraintLimit; use crate::ConstraintLimit;
@ -51,11 +51,11 @@ impl<T> Radio<T> {
} }
} }
impl<T> MakeWidgetWithId for Radio<T> impl<T> MakeWidgetWithTag for Radio<T>
where where
T: Clone + Debug + Eq + UnwindSafe + Send + 'static, T: Clone + Debug + Eq + UnwindSafe + Send + 'static,
{ {
fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { fn make_with_tag(self, id: crate::widget::WidgetTag) -> WidgetInstance {
RadioOrnament { RadioOrnament {
value: self.value.clone(), value: self.value.clone(),
state: self.state.create_reader(), state: self.state.create_reader(),
@ -67,7 +67,7 @@ where
self.state.set(self.value.clone()); self.state.set(self.value.clone());
}) })
.kind(self.kind) .kind(self.kind)
.make_with_id(id) .make_with_tag(id)
} }
} }

View file

@ -7,7 +7,7 @@ use kludgine::Color;
use crate::styles::components::OutlineColor; use crate::styles::components::OutlineColor;
use crate::styles::{Component, DynamicComponent}; use crate::styles::{Component, DynamicComponent};
use crate::value::{Dynamic, IntoDynamic, IntoValue, MapEach, Value}; use crate::value::{Dynamic, IntoDynamic, IntoValue, MapEach, Value};
use crate::widget::{MakeWidget, MakeWidgetWithId, WidgetInstance}; use crate::widget::{MakeWidget, MakeWidgetWithTag, WidgetInstance};
use crate::widgets::button::{ButtonBackground, ButtonHoverBackground, ButtonKind}; use crate::widgets::button::{ButtonBackground, ButtonHoverBackground, ButtonKind};
/// A selectable, labeled widget representing a value. /// A selectable, labeled widget representing a value.
@ -46,11 +46,11 @@ impl<T> Select<T> {
} }
} }
impl<T> MakeWidgetWithId for Select<T> impl<T> MakeWidgetWithTag for Select<T>
where where
T: Clone + Debug + Eq + RefUnwindSafe + UnwindSafe + Send + Sync + 'static, T: Clone + Debug + Eq + RefUnwindSafe + UnwindSafe + Send + Sync + 'static,
{ {
fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { fn make_with_tag(self, id: crate::widget::WidgetTag) -> WidgetInstance {
let selected = self.state.map_each({ let selected = self.state.map_each({
let value = self.value.clone(); let value = self.value.clone();
move |state| state == &value move |state| state == &value
@ -58,7 +58,7 @@ where
let selected_color = DynamicComponent::new({ let selected_color = DynamicComponent::new({
let selected = selected.clone(); let selected = selected.clone();
move |context| { move |context| {
if selected.get_tracking_refresh(context) { if selected.get_tracking_redraw(context) {
Some(Component::Color(context.get(&SelectedColor))) Some(Component::Color(context.get(&SelectedColor)))
} else { } else {
None None
@ -80,7 +80,7 @@ where
.kind(kind) .kind(kind)
.with_dynamic(&ButtonBackground, selected_color.clone()) .with_dynamic(&ButtonBackground, selected_color.clone())
.with_dynamic(&ButtonHoverBackground, selected_color) .with_dynamic(&ButtonHoverBackground, selected_color)
.make_with_id(id) .make_with_tag(id)
} }
} }

View file

@ -443,9 +443,9 @@ where
let half_knob = knob_size / 2; let half_knob = knob_size / 2;
let (mut start_value, mut end_value) = let (mut start_value, mut end_value) =
T::into_parts(self.value.get_tracking_refresh(context)); T::into_parts(self.value.get_tracking_redraw(context));
let min = self.minimum.get_tracked(context); let min = self.minimum.get_tracking_redraw(context);
let mut max = self.maximum.get_tracked(context); let mut max = self.maximum.get_tracking_redraw(context);
if max < min { if max < min {
self.maximum.map_mut(|max| *max = min.clone()); self.maximum.map_mut(|max| *max = min.clone());

View file

@ -39,7 +39,7 @@ impl Space {
impl Widget for Space { impl Widget for Space {
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) { fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
let color = self.color.get_tracked(context); let color = self.color.get_tracking_redraw(context);
context.fill(color); context.fill(color);
} }

View file

@ -7,7 +7,7 @@ use crate::context::{AsEventContext, EventContext, GraphicsContext, LayoutContex
use crate::styles::components::IntrinsicPadding; use crate::styles::components::IntrinsicPadding;
use crate::styles::FlexibleDimension; use crate::styles::FlexibleDimension;
use crate::value::{Generation, IntoValue, Value}; use crate::value::{Generation, IntoValue, Value};
use crate::widget::{Children, ChildrenSyncChange, ManagedWidget, Widget, WidgetRef}; use crate::widget::{Children, ChildrenSyncChange, MountedWidget, Widget, WidgetRef};
use crate::widgets::grid::{GridDimension, GridLayout, Orientation}; use crate::widgets::grid::{GridDimension, GridLayout, Orientation};
use crate::widgets::{Expand, Resize}; use crate::widgets::{Expand, Resize};
use crate::ConstraintLimit; use crate::ConstraintLimit;
@ -24,7 +24,7 @@ pub struct Stack {
layout: GridLayout, layout: GridLayout,
layout_generation: Option<Generation>, layout_generation: Option<Generation>,
// TODO Refactor synced_children into its own type. // TODO Refactor synced_children into its own type.
synced_children: Vec<ManagedWidget>, synced_children: Vec<MountedWidget>,
} }
impl Stack { impl Stack {
@ -68,7 +68,7 @@ impl Stack {
self.children.map(|children| { self.children.map(|children| {
children.synchronize_with( children.synchronize_with(
&mut self.synced_children, &mut self.synced_children,
|this, index| this.get(index).map(ManagedWidget::instance), |this, index| this.get(index).map(MountedWidget::instance),
|this, change| match change { |this, change| match change {
ChildrenSyncChange::Insert(index, widget) => { ChildrenSyncChange::Insert(index, widget) => {
// This is a brand new child. // This is a brand new child.

View file

@ -9,7 +9,7 @@ use crate::styles::components::{
}; };
use crate::styles::Dimension; use crate::styles::Dimension;
use crate::value::{Dynamic, IntoDynamic, IntoValue, MapEach, Validation, Value}; use crate::value::{Dynamic, IntoDynamic, IntoValue, MapEach, Validation, Value};
use crate::widget::{MakeWidget, MakeWidgetWithId, WidgetInstance, WidgetRef, WrapperWidget}; use crate::widget::{MakeWidget, MakeWidgetWithTag, WidgetInstance, WidgetRef, WrapperWidget};
/// A widget that displays validation information around another widget. /// A widget that displays validation information around another widget.
/// ///
@ -46,8 +46,8 @@ impl Validated {
} }
} }
impl MakeWidgetWithId for Validated { impl MakeWidgetWithTag for Validated {
fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { fn make_with_tag(self, id: crate::widget::WidgetTag) -> WidgetInstance {
let message = match self.hint { let message = match self.hint {
Value::Constant(hint) => self Value::Constant(hint) => self
.validation .validation
@ -84,7 +84,7 @@ impl MakeWidgetWithId for Validated {
error_color, error_color,
default_color, default_color,
} }
.make_with_id(id) .make_with_tag(id)
} }
} }

View file

@ -39,7 +39,7 @@ use crate::tree::Tree;
use crate::utils::ModifiersExt; use crate::utils::ModifiersExt;
use crate::value::{Dynamic, DynamicReader, IntoDynamic, IntoValue, Value}; use crate::value::{Dynamic, DynamicReader, IntoDynamic, IntoValue, Value};
use crate::widget::{ use crate::widget::{
EventHandling, ManagedWidget, RootBehavior, Widget, WidgetId, WidgetInstance, HANDLED, IGNORED, EventHandling, MountedWidget, RootBehavior, Widget, WidgetId, WidgetInstance, HANDLED, IGNORED,
}; };
use crate::window::sealed::WindowCommand; use crate::window::sealed::WindowCommand;
use crate::{initialize_tracing, ConstraintLimit, Run}; use crate::{initialize_tracing, ConstraintLimit, Run};
@ -338,7 +338,7 @@ pub trait WindowBehavior: Sized + 'static {
struct GooeyWindow<T> { struct GooeyWindow<T> {
behavior: T, behavior: T,
root: ManagedWidget, root: MountedWidget,
contents: Drawing, contents: Drawing,
should_close: bool, should_close: bool,
cursor: CursorState, cursor: CursorState,
@ -1221,7 +1221,7 @@ where
fn recursively_handle_event( fn recursively_handle_event(
context: &mut EventContext<'_, '_>, context: &mut EventContext<'_, '_>,
mut each_widget: impl FnMut(&mut EventContext<'_, '_>) -> EventHandling, mut each_widget: impl FnMut(&mut EventContext<'_, '_>) -> EventHandling,
) -> Option<ManagedWidget> { ) -> Option<MountedWidget> {
match each_widget(context) { match each_widget(context) {
HANDLED => Some(context.widget().clone()), HANDLED => Some(context.widget().clone()),
IGNORED => context.parent().and_then(|parent| { IGNORED => context.parent().and_then(|parent| {