From 02d6b343f1320724830067fcf73ce8d71da0bb99 Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Sun, 17 Dec 2023 07:38:31 -0800 Subject: [PATCH] Widget docs + refactoring - MakeWidgetWithId::make_with_id -> MakeWidgetWithTag::make_With_tag - ManagedWidget -> MountedWidget - *_refresh -> *_redraw, standardized on terminology - get_tracked -> get_tracking_redraw --- Cargo.lock | 22 +-- examples/custom-widgets.rs | 18 +-- examples/focus-order.rs | 8 +- examples/overlays.rs | 4 +- src/context.rs | 60 ++++----- src/lib.rs | 18 --- src/tree.rs | 52 ++++---- src/value.rs | 20 +-- src/widget.rs | 267 +++++++++++++++++++++++++++++++------ src/widgets/button.rs | 4 +- src/widgets/checkbox.rs | 10 +- src/widgets/color.rs | 4 +- src/widgets/custom.rs | 4 +- src/widgets/grid.rs | 4 +- src/widgets/input.rs | 2 +- src/widgets/label.rs | 6 +- src/widgets/layers.rs | 8 +- src/widgets/progress.rs | 18 ++- src/widgets/radio.rs | 8 +- src/widgets/select.rs | 10 +- src/widgets/slider.rs | 6 +- src/widgets/space.rs | 2 +- src/widgets/stack.rs | 6 +- src/widgets/validated.rs | 8 +- src/window.rs | 6 +- 25 files changed, 376 insertions(+), 199 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0d80e45..1fa89eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1181,13 +1181,13 @@ dependencies = [ [[package]] name = "lyon_tessellation" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f5bcf02928361d18e6edb8ad3bc5b93cba8aa57e2508deb072c2d2ade8bbd0d" +checksum = "8c7c67b5bc8123b352b2e7e742b47d1f236a13fe77619433be9568fbd888e9c0" dependencies = [ "float_next_after", "lyon_path", - "thiserror", + "num-traits", ] [[package]] @@ -1271,9 +1271,9 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deaba38d7abf1d4cca21cc89e932e542ba2b9258664d2a9ef0e61512039c9375" +checksum = "39a69c7c189ae418f83003da62820aca28d15a07725ce51fb924999335d622ff" dependencies = [ "libc", ] @@ -2064,7 +2064,7 @@ dependencies = [ "cursor-icon", "libc", "log", - "memmap2 0.9.0", + "memmap2 0.9.2", "rustix", "thiserror", "wayland-backend", @@ -2164,18 +2164,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" dependencies = [ "proc-macro2", "quote", @@ -2982,7 +2982,7 @@ dependencies = [ "js-sys", "libc", "log", - "memmap2 0.9.0", + "memmap2 0.9.2", "ndk", "ndk-sys", "objc2", diff --git a/examples/custom-widgets.rs b/examples/custom-widgets.rs index 8c35b43..624739d 100644 --- a/examples/custom-widgets.rs +++ b/examples/custom-widgets.rs @@ -2,7 +2,7 @@ //! traits or using the [`Custom`] widget with callbacks. 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::Run; 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 /// 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 // same Dynamic value setup. let toggle = Toggle::default(); @@ -44,7 +44,7 @@ fn callback_widget() -> impl MakeWidgetWithId { .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 /// widget. /// @@ -52,7 +52,7 @@ fn callback_widget() -> impl MakeWidgetWithId { /// widgets) in a reusable fashion. /// /// [`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 /// widget. These IDs are used when configuring custom tab orders, so if your /// widget or any of its children aren't focusable, implementing [`MakeWidget`] @@ -60,10 +60,10 @@ fn callback_widget() -> impl MakeWidgetWithId { #[derive(Default)] struct ToggleMakeWidget(Toggle); -impl MakeWidgetWithId for ToggleMakeWidget { - fn make_with_id(self, id: WidgetTag) -> WidgetInstance { +impl MakeWidgetWithTag for ToggleMakeWidget { + fn make_with_tag(self, id: WidgetTag) -> WidgetInstance { // 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 /// most power and flexibility. -fn impl_widget() -> impl MakeWidgetWithId { +fn impl_widget() -> impl MakeWidgetWithTag { Toggle::default() } @@ -91,7 +91,7 @@ impl Default for Toggle { impl Widget for Toggle { 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( diff --git a/examples/focus-order.rs b/examples/focus-order.rs index 675b0b4..4f0a25a 100644 --- a/examples/focus-order.rs +++ b/examples/focus-order.rs @@ -1,7 +1,7 @@ use std::process::exit; 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::input::{InputValue, MaskedString}; use gooey::widgets::Expand; @@ -24,7 +24,7 @@ fn main() -> gooey::Result { let username_row = ( "Username", - username.clone().into_input().make_with_id(username_tag), + username.clone().into_input().make_with_tag(username_tag), ); let password_row = ( @@ -38,7 +38,7 @@ fn main() -> gooey::Result { eprintln!("Login cancelled"); exit(0) }) - .make_with_id(cancel_tag) + .make_with_tag(cancel_tag) .into_escape() .with_next_focus(username_id) .and(Expand::empty()) @@ -49,7 +49,7 @@ fn main() -> gooey::Result { println!("Welcome, {}", username.get()); exit(0); }) - .make_with_id(login_tag) + .make_with_tag(login_tag) .with_enabled(valid) .into_default() .with_next_focus(cancel_id), diff --git a/examples/overlays.rs b/examples/overlays.rs index 3b27225..1dd1f54 100644 --- a/examples/overlays.rs +++ b/examples/overlays.rs @@ -1,6 +1,6 @@ use std::panic::UnwindSafe; -use gooey::widget::{MakeWidget, MakeWidgetWithId, WidgetTag}; +use gooey::widget::{MakeWidget, MakeWidgetWithTag, WidgetTag}; use gooey::widgets::container::ContainerShadow; use gooey::widgets::layers::{OverlayBuilder, OverlayLayer}; 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( diff --git a/src/context.rs b/src/context.rs index 14e9e87..0aa0fb0 100644 --- a/src/context.rs +++ b/src/context.rs @@ -25,7 +25,7 @@ use crate::styles::{ComponentDefinition, Styles, Theme, ThemePair}; use crate::utils::IgnorePoison; use crate::value::{IntoValue, Value}; use crate::widget::{ - EventHandling, ManagedWidget, RootBehavior, WidgetId, WidgetInstance, WidgetRef, + EventHandling, MountedWidget, RootBehavior, WidgetId, WidgetInstance, WidgetRef, }; use crate::window::{CursorState, RunningWindow, ThemeMode}; 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 { + fn next_focus_after(&mut self, mut focus: MountedWidget, advance: bool) -> Option { // First, look within the current focus for any focusable children. let stop_at = focus.id(); 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( &mut self, - focus: &ManagedWidget, + focus: &MountedWidget, stop_at: WidgetId, advance: bool, ) -> Option { @@ -387,7 +387,7 @@ impl<'context, 'window> EventContext<'context, 'window> { /// that returns true from `accept_focus`. fn next_focus_within( &mut self, - focus: &ManagedWidget, + focus: &MountedWidget, start_at: Option, stop_at: WidgetId, advance: bool, @@ -782,7 +782,7 @@ impl<'context, 'window, 'clip, 'gfx, 'pass> LayoutContext<'context, 'window, 'cl /// Sets the layout for `child` to `layout`. /// /// `layout` is relative to the current widget's controls. - pub fn set_child_layout(&mut self, child: &ManagedWidget, layout: Rect) { + pub fn set_child_layout(&mut self, child: &MountedWidget, layout: Rect) { // TODO verify that `child` belongs to the current node. if self.persist_layout { child.set_layout(layout); @@ -824,7 +824,7 @@ pub trait AsEventContext<'window> { /// Pushes a new child widget into the widget hierarchy beneathq the /// context's widget. #[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 pushed_widget = context .current_node @@ -838,7 +838,7 @@ pub trait AsEventContext<'window> { } /// 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(); child .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 /// specific widget. pub struct WidgetContext<'context, 'window> { - current_node: ManagedWidget, + current_node: MountedWidget, redraw_status: &'context InvalidationStatus, window: &'context mut RunningWindow<'window>, theme: Cow<'context, ThemePair>, @@ -880,7 +880,7 @@ pub struct WidgetContext<'context, 'window> { impl<'context, 'window> WidgetContext<'context, 'window> { pub(crate) fn new( - current_node: ManagedWidget, + current_node: MountedWidget, redraw_status: &'context InvalidationStatus, theme: &'context ThemePair, window: &'context mut RunningWindow<'window>, @@ -942,12 +942,12 @@ impl<'context, 'window> WidgetContext<'context, 'window> { widget.manage(self).map(|current_node| { let (effective_styles, theme, theme_mode) = current_node.overidden_theme(); let theme = if let Some(theme) = theme { - Cow::Owned(theme.get_tracked(self)) + Cow::Owned(theme.get_tracking_redraw(self)) } else { Cow::Borrowed(self.theme.as_ref()) }; let theme_mode = if let Some(mode) = theme_mode { - mode.get_tracked(self) + mode.get_tracking_redraw(self) } else { self.cache.theme_mode }; @@ -981,7 +981,7 @@ impl<'context, 'window> WidgetContext<'context, 'window> { self.cache.enabled } - pub(crate) fn parent(&self) -> Option { + pub(crate) fn parent(&self) -> Option { self.current_node.parent() } @@ -1096,7 +1096,7 @@ impl<'context, 'window> WidgetContext<'context, 'window> { #[must_use] pub fn focused(&self, check_window: bool) -> bool { 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 @@ -1123,7 +1123,7 @@ impl<'context, 'window> WidgetContext<'context, 'window> { /// Returns the widget this context is for. #[must_use] - pub const fn widget(&self) -> &ManagedWidget { + pub const fn widget(&self) -> &MountedWidget { &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 { - /// The managed type, which can be `Option` or - /// `ManagedWidget`. - type Managed: MapManagedWidget; + /// The managed type, which can be `Option` or + /// `MountedWidget`. + type Managed: MapManagedWidget; - /// Resolve `self` into a [`ManagedWidget`]. + /// Resolve `self` into a [`MountedWidget`]. fn manage(&self, context: &WidgetContext<'_, '_>) -> Self::Managed; } impl ManageWidget for WidgetId { - type Managed = Option; + type Managed = Option; fn manage(&self, context: &WidgetContext<'_, '_>) -> Self::Managed { context.current_node.tree.widget(*self) @@ -1334,7 +1334,7 @@ impl ManageWidget for WidgetId { } impl ManageWidget for WidgetInstance { - type Managed = Option; + type Managed = Option; fn manage(&self, context: &WidgetContext<'_, '_>) -> Self::Managed { context.current_node.tree.widget(self.id()) @@ -1342,7 +1342,7 @@ impl ManageWidget for WidgetInstance { } impl ManageWidget for WidgetRef { - type Managed = Option; + type Managed = Option; fn manage(&self, context: &WidgetContext<'_, '_>) -> Self::Managed { match self { @@ -1352,7 +1352,7 @@ impl ManageWidget for WidgetRef { } } -impl ManageWidget for ManagedWidget { +impl ManageWidget for MountedWidget { type Managed = Self; 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 { /// The result of the mapping operation. type Result; - /// Call `map` with a [`ManagedWidget`]. - fn map(self, map: impl FnOnce(ManagedWidget) -> T) -> Self::Result; + /// Call `map` with a [`MountedWidget`]. + fn map(self, map: impl FnOnce(MountedWidget) -> T) -> Self::Result; } -impl MapManagedWidget for Option { +impl MapManagedWidget for Option { type Result = Option; - fn map(self, map: impl FnOnce(ManagedWidget) -> T) -> Self::Result { + fn map(self, map: impl FnOnce(MountedWidget) -> T) -> Self::Result { self.map(map) } } -impl MapManagedWidget for ManagedWidget { +impl MapManagedWidget for MountedWidget { 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) } } diff --git a/src/lib.rs b/src/lib.rs index bb8936f..65a7bce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -125,24 +125,6 @@ pub trait Run: Sized { 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. /// /// This is used inside of Gooey macros to preallocate collections. diff --git a/src/tree.rs b/src/tree.rs index 6de8f36..74860b6 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -10,7 +10,7 @@ use crate::context::sealed::WindowHandle; use crate::styles::{Styles, ThemePair, VisualOrder}; use crate::utils::IgnorePoison; use crate::value::Value; -use crate::widget::{ManagedWidget, WidgetId, WidgetInstance}; +use crate::widget::{MountedWidget, WidgetId, WidgetInstance}; use crate::window::ThemeMode; use crate::ConstraintLimit; @@ -23,8 +23,8 @@ impl Tree { pub fn push_boxed( &self, widget: WidgetInstance, - parent: Option<&ManagedWidget>, - ) -> ManagedWidget { + parent: Option<&MountedWidget>, + ) -> MountedWidget { let mut data = self.data.lock().ignore_poison(); let id = widget.id(); let (effective_styles, parent_id) = if let Some(parent) = parent { @@ -60,14 +60,14 @@ impl Tree { if let Some(next_focus) = widget.next_focus() { data.previous_focuses.insert(next_focus, id); } - ManagedWidget { + MountedWidget { node_id, widget, 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(); data.remove_child(child.node_id, parent.node_id); @@ -163,11 +163,11 @@ impl Tree { &self, parent: LotId, order: VisualOrder, - ) -> Vec { + ) -> Vec { let data = self.data.lock().ignore_poison(); let node = &data.nodes[parent]; let mut unordered = node.children.clone(); - let mut ordered = Vec::::with_capacity(unordered.len()); + let mut ordered = Vec::::with_capacity(unordered.len()); loop { // 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(); @@ -225,13 +225,13 @@ impl Tree { 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 hovered = new_hover .map(|new_hover| data.widget_hierarchy(new_hover.node_id, self)) .unwrap_or_default(); 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 }) { Ok(Some(old_hover)) => { @@ -250,12 +250,12 @@ impl Tree { HoverResults { unhovered, hovered } } - pub fn focus(&self, new_focus: Option) -> Result, ()> { + pub fn focus(&self, new_focus: Option) -> Result, ()> { let mut data = self.data.lock().ignore_poison(); data.update_tracked_widget(new_focus, self, |data| &mut data.focus) } - pub fn previous_focus(&self, focus: WidgetId) -> Option { + pub fn previous_focus(&self, focus: WidgetId) -> Option { let data = self.data.lock().ignore_poison(); let previous = *data.previous_focuses.get(&focus)?; data.widget_from_id(previous, self) @@ -263,20 +263,20 @@ impl Tree { pub fn activate( &self, - new_active: Option<&ManagedWidget>, - ) -> Result, ()> { + new_active: Option<&MountedWidget>, + ) -> Result, ()> { 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 }) } - pub fn widget(&self, id: WidgetId) -> Option { + pub fn widget(&self, id: WidgetId) -> Option { let data = self.data.lock().ignore_poison(); data.widget_from_id(id, self) } - pub(crate) fn widget_from_node(&self, id: LotId) -> Option { + pub(crate) fn widget_from_node(&self, id: LotId) -> Option { let data = self.data.lock().ignore_poison(); data.widget_from_node(id, self) } @@ -333,7 +333,7 @@ impl Tree { self.data.lock().ignore_poison().focus } - pub(crate) fn widgets_under_point(&self, point: Point) -> Vec { + pub(crate) fn widgets_under_point(&self, point: Point) -> Vec { let data = self.data.lock().ignore_poison(); data.render_info.widgets_under_point(point, &data, self) } @@ -398,8 +398,8 @@ impl Tree { } pub(crate) struct HoverResults { - pub unhovered: Vec, - pub hovered: Vec, + pub unhovered: Vec, + pub hovered: Vec, } #[derive(Default)] @@ -416,17 +416,17 @@ struct TreeData { } impl TreeData { - fn widget_from_id(&self, id: WidgetId, tree: &Tree) -> Option { + fn widget_from_id(&self, id: WidgetId, tree: &Tree) -> Option { let node_id = *self.nodes_by_id.get(&id)?; - Some(ManagedWidget { + Some(MountedWidget { node_id, widget: self.nodes[node_id].widget.clone(), tree: tree.clone(), }) } - fn widget_from_node(&self, node_id: LotId, tree: &Tree) -> Option { - Some(ManagedWidget { + fn widget_from_node(&self, node_id: LotId, tree: &Tree) -> Option { + Some(MountedWidget { node_id, widget: self.nodes.get(node_id)?.widget.clone(), tree: tree.clone(), @@ -489,7 +489,7 @@ impl TreeData { } } - pub(crate) fn widget_hierarchy(&self, mut widget: LotId, tree: &Tree) -> Vec { + pub(crate) fn widget_hierarchy(&self, mut widget: LotId, tree: &Tree) -> Vec { let mut hierarchy = Vec::new(); while let Some(managed) = self.widget_from_node(widget, tree) { hierarchy.push(managed); @@ -509,7 +509,7 @@ impl TreeData { new_widget: Option, tree: &Tree, property: impl FnOnce(&mut Self) -> &mut Option, - ) -> Result, ()> { + ) -> Result, ()> { let new_widget = new_widget.and_then(|w| self.widget_from_id(w, tree)); match ( mem::replace(property(self), new_widget.as_ref().map(|w| w.node_id)), @@ -555,7 +555,7 @@ impl RenderInfo { point: Point, tree_data: &TreeData, tree: &Tree, - ) -> Vec { + ) -> Vec { // We pessimistically allocate a vector as if all widgets match, up to a // reasonable limit. This should ensure minimal allocations in all but // extreme circumstances where widgets are nested with a significant diff --git a/src/value.rs b/src/value.rs index 0e37595..879098b 100644 --- a/src/value.rs +++ b/src/value.rs @@ -22,7 +22,7 @@ use crate::animation::{AnimationHandle, DynamicTransition, IntoAnimate, LinearIn use crate::context::sealed::WindowHandle; use crate::context::{self, WidgetContext}; 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}; /// An instance of a value that provides APIs to observe and react to its @@ -377,7 +377,7 @@ impl Dynamic { /// This function panics if this value is already locked by the current /// thread. #[must_use] - pub fn get_tracking_refresh(&self, context: &WidgetContext<'_, '_>) -> T + pub fn get_tracking_redraw(&self, context: &WidgetContext<'_, '_>) -> T where T: Clone, { @@ -638,20 +638,20 @@ impl Dynamic { } } -impl MakeWidgetWithId for Dynamic { - fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { - self.into_switcher().make_with_id(id) +impl MakeWidgetWithTag for Dynamic { + fn make_with_tag(self, id: crate::widget::WidgetTag) -> WidgetInstance { + self.into_switcher().make_with_tag(id) } } -impl MakeWidgetWithId for Dynamic> { - fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { +impl MakeWidgetWithTag for Dynamic> { + fn make_with_tag(self, id: crate::widget::WidgetTag) -> WidgetInstance { self.map_each(|widget| { widget .as_ref() .map_or_else(|| Space::clear().make_widget(), Clone::clone) }) - .make_with_id(id) + .make_with_tag(id) } } @@ -1260,7 +1260,7 @@ impl DynamicReader { /// This function panics if this value is already locked by the current /// thread. #[must_use] - pub fn get_tracking_refresh(&mut self, context: &WidgetContext<'_, '_>) -> T + pub fn get_tracking_redraw(&mut self, context: &WidgetContext<'_, '_>) -> T where T: Clone, { @@ -1649,7 +1649,7 @@ impl Value { /// /// If `self` is a dynamic, `context` will be refreshed when the value is /// updated. - pub fn get_tracked(&self, context: &WidgetContext<'_, '_>) -> T + pub fn get_tracking_redraw(&self, context: &WidgetContext<'_, '_>) -> T where T: Clone, { diff --git a/src/widget.rs b/src/widget.rs index 0291a24..0844a33 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -52,25 +52,214 @@ use crate::{ConstraintLimit, Run}; /// This type can go by many names in other UI frameworks: View, Component, /// 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 /// -/// 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 /// -/// 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 /// -/// 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 /// -/// 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 { /// Redraw the contents of this widget. 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 /// [`WidgetId`]. -pub trait MakeWidgetWithId: Sized { - /// Returns a new [`WidgetInstance`] whose [`WidgetId`] is `id`. - fn make_with_id(self, id: WidgetTag) -> WidgetInstance; +pub trait MakeWidgetWithTag: Sized { + /// Returns a new [`WidgetInstance`] whose [`WidgetId`] comes from `tag`. + fn make_with_tag(self, tag: WidgetTag) -> WidgetInstance; } -impl MakeWidgetWithId for T +impl MakeWidgetWithTag for T where T: Widget, { - fn make_with_id(self, id: WidgetTag) -> WidgetInstance { + fn make_with_tag(self, id: WidgetTag) -> WidgetInstance { WidgetInstance::with_id(self, id) } } impl MakeWidget for T where - T: MakeWidgetWithId, + T: MakeWidgetWithTag, { 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 { - fn make_with_id(self, id: WidgetTag) -> WidgetInstance { - Space::colored(self).make_with_id(id) +impl MakeWidgetWithTag for Color { + fn make_with_tag(self, id: WidgetTag) -> WidgetInstance { + Space::colored(self).make_with_tag(id) } } @@ -1490,19 +1679,19 @@ where /// A [`Widget`] that has been attached to a widget hierarchy. #[derive(Clone)] -pub struct ManagedWidget { +pub struct MountedWidget { pub(crate) node_id: LotId, pub(crate) widget: WidgetInstance, pub(crate) tree: Tree, } -impl Debug for ManagedWidget { +impl Debug for MountedWidget { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { Debug::fmt(&self.widget, f) } } -impl ManagedWidget { +impl MountedWidget { /// Locks the widget for exclusive access. Locking widgets should only be /// done for brief moments of time when you are certain no deadlocks can /// occur due to other widget locks being held. @@ -1537,7 +1726,7 @@ impl ManagedWidget { /// This function returns the value set in /// [`MakeWidget::with_next_focus()`]. #[must_use] - pub fn next_focus(&self) -> Option { + pub fn next_focus(&self) -> Option { self.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 /// automatically using [`MakeWidget::with_next_focus()`]. #[must_use] - pub fn previous_focus(&self) -> Option { + pub fn previous_focus(&self) -> Option { self.tree.previous_focus(self.id()) } /// Returns the next or previous focus target, if one was set using /// [`MakeWidget::with_next_focus()`]. #[must_use] - pub fn explicit_focus_target(&self, advance: bool) -> Option { + pub fn explicit_focus_target(&self, advance: bool) -> Option { if advance { self.next_focus() } else { @@ -1605,7 +1794,7 @@ impl ManagedWidget { /// Returns the parent of this widget. #[must_use] - pub fn parent(&self) -> Option { + pub fn parent(&self) -> Option { self.tree .parent(self.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); } - pub(crate) fn visually_ordered_children(&self, order: VisualOrder) -> Vec { + pub(crate) fn visually_ordered_children(&self, order: VisualOrder) -> Vec { self.tree.visually_ordered_children(self.node_id, order) } } -impl AsRef for ManagedWidget { +impl AsRef for MountedWidget { fn as_ref(&self) -> &WidgetId { self.widget.as_ref() } } -impl PartialEq for ManagedWidget { +impl PartialEq for MountedWidget { fn eq(&self, other: &Self) -> bool { self.widget == other.widget } } -impl PartialEq for ManagedWidget { +impl PartialEq for MountedWidget { fn eq(&self, other: &WidgetInstance) -> bool { &self.widget == other } @@ -1915,7 +2104,7 @@ pub enum ChildrenSyncChange { /// contain multiple children widgets. It is used in conjunction with a /// `Value`. #[derive(Debug)] -pub struct MountedChildren { +pub struct MountedChildren { generation: Option, children: Vec, } @@ -1990,23 +2179,23 @@ impl Default for MountedChildren { /// A child in a [`MountedChildren`] collection. pub trait MountableChild: Sized { /// Returns the mounted representation of `widget`. - fn mount(widget: ManagedWidget, into: &MountedChildren, index: usize) -> Self; + fn mount(widget: MountedWidget, into: &MountedChildren, index: usize) -> Self; /// 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. - fn widget(&self) -> &ManagedWidget; + fn widget(&self) -> &MountedWidget; } -impl MountableChild for ManagedWidget { - fn mount(widget: ManagedWidget, _into: &MountedChildren, _index: usize) -> Self { +impl MountableChild for MountedWidget { + fn mount(widget: MountedWidget, _into: &MountedChildren, _index: usize) -> Self { widget } - fn widget(&self) -> &ManagedWidget { + fn widget(&self) -> &MountedWidget { self } - fn unmount(self) -> ManagedWidget { + fn unmount(self) -> MountedWidget { self } } @@ -2017,7 +2206,7 @@ pub enum WidgetRef { /// An unmounted child widget Unmounted(WidgetInstance), /// A mounted child widget - Mounted(ManagedWidget), + Mounted(MountedWidget), } impl WidgetRef { @@ -2037,7 +2226,7 @@ impl WidgetRef { pub fn mounted<'window>( &mut self, context: &mut impl AsEventContext<'window>, - ) -> ManagedWidget { + ) -> MountedWidget { self.mount_if_needed(context); let Self::Mounted(widget) = self else { @@ -2101,14 +2290,14 @@ impl WidgetId { /// Finds this widget mounted in this window, if present. #[must_use] - pub fn find_in(self, context: &WidgetContext<'_, '_>) -> Option { + pub fn find_in(self, context: &WidgetContext<'_, '_>) -> Option { context.widget().tree.widget(self) } } /// 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. /// /// This type cannot be cloned or copied to ensure only a single widget can be diff --git a/src/widgets/button.rs b/src/widgets/button.rs index 859c676..a2c83c4 100644 --- a/src/widgets/button.rs +++ b/src/widgets/button.rs @@ -226,7 +226,7 @@ impl Button { } 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); self.cached_state = CacheState { @@ -352,7 +352,7 @@ impl Widget for Button { fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) { #![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 { self.update_colors(context, false); } diff --git a/src/widgets/checkbox.rs b/src/widgets/checkbox.rs index a66d0d7..04eb69f 100644 --- a/src/widgets/checkbox.rs +++ b/src/widgets/checkbox.rs @@ -11,7 +11,7 @@ use crate::context::{GraphicsContext, LayoutContext}; use crate::styles::components::{LineHeight, OutlineColor, TextColor, WidgetAccentColor}; use crate::styles::Dimension; 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::ConstraintLimit; @@ -51,8 +51,8 @@ impl Checkbox { } } -impl MakeWidgetWithId for Checkbox { - fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { +impl MakeWidgetWithTag for Checkbox { + fn make_with_tag(self, id: crate::widget::WidgetTag) -> WidgetInstance { CheckboxOrnament { value: self.state.create_reader(), } @@ -64,7 +64,7 @@ impl MakeWidgetWithId for Checkbox { *value = !*value; }) .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()); - match self.value.get_tracking_refresh(context) { + match self.value.get_tracking_redraw(context) { state @ (CheckboxState::Checked | CheckboxState::Indeterminant) => { let color = context.get(&WidgetAccentColor); context diff --git a/src/widgets/color.rs b/src/widgets/color.rs index 7bc7745..d69792c 100644 --- a/src/widgets/color.rs +++ b/src/widgets/color.rs @@ -73,7 +73,7 @@ impl Widget for ColorSourcePicker { let loupe_size = Lp::mm(3).into_px(context.gfx.scale()); 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 + Point::new( if self.hue_is_360 { @@ -84,7 +84,7 @@ impl Widget for ColorSourcePicker { 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 outline_color = if context.focused(true) { diff --git a/src/widgets/custom.rs b/src/widgets/custom.rs index 2f60f18..d7966f1 100644 --- a/src/widgets/custom.rs +++ b/src/widgets/custom.rs @@ -544,7 +544,9 @@ impl WrapperWidget for Custom { } fn background_color(&mut self, context: &WidgetContext<'_, '_>) -> Option { - 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<'_, '_>) { diff --git a/src/widgets/grid.rs b/src/widgets/grid.rs index 439a377..dcecf60 100644 --- a/src/widgets/grid.rs +++ b/src/widgets/grid.rs @@ -16,7 +16,7 @@ use crate::context::{AsEventContext, EventContext, GraphicsContext, LayoutContex use crate::styles::components::IntrinsicPadding; use crate::styles::Dimension; use crate::value::{Generation, IntoValue, Value}; -use crate::widget::{MakeWidget, ManagedWidget, Widget, WidgetInstance}; +use crate::widget::{MakeWidget, MountedWidget, Widget, WidgetInstance}; use crate::ConstraintLimit; /// A 2D grid of widgets. @@ -24,7 +24,7 @@ use crate::ConstraintLimit; pub struct Grid { columns: Value<[GridDimension; ELEMENTS]>, rows: Value>, - live_rows: Vec<[ManagedWidget; ELEMENTS]>, + live_rows: Vec<[MountedWidget; ELEMENTS]>, layout: GridLayout, layout_generation: Option, spec_generation: Option, diff --git a/src/widgets/input.rs b/src/widgets/input.rs index aab1f9b..c513f37 100644 --- a/src/widgets/input.rs +++ b/src/widgets/input.rs @@ -1019,7 +1019,7 @@ where } 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.blink_state.force_on(); diff --git a/src/widgets/label.rs b/src/widgets/label.rs index 5140cda..9ad3815 100644 --- a/src/widgets/label.rs +++ b/src/widgets/label.rs @@ -94,9 +94,9 @@ impl Widget for Label { macro_rules! impl_make_widget { ($($type:ty),*) => { - $(impl crate::widget::MakeWidgetWithId for $type { - fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { - Label::new(self).make_with_id(id) + $(impl crate::widget::MakeWidgetWithTag for $type { + fn make_with_tag(self, id: crate::widget::WidgetTag) -> WidgetInstance { + Label::new(self).make_with_tag(id) } })* }; diff --git a/src/widgets/layers.rs b/src/widgets/layers.rs index fd1a8f9..f543a0c 100644 --- a/src/widgets/layers.rs +++ b/src/widgets/layers.rs @@ -16,7 +16,7 @@ use crate::context::{AsEventContext, EventContext, GraphicsContext, LayoutContex use crate::utils::IgnorePoison; use crate::value::{Dynamic, DynamicGuard, IntoValue, Value}; use crate::widget::{ - Callback, Children, MakeWidget, ManagedWidget, MountedChildren, Widget, WidgetId, WidgetRef, + Callback, Children, MakeWidget, MountedChildren, MountedWidget, Widget, WidgetId, WidgetRef, WrapperWidget, }; use crate::widgets::container::ContainerShadow; @@ -182,7 +182,7 @@ impl Widget for OverlayLayer { continue; }; - let opacity = child.opacity.get_tracking_refresh(context); + let opacity = child.opacity.get_tracking_redraw(context); let mut context = context.for_other(mounted); context.apply_opacity(opacity); context.redraw(); @@ -376,7 +376,7 @@ impl OverlayState { fn layout_overlay_relative( &mut self, index: usize, - widget: &ManagedWidget, + widget: &MountedWidget, available_space: Size, context: &mut LayoutContext<'_, '_, '_, '_, '_>, relative_to: WidgetId, @@ -495,7 +495,7 @@ impl OverlayState { fn layout_overlay( &mut self, index: usize, - widget: &ManagedWidget, + widget: &MountedWidget, available_space: Size, context: &mut LayoutContext<'_, '_, '_, '_, '_>, ) -> Option> { diff --git a/src/widgets/progress.rs b/src/widgets/progress.rs index 07c8db3..99792eb 100644 --- a/src/widgets/progress.rs +++ b/src/widgets/progress.rs @@ -13,7 +13,7 @@ use crate::animation::{ AnimationHandle, AnimationTarget, IntoAnimate, PercentBetween, Spawn, ZeroToOne, }; 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::Data; @@ -60,8 +60,8 @@ pub enum Progress { Percent(T), } -impl MakeWidgetWithId for ProgressBar { - fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { +impl MakeWidgetWithTag for ProgressBar { + fn make_with_tag(self, id: crate::widget::WidgetTag) -> WidgetInstance { let start = Dynamic::new(ZeroToOne::ZERO); let end = Dynamic::new(ZeroToOne::ZERO); let value = (&start, &end).map_each(|(start, end)| *start..=*end); @@ -76,12 +76,16 @@ impl MakeWidgetWithId for ProgressBar { end: end.clone(), degree_offset: degree_offset.clone(), } - .make_with_id(id), + .make_with_tag(id), Some(degree_offset), ) } else { ( - value.slider().knobless().non_interactive().make_with_id(id), + value + .slider() + .knobless() + .non_interactive() + .make_with_tag(id), None, ) }; @@ -332,8 +336,8 @@ impl Spinner { impl Widget for Spinner { fn redraw(&mut self, context: &mut crate::context::GraphicsContext<'_, '_, '_, '_, '_>) { let track_size = context.get(&TrackSize).into_px(context.gfx.scale()); - let start = self.start.get_tracking_refresh(context); - let end = self.end.get_tracking_refresh(context); + let start = self.start.get_tracking_redraw(context); + let end = self.end.get_tracking_redraw(context); let size = context.gfx.region().size; let render_size = size.width.min(size.height); let radius = render_size / 2 - track_size; diff --git a/src/widgets/radio.rs b/src/widgets/radio.rs index 2269e46..062e3b9 100644 --- a/src/widgets/radio.rs +++ b/src/widgets/radio.rs @@ -11,7 +11,7 @@ use crate::context::{GraphicsContext, LayoutContext}; use crate::styles::components::{LineHeight, OutlineColor, WidgetAccentColor}; use crate::styles::Dimension; 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::ConstraintLimit; @@ -51,11 +51,11 @@ impl Radio { } } -impl MakeWidgetWithId for Radio +impl MakeWidgetWithTag for Radio where 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 { value: self.value.clone(), state: self.state.create_reader(), @@ -67,7 +67,7 @@ where self.state.set(self.value.clone()); }) .kind(self.kind) - .make_with_id(id) + .make_with_tag(id) } } diff --git a/src/widgets/select.rs b/src/widgets/select.rs index 671de04..ed416ff 100644 --- a/src/widgets/select.rs +++ b/src/widgets/select.rs @@ -7,7 +7,7 @@ use kludgine::Color; use crate::styles::components::OutlineColor; use crate::styles::{Component, DynamicComponent}; 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}; /// A selectable, labeled widget representing a value. @@ -46,11 +46,11 @@ impl Select { } } -impl MakeWidgetWithId for Select +impl MakeWidgetWithTag for Select where 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 value = self.value.clone(); move |state| state == &value @@ -58,7 +58,7 @@ where let selected_color = DynamicComponent::new({ let selected = selected.clone(); move |context| { - if selected.get_tracking_refresh(context) { + if selected.get_tracking_redraw(context) { Some(Component::Color(context.get(&SelectedColor))) } else { None @@ -80,7 +80,7 @@ where .kind(kind) .with_dynamic(&ButtonBackground, selected_color.clone()) .with_dynamic(&ButtonHoverBackground, selected_color) - .make_with_id(id) + .make_with_tag(id) } } diff --git a/src/widgets/slider.rs b/src/widgets/slider.rs index 2225956..a42c207 100644 --- a/src/widgets/slider.rs +++ b/src/widgets/slider.rs @@ -443,9 +443,9 @@ where let half_knob = knob_size / 2; let (mut start_value, mut end_value) = - T::into_parts(self.value.get_tracking_refresh(context)); - let min = self.minimum.get_tracked(context); - let mut max = self.maximum.get_tracked(context); + T::into_parts(self.value.get_tracking_redraw(context)); + let min = self.minimum.get_tracking_redraw(context); + let mut max = self.maximum.get_tracking_redraw(context); if max < min { self.maximum.map_mut(|max| *max = min.clone()); diff --git a/src/widgets/space.rs b/src/widgets/space.rs index b0de0fb..f7b9cdd 100644 --- a/src/widgets/space.rs +++ b/src/widgets/space.rs @@ -39,7 +39,7 @@ impl Space { impl Widget for Space { 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); } diff --git a/src/widgets/stack.rs b/src/widgets/stack.rs index bffd1f5..cb9893d 100644 --- a/src/widgets/stack.rs +++ b/src/widgets/stack.rs @@ -7,7 +7,7 @@ use crate::context::{AsEventContext, EventContext, GraphicsContext, LayoutContex use crate::styles::components::IntrinsicPadding; use crate::styles::FlexibleDimension; 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::{Expand, Resize}; use crate::ConstraintLimit; @@ -24,7 +24,7 @@ pub struct Stack { layout: GridLayout, layout_generation: Option, // TODO Refactor synced_children into its own type. - synced_children: Vec, + synced_children: Vec, } impl Stack { @@ -68,7 +68,7 @@ impl Stack { self.children.map(|children| { children.synchronize_with( &mut self.synced_children, - |this, index| this.get(index).map(ManagedWidget::instance), + |this, index| this.get(index).map(MountedWidget::instance), |this, change| match change { ChildrenSyncChange::Insert(index, widget) => { // This is a brand new child. diff --git a/src/widgets/validated.rs b/src/widgets/validated.rs index 1139fcc..a7df260 100644 --- a/src/widgets/validated.rs +++ b/src/widgets/validated.rs @@ -9,7 +9,7 @@ use crate::styles::components::{ }; use crate::styles::Dimension; 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. /// @@ -46,8 +46,8 @@ impl Validated { } } -impl MakeWidgetWithId for Validated { - fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance { +impl MakeWidgetWithTag for Validated { + fn make_with_tag(self, id: crate::widget::WidgetTag) -> WidgetInstance { let message = match self.hint { Value::Constant(hint) => self .validation @@ -84,7 +84,7 @@ impl MakeWidgetWithId for Validated { error_color, default_color, } - .make_with_id(id) + .make_with_tag(id) } } diff --git a/src/window.rs b/src/window.rs index 803eacc..ba0c1e5 100644 --- a/src/window.rs +++ b/src/window.rs @@ -39,7 +39,7 @@ use crate::tree::Tree; use crate::utils::ModifiersExt; use crate::value::{Dynamic, DynamicReader, IntoDynamic, IntoValue, Value}; 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::{initialize_tracing, ConstraintLimit, Run}; @@ -338,7 +338,7 @@ pub trait WindowBehavior: Sized + 'static { struct GooeyWindow { behavior: T, - root: ManagedWidget, + root: MountedWidget, contents: Drawing, should_close: bool, cursor: CursorState, @@ -1221,7 +1221,7 @@ where fn recursively_handle_event( context: &mut EventContext<'_, '_>, mut each_widget: impl FnMut(&mut EventContext<'_, '_>) -> EventHandling, -) -> Option { +) -> Option { match each_widget(context) { HANDLED => Some(context.widget().clone()), IGNORED => context.parent().and_then(|parent| {