diff --git a/druid/src/app_delegate.rs b/druid/src/app_delegate.rs index ddeb484773..93cd52623f 100644 --- a/druid/src/app_delegate.rs +++ b/druid/src/app_delegate.rs @@ -33,7 +33,7 @@ impl<'a> DelegateCtx<'a> { /// the [`update()`] method is called. /// /// [`Command`]: struct.Command.html - /// [`update()`]: widget/trait.Widget.html#tymethod.update + /// [`update()`]: trait.Widget.html#tymethod.update pub fn submit_command( &mut self, command: impl Into, @@ -62,7 +62,7 @@ pub trait AppDelegate { /// be the event that was passed in, a different event, or no event. In all cases, /// the [`update()`] method will be called as usual. /// - /// [`update()`]: widget/trait.Widget.html#tymethod.update + /// [`update()`]: trait.Widget.html#tymethod.update fn event( &mut self, ctx: &mut DelegateCtx, diff --git a/druid/src/box_constraints.rs b/druid/src/box_constraints.rs index 65f7911d3f..ec21222c69 100644 --- a/druid/src/box_constraints.rs +++ b/druid/src/box_constraints.rs @@ -29,7 +29,7 @@ use log; /// Further, a container widget should compute appropriate constraints /// for each of its child widgets, and pass those down when recursing. /// -/// [`layout`]: widget/trait.Widget.html#tymethod.layout +/// [`layout`]: trait.Widget.html#tymethod.layout /// [Flutter BoxConstraints]: https://api.flutter.dev/flutter/rendering/BoxConstraints-class.html #[derive(Clone, Copy, Debug)] pub struct BoxConstraints { diff --git a/druid/src/contexts.rs b/druid/src/contexts.rs index ee9c6d3572..cccf599910 100644 --- a/druid/src/contexts.rs +++ b/druid/src/contexts.rs @@ -54,7 +54,7 @@ pub struct EventCtx<'a> { /// specific lifecycle events; for instance [`register_child`] /// should only be called while handling [`LifeCycle::WidgetAdded`]. /// -/// [`lifecycle`]: widget/trait.Widget.html#tymethod.lifecycle +/// [`lifecycle`]: trait.Widget.html#tymethod.lifecycle /// [`register_child`]: #method.register_child /// [`LifeCycle::WidgetAdded`]: enum.LifeCycle.html#variant.WidgetAdded pub struct LifeCycleCtx<'a> { @@ -133,7 +133,7 @@ impl<'a> EventCtx<'a> { /// Request a [`paint`] pass. /// - /// [`paint`]: widget/trait.Widget.html#tymethod.paint + /// [`paint`]: trait.Widget.html#tymethod.paint pub fn request_paint(&mut self) { self.base_state.needs_inval = true; } @@ -147,7 +147,7 @@ impl<'a> EventCtx<'a> { /// (such as if it would like to change the layout of children in /// response to some event) it must call this method. /// - /// [`layout`]: widget/trait.Widget.html#tymethod.layout + /// [`layout`]: trait.Widget.html#tymethod.layout pub fn request_layout(&mut self) { self.base_state.needs_layout = true; self.base_state.needs_inval = true; @@ -327,7 +327,7 @@ impl<'a> EventCtx<'a> { /// Generally it will be the same as the size returned by the child widget's /// [`layout`] method. /// - /// [`layout`]: widget/trait.Widget.html#tymethod.layout + /// [`layout`]: trait.Widget.html#tymethod.layout pub fn size(&self) -> Size { self.base_state.size() } @@ -339,7 +339,7 @@ impl<'a> EventCtx<'a> { /// the [`update`] method is called. /// /// [`Command`]: struct.Command.html - /// [`update`]: widget/trait.Widget.html#tymethod.update + /// [`update`]: trait.Widget.html#tymethod.update pub fn submit_command( &mut self, command: impl Into, @@ -376,7 +376,7 @@ impl<'a> LifeCycleCtx<'a> { /// Request a [`paint`] pass. /// - /// [`paint`]: widget/trait.Widget.html#tymethod.paint + /// [`paint`]: trait.Widget.html#tymethod.paint pub fn request_paint(&mut self) { self.base_state.needs_inval = true; } @@ -430,7 +430,7 @@ impl<'a> LifeCycleCtx<'a> { /// the [`update`] method is called. /// /// [`Command`]: struct.Command.html - /// [`update`]: widget/trait.Widget.html#tymethod.update + /// [`update`]: trait.Widget.html#tymethod.update pub fn submit_command( &mut self, command: impl Into, diff --git a/druid/src/core.rs b/druid/src/core.rs index 10072d872f..645222ce6c 100644 --- a/druid/src/core.rs +++ b/druid/src/core.rs @@ -40,7 +40,7 @@ pub(crate) type CommandQueue = VecDeque<(Target, Command)>; /// needs to propagate, and to provide the previous data so that a /// widget can process a diff between the old value and the new. /// -/// [`update`]: widget/trait.Widget.html#tymethod.update +/// [`update`]: trait.Widget.html#tymethod.update pub struct WidgetPod { state: BaseState, old_data: Option, @@ -61,7 +61,7 @@ pub struct WidgetPod { /// that, widgets will generally not interact with it directly, /// but it is an important part of the [`WidgetPod`] struct. /// -/// [`paint`]: widget/trait.Widget.html#tymethod.paint +/// [`paint`]: trait.Widget.html#tymethod.paint /// [`WidgetPod`]: struct.WidgetPod.html #[derive(Clone)] pub(crate) struct BaseState { @@ -218,7 +218,7 @@ impl> WidgetPod { /// /// [`Insets`]: struct.Insets.html /// [`set_paint_insets`]: struct.LayoutCtx.html#method.set_paint_insets - /// [`layout`]: widget/trait.Widget.html#tymethod.layout + /// [`layout`]: trait.Widget.html#tymethod.layout pub fn paint_insets(&self) -> Insets { self.state.paint_insets } @@ -231,7 +231,7 @@ impl> WidgetPod { /// propogate a child's desired paint rect, if it extends beyond the bounds /// of the parent's layout rect. /// - /// [`layout`]: widget/trait.Widget.html#tymethod.layout + /// [`layout`]: trait.Widget.html#tymethod.layout /// [`Insets`]: struct.Insets.html pub fn compute_parent_paint_insets(&self, parent_size: Size) -> Insets { let parent_bounds = Rect::ZERO.with_size(parent_size); @@ -249,8 +249,8 @@ impl> WidgetPod { /// Note that this method does not apply the offset of the layout rect. /// If that is desired, use [`paint_with_offset`] instead. /// - /// [`layout`]: widget/trait.Widget.html#tymethod.layout - /// [`paint`]: widget/trait.Widget.html#tymethod.paint + /// [`layout`]: trait.Widget.html#tymethod.layout + /// [`paint`]: trait.Widget.html#tymethod.paint /// [`paint_with_offset`]: #method.paint_with_offset pub fn paint(&mut self, ctx: &mut PaintCtx, data: &T, env: &Env) { let mut inner_ctx = PaintCtx { @@ -315,7 +315,7 @@ impl> WidgetPod { /// Generally called by container widgets as part of their [`layout`] /// method. /// - /// [`layout`]: widget/trait.Widget.html#tymethod.layout + /// [`layout`]: trait.Widget.html#tymethod.layout pub fn layout( &mut self, layout_ctx: &mut LayoutCtx, @@ -348,7 +348,7 @@ impl> WidgetPod { /// flow logic resides, particularly whether to continue propagating /// the event. /// - /// [`event`]: widget/trait.Widget.html#tymethod.event + /// [`event`]: trait.Widget.html#tymethod.event pub fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut T, env: &Env) { if self.old_data.is_none() { log::error!( @@ -571,7 +571,7 @@ impl> WidgetPod { /// Generally called by container widgets as part of their [`update`] /// method. /// - /// [`update`]: widget/trait.Widget.html#tymethod.update + /// [`update`]: trait.Widget.html#tymethod.update pub fn update(&mut self, ctx: &mut UpdateCtx, data: &T, env: &Env) { match (self.old_data.as_ref(), self.env.as_ref()) { (Some(d), Some(e)) if d.same(data) && e.same(env) => return, diff --git a/druid/src/env.rs b/druid/src/env.rs index 23b651ab7c..4efde0a9e9 100644 --- a/druid/src/env.rs +++ b/druid/src/env.rs @@ -117,7 +117,7 @@ impl Env { /// /// Set by the `debug_paint_layout()` method on [`WidgetExt`]'. /// - /// [`WidgetExt`]: widget/trait.WidgetExt.html + /// [`WidgetExt`]: trait.WidgetExt.html pub(crate) const DEBUG_PAINT: Key = Key::new("druid.built-in.debug-paint"); /// A key used to tell widgets to print additional debug information. @@ -140,7 +140,7 @@ impl Env { /// } /// ``` /// - /// [`WidgetExt::debug_widget`]: widget/trait.WidgetExt.html#method.debug_widget + /// [`WidgetExt::debug_widget`]: trait.WidgetExt.html#method.debug_widget pub const DEBUG_WIDGET: Key = Key::new("druid.built-in.debug-widget"); /// Gets a value from the environment, expecting it to be present. diff --git a/druid/src/event.rs b/druid/src/event.rs index c9f5742597..c90daaf26f 100644 --- a/druid/src/event.rs +++ b/druid/src/event.rs @@ -42,7 +42,7 @@ use crate::{Command, Target, WidgetId}; /// This enum is expected to grow considerably, as there are many, many /// different kinds of events that are relevant in a GUI. /// -/// [`event`]: widget/trait.Widget.html#tymethod.event +/// [`event`]: trait.Widget.html#tymethod.event /// [`WidgetPod`]: struct.WidgetPod.html #[derive(Debug, Clone)] pub enum Event { @@ -124,7 +124,7 @@ pub enum Event { /// [`Widget`]s, at runtime, with [`EventCtx::submit_command`]. /// /// [`Command`]: struct.Command.html - /// [`Widget`]: widget/trait.Widget.html + /// [`Widget`]: trait.Widget.html /// [`EventCtx::submit_command`]: struct.EventCtx.html#method.submit_command Command(Command), /// A command still in the process of being dispatched. This is an internal diff --git a/druid/src/lens.rs b/druid/src/lens/lens.rs similarity index 91% rename from druid/src/lens.rs rename to druid/src/lens/lens.rs index 27533f21cd..70a948ded3 100644 --- a/druid/src/lens.rs +++ b/druid/src/lens/lens.rs @@ -12,51 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Support for lenses, a way of focusing on subfields of data. -//! -//! Lenses are useful whenever a widget only needs access to a subfield of a larger struct or -//! generally access to part of a larger value. -//! -//! For example: If one wants to embed a [`TextBox`] in a widget with a `Data` type -//! that is not `String`, they need to specify how to access a `String` from within the `Data`. -//! -//! [`TextBox`]: ../widget/struct.TextBox.html -//! ``` -//! use druid::{Data, Lens, Widget, WidgetExt, widget::{TextBox, Flex}}; -//! -//! #[derive(Clone, Debug, Data, Lens)] -//! struct MyState { -//! search_term: String, -//! scale: f64, -//! // ... -//! } -//! -//! -//! fn my_sidebar() -> impl Widget { -//! // `TextBox` is of type `Widget` -//! // via `.lens` we get it to be of type `Widget`. -//! // `MyState::search_term` is a lens generated by the `derive(Lens)` macro, -//! // that provides access to the search_term field. -//! let searchbar = TextBox::new().lens(MyState::search_term); -//! -//! // ... -//! -//! // We can now use `searchbar` just like any other `Widget` -//! Flex::column().with_child(searchbar) -//! } -//! ``` - use std::marker::PhantomData; use std::ops; use std::sync::Arc; -pub use druid_derive::Lens; - use crate::kurbo::Size; -use crate::{ - BoxConstraints, Data, Env, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, - UpdateCtx, Widget, WidgetId, -}; +use crate::widget::prelude::*; +use crate::Data; /// A lens is a datatype that gives access to a part of a larger /// data structure. diff --git a/druid/src/lens/mod.rs b/druid/src/lens/mod.rs new file mode 100644 index 0000000000..fb7d0ef395 --- /dev/null +++ b/druid/src/lens/mod.rs @@ -0,0 +1,53 @@ +// Copyright 2020 The xi-editor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Support for lenses, a way of focusing on subfields of data. +//! +//! Lenses are useful whenever a widget only needs access to a subfield of a larger struct or +//! generally access to part of a larger value. +//! +//! For example: If one wants to embed a [`TextBox`] in a widget with a `Data` type +//! that is not `String`, they need to specify how to access a `String` from within the `Data`. +//! +//! [`TextBox`]: ../widget/struct.TextBox.html +//! ``` +//! use druid::{Data, Lens, Widget, WidgetExt, widget::{TextBox, Flex}}; +//! +//! #[derive(Clone, Debug, Data, Lens)] +//! struct MyState { +//! search_term: String, +//! scale: f64, +//! // ... +//! } +//! +//! +//! fn my_sidebar() -> impl Widget { +//! // `TextBox` is of type `Widget` +//! // via `.lens` we get it to be of type `Widget`. +//! // `MyState::search_term` is a lens generated by the `derive(Lens)` macro, +//! // that provides access to the search_term field. +//! let searchbar = TextBox::new().lens(MyState::search_term); +//! +//! // ... +//! +//! // We can now use `searchbar` just like any other `Widget` +//! Flex::column().with_child(searchbar) +//! } +//! ``` + +#[allow(clippy::module_inception)] +mod lens; +pub use lens::{Deref, Field, Id, InArc, Index, Map, Then}; +#[doc(hidden)] +pub use lens::{Lens, LensExt, LensWrap}; diff --git a/druid/src/lib.rs b/druid/src/lib.rs index 4d130bfb37..d064db7277 100644 --- a/druid/src/lib.rs +++ b/druid/src/lib.rs @@ -89,9 +89,9 @@ //! } //! ``` //! -//! [`Widget`]: widget/trait.Widget.html +//! [`Widget`]: trait.Widget.html //! [`Data`]: trait.Data.html -//! [`Lens`]: lens/trait.Lens.html +//! [`Lens`]: trait.Lens.html //! [`widget`]: ./widget/index.html //! [`Event`]: enum.Event.html //! [`druid-shell`]: https://docs.rs/druid-shell @@ -104,8 +104,10 @@ // Allows to use macros from druid_derive in this crate extern crate self as druid; +pub use druid_derive::Lens; use druid_shell as shell; +#[doc(inline)] pub use druid_shell::{kurbo, piet}; mod app; @@ -146,7 +148,7 @@ pub use app::{AppLauncher, WindowDesc}; pub use app_delegate::{AppDelegate, DelegateCtx}; pub use box_constraints::BoxConstraints; pub use command::{sys as commands, Command, Selector, Target}; -pub use contexts::{EventCtx, LayoutCtx, LifeCycleCtx, PaintCtx, UpdateCtx}; +pub use contexts::{EventCtx, LayoutCtx, LifeCycleCtx, PaintCtx, Region, UpdateCtx}; pub use data::Data; pub use env::{Env, Key, KeyOrValue, Value, ValueType}; pub use event::{Event, LifeCycle, WheelEvent}; diff --git a/druid/src/widget/click.rs b/druid/src/widget/click.rs index 8ef872ee3c..031a3e2a7a 100644 --- a/druid/src/widget/click.rs +++ b/druid/src/widget/click.rs @@ -32,7 +32,7 @@ use crate::{Data, Env, Event, EventCtx, LifeCycle, LifeCycleCtx, Widget}; /// /// [`Controller`]: struct.Controller.html /// [`ControllerHost`]: struct.ControllerHost.html -/// [`WidgetExt`]: trait.WidgetExt.html +/// [`WidgetExt`]: ../trait.WidgetExt.html /// [`Button`]: struct.Button.html /// [`LifeCycle::HotChanged`]: ../enum.LifeCycle.html#variant.HotChanged pub struct Click { diff --git a/druid/src/widget/controller.rs b/druid/src/widget/controller.rs index 2bc287c201..81e403a3a1 100644 --- a/druid/src/widget/controller.rs +++ b/druid/src/widget/controller.rs @@ -58,10 +58,10 @@ use crate::{ /// } /// ``` /// -/// [`Widget`]: trait.Widget.html +/// [`Widget`]: ../trait.Widget.html /// [`TextBox`]: struct.TextBox.html /// [`ControllerHost`]: struct.ControllerHost.html -/// [`WidgetExt::controller`]: trait.WidgetExt.html#tymethod.controller +/// [`WidgetExt::controller`]: ../trait.WidgetExt.html#tymethod.controller pub trait Controller> { fn event(&mut self, child: &mut W, ctx: &mut EventCtx, event: &Event, data: &mut T, env: &Env) { child.event(ctx, event, data, env) @@ -85,7 +85,7 @@ pub trait Controller> { /// A [`Widget`] that manages a child and a [`Controller`]. /// -/// [`Widget`]: trait.Widget.html +/// [`Widget`]: ../trait.Widget.html /// [`Controller`]: trait.Controller.html pub struct ControllerHost { widget: W, diff --git a/druid/src/widget/flex.rs b/druid/src/widget/flex.rs index 840bae591d..15aeaaa4d9 100644 --- a/druid/src/widget/flex.rs +++ b/druid/src/widget/flex.rs @@ -128,14 +128,14 @@ use crate::{ /// my_row.add_flex_child(Slider::new(), 1.0); /// ``` /// -/// [`layout`]: trait.Widget.html#tymethod.layout +/// [`layout`]: ../trait.Widget.html#tymethod.layout /// [`MainAxisAlignment`]: enum.MainAxisAlignment.html /// [`CrossAxisAlignment`]: enum.CrossAxisAlignment.html /// [`must_fill_main_axis`]: struct.Flex.html#method.must_fill_main_axis /// [`FlexParams`]: struct.FlexParams.html -/// [`WidgetExt`]: trait.WidgetExt.html -/// [`expand_height`]: trait.WidgetExt.html#method.expand_height -/// [`expand_width`]: trait.WidgetExt.html#method.expand_width +/// [`WidgetExt`]: ../trait.WidgetExt.html +/// [`expand_height`]: ../trait.WidgetExt.html#method.expand_height +/// [`expand_width`]: ../trait.WidgetExt.html#method.expand_width /// [`TextBox`]: struct.TextBox.html /// [`SizedBox`]: struct.SizedBox.html pub struct Flex { diff --git a/druid/src/widget/mod.rs b/druid/src/widget/mod.rs index 164d6a2eaa..ad30a28d67 100644 --- a/druid/src/widget/mod.rs +++ b/druid/src/widget/mod.rs @@ -46,6 +46,8 @@ mod svg; mod switch; mod textbox; mod view_switcher; +#[allow(clippy::module_inception)] +mod widget; mod widget_ext; #[cfg(feature = "image")] @@ -80,248 +82,45 @@ pub use svg::{Svg, SvgData}; pub use switch::Switch; pub use textbox::TextBox; pub use view_switcher::ViewSwitcher; +#[doc(hidden)] +pub use widget::{Widget, WidgetId}; +#[doc(hidden)] pub use widget_ext::WidgetExt; -use std::num::NonZeroU64; -use std::ops::{Deref, DerefMut}; - /// The types required to implement a `Widget`. -pub mod prelude { - pub use super::{Widget, WidgetId}; - pub use crate::{ - BoxConstraints, Env, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, - RenderContext, Size, UpdateCtx, - }; -} - -use prelude::*; - -/// A unique identifier for a single [`Widget`]. /// -/// `WidgetId`s are generated automatically for all widgets that participate -/// in layout. More specifically, each [`WidgetPod`] has a unique `WidgetId`. +/// # Structs +/// [`BoxConstraints`](../../struct.BoxConstraints.html) /// -/// These ids are used internally to route events, and can be used to communicate -/// between widgets, by submitting a command (as with [`EventCtx::submit_command`]) -/// and passing a `WidgetId` as the [`Target`]. +/// [`Env`](../../struct.Env.html) /// -/// A widget can retrieve its id via methods on the various contexts, such as -/// [`LifeCycleCtx::widget_id`]. +/// [`EventCtx`](../../struct.EventCtx.html) /// -/// ## Explicit `WidgetId`s. +/// [`LayoutCtx`](../../struct.LayoutCtx.html) /// -/// Sometimes, you may want to know a widget's id when constructing the widget. -/// You can give a widget an _explicit_ id by wrapping it in an [`IdentityWrapper`] -/// widget, or by using the [`WidgetExt::with_id`] convenience method. +/// [`LifeCycleCtx`](../../struct.LifeCycleCtx.html) /// -/// If you set a `WidgetId` directly, you are resposible for ensuring that it -/// is unique in time. That is: only one widget can exist with a given id at a -/// given time. +/// [`PaintCtx`](../../struct.PaintCtx.html) /// -/// [`Widget`]: trait.Widget.html -/// [`EventCtx::submit_command`]: ../struct.EventCtx.html#method.submit_command -/// [`Target`]: ../enum.Target.html -/// [`WidgetPod`]: ../struct.WidgetPod.html -/// [`LifeCycleCtx::widget_id`]: ../struct.LifeCycleCtx.html#method.id -/// [`WidgetExt::with_id`]: ../trait.WidgetExt.html#tymethod.with_id -/// [`IdentityWrapper`]: struct.IdentityWrapper.html -// this is NonZeroU64 because we regularly store Option -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] -pub struct WidgetId(NonZeroU64); - -/// The trait implemented by all widgets. +/// [`Size`](../../struct.Size.html) /// -/// All appearance and behavior for a widget is encapsulated in an -/// object that implements this trait. +/// [`UpdateCtx`](../../struct.UpdateCtx.html) /// -/// The trait is parametrized by a type (`T`) for associated data. -/// All trait methods are provided with access to this data, and -/// in the case of [`event`] the reference is mutable, so that events -/// can directly update the data. +/// [`WidgetId`](../../struct.WidgetId.html) /// -/// Whenever the application data changes, the framework traverses -/// the widget hierarchy with an [`update`] method. The framework -/// needs to know whether the data has actually changed or not, which -/// is why `T` has a [`Data`] bound. +/// # Enums +/// [`Event`](../../enum.Event.html) /// -/// All the trait methods are provided with a corresponding context. -/// The widget can request things and cause actions by calling methods -/// on that context. +/// [`LifeCycle`](../../enum.LifeCycle.html) /// -/// In addition, all trait methods are provided with an environment -/// ([`Env`]). +/// # Traits +/// [`RenderContext`](../../trait.RenderContext.html) /// -/// Container widgets will generally not call `Widget` methods directly -/// on their child widgets, but rather will own their widget wrapped in -/// a [`WidgetPod`], and call the corresponding method on that. The -/// `WidgetPod` contains state and logic for these traversals. On the -/// other hand, particularly light-weight containers might contain their -/// child `Widget` directly (when no layout or event flow logic is -/// needed), and in those cases will call these methods. -/// -/// As a general pattern, container widgets will call the corresponding -/// `WidgetPod` method on all their children. The `WidgetPod` applies -/// logic to determine whether to recurse, as needed. -/// -/// [`event`]: #tymethod.event -/// [`update`]: #tymethod.update -/// [`Data`]: ../trait.Data.html -/// [`Env`]: ../struct.Env.html -/// [`WidgetPod`]: ../struct.WidgetPod.html -pub trait Widget { - /// Handle an event. - /// - /// A number of different events (in the [`Event`] enum) are handled in this - /// method call. A widget can handle these events in a number of ways: - /// requesting things from the [`EventCtx`], mutating the data, or submitting - /// a [`Command`]. - /// - /// [`Event`]: ../enum.Event.html - /// [`EventCtx`]: ../struct.EventCtx.html - /// [`Command`]: ../struct.Command.html - fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut T, env: &Env); - - /// Handle a life cycle notification. - /// - /// This method is called to notify your widget of certain special events, - /// (available in the [`LifeCycle`] enum) that are generally related to - /// changes in the widget graph or in the state of your specific widget. - /// - /// A widget is not expected to mutate the application state in response - /// to these events, but only to update its own internal state as required; - /// if a widget needs to mutate data, it can submit a [`Command`] that will - /// be executed at the next opportunity. - /// - /// [`LifeCycle`]: ../enum.LifeCycle.html - /// [`LifeCycleCtx`]: ../struct.LifeCycleCtx.html - /// [`Command`]: ../struct.Command.html - fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, data: &T, env: &Env); - - /// Handle a change of data. - /// - /// This method is called whenever the data changes. When the appearance of - /// the widget depends on data, call [`request_paint`] so that it's scheduled - /// for repaint. - /// - /// The previous value of the data is provided in case the widget wants to - /// compute a fine-grained delta. - /// - /// [`request_paint`]: ../struct.UpdateCtx.html#method.request_paint - fn update(&mut self, ctx: &mut UpdateCtx, old_data: &T, data: &T, env: &Env); - - /// Compute layout. - /// - /// A leaf widget should determine its size (subject to the provided - /// constraints) and return it. - /// - /// A container widget will recursively call [`WidgetPod::layout`] on its - /// child widgets, providing each of them an appropriate box constraint, - /// compute layout, then call [`set_layout_rect`] on each of its children. - /// Finally, it should return the size of the container. The container - /// can recurse in any order, which can be helpful to, for example, compute - /// the size of non-flex widgets first, to determine the amount of space - /// available for the flex widgets. - /// - /// For efficiency, a container should only invoke layout of a child widget - /// once, though there is nothing enforcing this. - /// - /// The layout strategy is strongly inspired by Flutter. - /// - /// [`WidgetPod::layout`]: ../struct.WidgetPod.html#method.layout - /// [`set_layout_rect`]: ../struct.WidgetPod.html#method.set_layout_rect - fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints, data: &T, env: &Env) -> Size; - - /// Paint the widget appearance. - /// - /// The [`PaintCtx`] derefs to something that implements the [`RenderContext`] - /// trait, which exposes various methods that the widget can use to paint - /// its appearance. - /// - /// Container widgets can paint a background before recursing to their - /// children, or annotations (for example, scrollbars) by painting - /// afterwards. In addition, they can apply masks and transforms on - /// the render context, which is especially useful for scrolling. - /// - /// [`PaintCtx`]: ../struct.PaintCtx.html - /// [`RenderContext`]: ../trait.RenderContext.html - fn paint(&mut self, ctx: &mut PaintCtx, data: &T, env: &Env); - - #[doc(hidden)] - /// Get the identity of the widget; this is basically only implemented by - /// `IdentityWrapper`. Widgets should not implement this on their own. - fn id(&self) -> Option { - None - } - +/// [`Widget`](../../trait.Widget.html) +pub mod prelude { #[doc(hidden)] - /// Get the (verbose) type name of the widget for debugging purposes. - /// You should not override this method. - fn type_name(&self) -> &'static str { - std::any::type_name::() - } -} - -impl WidgetId { - /// Allocate a new, unique `WidgetId`. - /// - /// All widgets are assigned ids automatically; you should only create - /// an explicit id if you need to know it ahead of time, for instance - /// if you want two sibling widgets to know each others' ids. - /// - /// You must ensure that a given `WidgetId` is only ever used for one - /// widget at a time. - pub fn next() -> WidgetId { - use crate::shell::Counter; - static WIDGET_ID_COUNTER: Counter = Counter::new(); - WidgetId(WIDGET_ID_COUNTER.next_nonzero()) - } - - /// Create a reserved `WidgetId`, suitable for reuse. - /// - /// The caller is responsible for ensuring that this ID is in fact assigned - /// to a single widget at any time, or your code may become haunted. - /// - /// The actual inner representation of the returned `WidgetId` will not - /// be the same as the raw value that is passed in; it will be - /// `u64::max_value() - raw`. - #[allow(unsafe_code)] - pub const fn reserved(raw: u16) -> WidgetId { - let id = u64::max_value() - raw as u64; - // safety: by construction this can never be zero. - WidgetId(unsafe { std::num::NonZeroU64::new_unchecked(id) }) - } - - pub(crate) fn to_raw(self) -> u64 { - self.0.into() - } -} - -impl Widget for Box> { - fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut T, env: &Env) { - self.deref_mut().event(ctx, event, data, env) - } - - fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, data: &T, env: &Env) { - self.deref_mut().lifecycle(ctx, event, data, env); - } - - fn update(&mut self, ctx: &mut UpdateCtx, old_data: &T, data: &T, env: &Env) { - self.deref_mut().update(ctx, old_data, data, env); - } - - fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints, data: &T, env: &Env) -> Size { - self.deref_mut().layout(ctx, bc, data, env) - } - - fn paint(&mut self, ctx: &mut PaintCtx, data: &T, env: &Env) { - self.deref_mut().paint(ctx, data, env); - } - - fn id(&self) -> Option { - self.deref().id() - } - - fn type_name(&self) -> &'static str { - self.deref().type_name() - } + pub use crate::{ + BoxConstraints, Env, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, + RenderContext, Size, UpdateCtx, Widget, WidgetId, + }; } diff --git a/druid/src/widget/painter.rs b/druid/src/widget/painter.rs index 055f2c815e..1969fb2263 100644 --- a/druid/src/widget/painter.rs +++ b/druid/src/widget/painter.rs @@ -71,7 +71,7 @@ use crate::{ /// }); /// ``` /// -/// [`paint`]: trait.Widget.html#tymethod.paint +/// [`paint`]: ../trait.Widget.html#tymethod.paint /// [`Data`]: ../trait.Data.html /// [`request_paint`]: ../EventCtx.html#method.request_paint /// [`Controller`]: trait.Controller.html @@ -82,9 +82,9 @@ pub struct Painter(Box); /// This represents anything that can be painted inside a widgets [`paint`] /// method; that is, it may have access to the [`Data`] and the [`Env`]. /// -/// [`paint`]: widget/trait.Widget.html#tymethod.paint -/// [`Data`]: trait.Data.html -/// [`Env`]: struct.Env.html +/// [`paint`]: ../trait.Widget.html#tymethod.paint +/// [`Data`]: ../trait.Data.html +/// [`Env`]: ../struct.Env.html #[non_exhaustive] pub enum BackgroundBrush { Color(Color), @@ -98,7 +98,7 @@ pub enum BackgroundBrush { impl Painter { /// Create a new `Painter` with the provided [`paint`] fn. /// - /// [`paint`]: trait.Widget.html#tymethod.paint + /// [`paint`]: ../trait.Widget.html#tymethod.paint pub fn new(f: impl FnMut(&mut PaintCtx, &T, &Env) + 'static) -> Self { Painter(Box::new(f)) } diff --git a/druid/src/widget/widget.rs b/druid/src/widget/widget.rs new file mode 100644 index 0000000000..764983e58c --- /dev/null +++ b/druid/src/widget/widget.rs @@ -0,0 +1,248 @@ +// Copyright 2018 The xi-editor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::num::NonZeroU64; +use std::ops::{Deref, DerefMut}; + +use super::prelude::*; + +/// A unique identifier for a single [`Widget`]. +/// +/// `WidgetId`s are generated automatically for all widgets that participate +/// in layout. More specifically, each [`WidgetPod`] has a unique `WidgetId`. +/// +/// These ids are used internally to route events, and can be used to communicate +/// between widgets, by submitting a command (as with [`EventCtx::submit_command`]) +/// and passing a `WidgetId` as the [`Target`]. +/// +/// A widget can retrieve its id via methods on the various contexts, such as +/// [`LifeCycleCtx::widget_id`]. +/// +/// ## Explicit `WidgetId`s. +/// +/// Sometimes, you may want to know a widget's id when constructing the widget. +/// You can give a widget an _explicit_ id by wrapping it in an [`IdentityWrapper`] +/// widget, or by using the [`WidgetExt::with_id`] convenience method. +/// +/// If you set a `WidgetId` directly, you are resposible for ensuring that it +/// is unique in time. That is: only one widget can exist with a given id at a +/// given time. +/// +/// [`Widget`]: trait.Widget.html +/// [`EventCtx::submit_command`]: struct.EventCtx.html#method.submit_command +/// [`Target`]: enum.Target.html +/// [`WidgetPod`]: struct.WidgetPod.html +/// [`LifeCycleCtx::widget_id`]: struct.LifeCycleCtx.html#method.widget_id +/// [`WidgetExt::with_id`]: trait.WidgetExt.html#method.with_id +/// [`IdentityWrapper`]: widget/struct.IdentityWrapper.html +// this is NonZeroU64 because we regularly store Option +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] +pub struct WidgetId(NonZeroU64); + +/// The trait implemented by all widgets. +/// +/// All appearance and behavior for a widget is encapsulated in an +/// object that implements this trait. +/// +/// The trait is parametrized by a type (`T`) for associated data. +/// All trait methods are provided with access to this data, and +/// in the case of [`event`] the reference is mutable, so that events +/// can directly update the data. +/// +/// Whenever the application data changes, the framework traverses +/// the widget hierarchy with an [`update`] method. The framework +/// needs to know whether the data has actually changed or not, which +/// is why `T` has a [`Data`] bound. +/// +/// All the trait methods are provided with a corresponding context. +/// The widget can request things and cause actions by calling methods +/// on that context. +/// +/// In addition, all trait methods are provided with an environment +/// ([`Env`]). +/// +/// Container widgets will generally not call `Widget` methods directly +/// on their child widgets, but rather will own their widget wrapped in +/// a [`WidgetPod`], and call the corresponding method on that. The +/// `WidgetPod` contains state and logic for these traversals. On the +/// other hand, particularly light-weight containers might contain their +/// child `Widget` directly (when no layout or event flow logic is +/// needed), and in those cases will call these methods. +/// +/// As a general pattern, container widgets will call the corresponding +/// `WidgetPod` method on all their children. The `WidgetPod` applies +/// logic to determine whether to recurse, as needed. +/// +/// [`event`]: #tymethod.event +/// [`update`]: #tymethod.update +/// [`Data`]: trait.Data.html +/// [`Env`]: struct.Env.html +/// [`WidgetPod`]: struct.WidgetPod.html +pub trait Widget { + /// Handle an event. + /// + /// A number of different events (in the [`Event`] enum) are handled in this + /// method call. A widget can handle these events in a number of ways: + /// requesting things from the [`EventCtx`], mutating the data, or submitting + /// a [`Command`]. + /// + /// [`Event`]: enum.Event.html + /// [`EventCtx`]: struct.EventCtx.html + /// [`Command`]: struct.Command.html + fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut T, env: &Env); + + /// Handle a life cycle notification. + /// + /// This method is called to notify your widget of certain special events, + /// (available in the [`LifeCycle`] enum) that are generally related to + /// changes in the widget graph or in the state of your specific widget. + /// + /// A widget is not expected to mutate the application state in response + /// to these events, but only to update its own internal state as required; + /// if a widget needs to mutate data, it can submit a [`Command`] that will + /// be executed at the next opportunity. + /// + /// [`LifeCycle`]: enum.LifeCycle.html + /// [`LifeCycleCtx`]: struct.LifeCycleCtx.html + /// [`Command`]: struct.Command.html + fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, data: &T, env: &Env); + + /// Handle a change of data. + /// + /// This method is called whenever the data changes. When the appearance of + /// the widget depends on data, call [`request_paint`] so that it's scheduled + /// for repaint. + /// + /// The previous value of the data is provided in case the widget wants to + /// compute a fine-grained delta. + /// + /// [`request_paint`]: struct.UpdateCtx.html#method.request_paint + fn update(&mut self, ctx: &mut UpdateCtx, old_data: &T, data: &T, env: &Env); + + /// Compute layout. + /// + /// A leaf widget should determine its size (subject to the provided + /// constraints) and return it. + /// + /// A container widget will recursively call [`WidgetPod::layout`] on its + /// child widgets, providing each of them an appropriate box constraint, + /// compute layout, then call [`set_layout_rect`] on each of its children. + /// Finally, it should return the size of the container. The container + /// can recurse in any order, which can be helpful to, for example, compute + /// the size of non-flex widgets first, to determine the amount of space + /// available for the flex widgets. + /// + /// For efficiency, a container should only invoke layout of a child widget + /// once, though there is nothing enforcing this. + /// + /// The layout strategy is strongly inspired by Flutter. + /// + /// [`WidgetPod::layout`]: struct.WidgetPod.html#method.layout + /// [`set_layout_rect`]: struct.WidgetPod.html#method.set_layout_rect + fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints, data: &T, env: &Env) -> Size; + + /// Paint the widget appearance. + /// + /// The [`PaintCtx`] derefs to something that implements the [`RenderContext`] + /// trait, which exposes various methods that the widget can use to paint + /// its appearance. + /// + /// Container widgets can paint a background before recursing to their + /// children, or annotations (for example, scrollbars) by painting + /// afterwards. In addition, they can apply masks and transforms on + /// the render context, which is especially useful for scrolling. + /// + /// [`PaintCtx`]: struct.PaintCtx.html + /// [`RenderContext`]: trait.RenderContext.html + fn paint(&mut self, ctx: &mut PaintCtx, data: &T, env: &Env); + + #[doc(hidden)] + /// Get the identity of the widget; this is basically only implemented by + /// `IdentityWrapper`. Widgets should not implement this on their own. + fn id(&self) -> Option { + None + } + + #[doc(hidden)] + /// Get the (verbose) type name of the widget for debugging purposes. + /// You should not override this method. + fn type_name(&self) -> &'static str { + std::any::type_name::() + } +} + +impl WidgetId { + /// Allocate a new, unique `WidgetId`. + /// + /// All widgets are assigned ids automatically; you should only create + /// an explicit id if you need to know it ahead of time, for instance + /// if you want two sibling widgets to know each others' ids. + /// + /// You must ensure that a given `WidgetId` is only ever used for one + /// widget at a time. + pub fn next() -> WidgetId { + use crate::shell::Counter; + static WIDGET_ID_COUNTER: Counter = Counter::new(); + WidgetId(WIDGET_ID_COUNTER.next_nonzero()) + } + + /// Create a reserved `WidgetId`, suitable for reuse. + /// + /// The caller is responsible for ensuring that this ID is in fact assigned + /// to a single widget at any time, or your code may become haunted. + /// + /// The actual inner representation of the returned `WidgetId` will not + /// be the same as the raw value that is passed in; it will be + /// `u64::max_value() - raw`. + #[allow(unsafe_code)] + pub const fn reserved(raw: u16) -> WidgetId { + let id = u64::max_value() - raw as u64; + // safety: by construction this can never be zero. + WidgetId(unsafe { std::num::NonZeroU64::new_unchecked(id) }) + } + + pub(crate) fn to_raw(self) -> u64 { + self.0.into() + } +} + +impl Widget for Box> { + fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut T, env: &Env) { + self.deref_mut().event(ctx, event, data, env) + } + + fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, data: &T, env: &Env) { + self.deref_mut().lifecycle(ctx, event, data, env); + } + + fn update(&mut self, ctx: &mut UpdateCtx, old_data: &T, data: &T, env: &Env) { + self.deref_mut().update(ctx, old_data, data, env); + } + + fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints, data: &T, env: &Env) -> Size { + self.deref_mut().layout(ctx, bc, data, env) + } + + fn paint(&mut self, ctx: &mut PaintCtx, data: &T, env: &Env) { + self.deref_mut().paint(ctx, data, env); + } + + fn id(&self) -> Option { + self.deref().id() + } + + fn type_name(&self) -> &'static str { + self.deref().type_name() + } +} diff --git a/druid/src/widget/widget_ext.rs b/druid/src/widget/widget_ext.rs index edd3a79c0a..70ffe5dfd9 100644 --- a/druid/src/widget/widget_ext.rs +++ b/druid/src/widget/widget_ext.rs @@ -24,64 +24,64 @@ use crate::{Color, Data, Env, EventCtx, Insets, KeyOrValue, Lens, LensWrap, Unit pub trait WidgetExt: Widget + Sized + 'static { /// Wrap this widget in a [`Padding`] widget with the given [`Insets`]. /// - /// [`Padding`]: struct.Padding.html - /// [`Insets`]: https://docs.rs/kurbo/0.5.4/kurbo/struct.Insets.html + /// [`Padding`]: widget/struct.Padding.html + /// [`Insets`]: kurbo/struct.Insets.html fn padding(self, insets: impl Into) -> Padding { Padding::new(insets, self) } /// Wrap this widget in an [`Align`] widget, configured to center it. /// - /// [`Align`]: struct.Align.html + /// [`Align`]: widget/struct.Align.html fn center(self) -> Align { Align::centered(self) } /// Wrap this widget in an [`Align`] widget, configured to align left. /// - /// [`Align`]: struct.Align.html + /// [`Align`]: widget/struct.Align.html fn align_left(self) -> Align { Align::left(self) } /// Wrap this widget in an [`Align`] widget, configured to align right. /// - /// [`Align`]: struct.Align.html + /// [`Align`]: widget/struct.Align.html fn align_right(self) -> Align { Align::right(self) } /// Wrap this widget in an [`Align`] widget, configured to align vertically. /// - /// [`Align`]: struct.Align.html + /// [`Align`]: widget/struct.Align.html fn align_vertical(self, align: UnitPoint) -> Align { Align::vertical(align, self) } /// Wrap this widget in an [`Align`] widget, configured to align horizontally. /// - /// [`Align`]: struct.Align.html + /// [`Align`]: widget/struct.Align.html fn align_horizontal(self, align: UnitPoint) -> Align { Align::horizontal(align, self) } /// Wrap this widget in a [`SizedBox`] with an explicit width. /// - /// [`SizedBox`]: struct.SizedBox.html + /// [`SizedBox`]: widget/struct.SizedBox.html fn fix_width(self, width: f64) -> SizedBox { SizedBox::new(self).width(width) } /// Wrap this widget in a [`SizedBox`] with an explicit width. /// - /// [`SizedBox`]: struct.SizedBox.html + /// [`SizedBox`]: widget/struct.SizedBox.html fn fix_height(self, height: f64) -> SizedBox { SizedBox::new(self).height(height) } /// Wrap this widget in an [`SizedBox`] with an explicit width and height /// - /// [`SizedBox`]: struct.SizedBox.html + /// [`SizedBox`]: widget/struct.SizedBox.html fn fix_size(self, width: f64, height: f64) -> SizedBox { SizedBox::new(self).width(width).height(height) } @@ -94,7 +94,7 @@ pub trait WidgetExt: Widget + Sized + 'static { /// /// [`expand_height`]: #method.expand_height /// [`expand_width`]: #method.expand_width - /// [`SizedBox`]: struct.SizedBox.html + /// [`SizedBox`]: widget/struct.SizedBox.html fn expand(self) -> SizedBox { SizedBox::new(self).expand() } @@ -103,7 +103,7 @@ pub trait WidgetExt: Widget + Sized + 'static { /// /// This will force the child to use all available space on the x-axis. /// - /// [`SizedBox`]: struct.SizedBox.html + /// [`SizedBox`]: widget/struct.SizedBox.html fn expand_width(self) -> SizedBox { SizedBox::new(self).expand_width() } @@ -112,7 +112,7 @@ pub trait WidgetExt: Widget + Sized + 'static { /// /// This will force the child to use all available space on the y-axis. /// - /// [`SizedBox`]: struct.SizedBox.html + /// [`SizedBox`]: widget/struct.SizedBox.html fn expand_height(self) -> SizedBox { SizedBox::new(self).expand_height() } @@ -121,8 +121,8 @@ pub trait WidgetExt: Widget + Sized + 'static { /// /// See [`Container::background`] for more information. /// - /// [`Container`]: struct.Container.html - /// [`Container::background`]: struct.Container.html#method.background + /// [`Container`]: widget/struct.Container.html + /// [`Container::background`]: widget/struct.Container.html#method.background fn background(self, brush: impl Into>) -> Container { Container::new(self).background(brush) } @@ -132,8 +132,8 @@ pub trait WidgetExt: Widget + Sized + 'static { /// Arguments can be either concrete values, or a [`Key`] of the respective /// type. /// - /// [`Container`]: struct.Container.html - /// [`Key`]: ../struct.Key.html + /// [`Container`]: widget/struct.Container.html + /// [`Key`]: struct.Key.html fn border( self, color: impl Into>, @@ -145,15 +145,15 @@ pub trait WidgetExt: Widget + Sized + 'static { /// Wrap this widget in a [`EnvScope`] widget, modifying the parent /// [`Env`] with the provided closure. /// - /// [`EnvScope`]: struct.EnvScope.html - /// [`Env`]: ../struct.Env.html + /// [`EnvScope`]: widget/struct.EnvScope.html + /// [`Env`]: struct.Env.html fn env_scope(self, f: impl Fn(&mut Env, &T) + 'static) -> EnvScope { EnvScope::new(f, self) } /// Wrap this widget with the provided [`Controller`]. /// - /// [`Controller`]: trait.Controller.html + /// [`Controller`]: widget/trait.Controller.html fn controller>(self, controller: C) -> ControllerHost { ControllerHost::new(self, controller) } @@ -165,8 +165,8 @@ pub trait WidgetExt: Widget + Sized + 'static { /// mouse down, which can be useful for painting based on `ctx.is_active()` /// and `ctx.is_hot()`. /// - /// [`Click`]: struct.Click.html - /// [`LifeCycle::HotChanged`]: ../enum.LifeCycle.html#variant.HotChanged + /// [`Click`]: widget/struct.Click.html + /// [`LifeCycle::HotChanged`]: enum.LifeCycle.html#variant.HotChanged fn on_click( self, f: impl Fn(&mut EventCtx, &mut T, &Env) + 'static, @@ -186,7 +186,7 @@ pub trait WidgetExt: Widget + Sized + 'static { /// This does nothing by default, but you can use this variable while /// debugging to only print messages from particular instances of a widget. /// - /// [`DEBUG_WIDGET`]: ../struct.Env.html#associatedconstant.DEBUG_WIDGET + /// [`DEBUG_WIDGET`]: struct.Env.html#associatedconstant.DEBUG_WIDGET fn debug_widget(self) -> EnvScope { EnvScope::new(|env, _| env.set(Env::DEBUG_WIDGET, true), self) } @@ -194,8 +194,8 @@ pub trait WidgetExt: Widget + Sized + 'static { /// Wrap this widget in a [`LensWrap`] widget for the provided [`Lens`]. /// /// - /// [`LensWrap`]: ../lens/struct.LensWrap.html - /// [`Lens`]: ../lens/trait.Lens.html + /// [`LensWrap`]: struct.LensWrap.html + /// [`Lens`]: trait.Lens.html fn lens>(self, lens: L) -> LensWrap { LensWrap::new(self, lens) }