Skip to content

Commit

Permalink
Merge pull request #470 from kas-gui/work
Browse files Browse the repository at this point in the history
Hide all fields of widget_core!()
  • Loading branch information
dhardy authored Jan 23, 2025
2 parents 90a4347 + a52f2ca commit e929dba
Show file tree
Hide file tree
Showing 47 changed files with 363 additions and 297 deletions.
21 changes: 10 additions & 11 deletions crates/kas-core/src/core/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,22 @@ impl Icon {
/// Common widget data
///
/// This type may be used for a [`Widget`]'s `core: widget_core!()` field.
#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
#[derive(Default, Debug)]
pub struct CoreData {
pub rect: Rect,
pub id: Id,
#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
pub struct DefaultCoreType {
pub _rect: Rect,
pub _id: Id,
#[cfg(debug_assertions)]
pub status: WidgetStatus,
}

/// Note: the clone has default-initialised identifier.
/// Configuration and layout solving is required as for any other widget.
impl Clone for CoreData {
impl Clone for DefaultCoreType {
fn clone(&self) -> Self {
CoreData {
rect: self.rect,
..CoreData::default()
DefaultCoreType {
_rect: self._rect,
_id: Default::default(),
status: self.status,
}
}
}
Expand Down
36 changes: 21 additions & 15 deletions crates/kas-core/src/core/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,18 +234,34 @@ pub trait Tile: Layout {
unimplemented!() // make rustdoc show that this is a provided method
}

/// Get the widget's identifier
/// Get a reference to the widget's identifier
///
/// Note that the default-constructed [`Id`] is *invalid*: any
/// operations on this value will cause a panic. A valid identifier is
/// assigned when the widget is configured (immediately before calling
/// [`Events::configure`]).
/// The widget identifier is assigned when the widget is configured (see
/// [`Events::configure`] and [`Events::configure_recurse`]). In case the
/// [`Id`] is accessed before this, it will be [invalid](Id#invalid-state).
/// The identifier *may* change when widgets which are descendants of some
/// dynamic layout are reconfigured.
///
/// This method is implemented by the `#[widget]` macro.
fn id_ref(&self) -> &Id {
unimplemented!() // make rustdoc show that this is a provided method
}

/// Get the widget's identifier
///
/// This method returns a [`Clone`] of [`Self::id_ref`]. Since cloning an
/// `Id` is [very cheap](Id#representation), this can mostly be ignored.
///
/// The widget identifier is assigned when the widget is configured (see
/// [`Events::configure`] and [`Events::configure_recurse`]). In case the
/// [`Id`] is accessed before this, it will be [invalid](Id#invalid-state).
/// The identifier *may* change when widgets which are descendants of some
/// dynamic layout are reconfigured.
#[inline]
fn id(&self) -> Id {
self.id_ref().clone()
}

/// Get the widget's region, relative to its parent.
///
/// This method is implemented by the `#[widget]` macro.
Expand Down Expand Up @@ -351,16 +367,6 @@ impl<W: Tile + ?Sized> HasId for &mut W {

/// Extension trait over widgets
pub trait TileExt: Tile {
/// Get the widget's identifier
///
/// Note that the default-constructed [`Id`] is *invalid*: any
/// operations on this value will cause a panic. Valid identifiers are
/// assigned during configure.
#[inline]
fn id(&self) -> Id {
self.id_ref().clone()
}

/// Test widget identifier for equality
///
/// This method may be used to test against `Id`, `Option<Id>`
Expand Down
17 changes: 10 additions & 7 deletions crates/kas-core/src/core/widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ use kas_macros::autoimpl;
///
/// # Widget lifecycle
///
/// 1. The widget is configured ([`Events::configure`]) and immediately updated
/// 1. The widget is configured ([`Events::configure`],
/// [`Events::configure_recurse`]) and immediately updated
/// ([`Events::update`]).
/// 2. The widget has its size-requirements checked by calling
/// [`Layout::size_rules`] for each axis.
Expand Down Expand Up @@ -80,12 +81,14 @@ pub trait Events: Widget + Sized {
/// Configure children
///
/// This method is called after [`Self::configure`].
/// It usually configures all children.
///
/// The default implementation suffices except where children should *not*
/// be configured (for example, to delay configuration of hidden children).
///
/// Use [`Events::make_child_id`] and [`ConfigCx::configure`].
/// The default implementation configures all children.
///
/// An explicit implementation is required in cases where not all children
/// should be configured immediately (for example, a stack or paged list may
/// choose not to configure hidden children until just before they become
/// visible). To configure children explicitly, generate an [`Id`] by
/// calling [`Events::make_child_id`] on `self` then pass this `id` to
/// [`ConfigCx::configure`].
fn configure_recurse(&mut self, cx: &mut ConfigCx, data: &Self::Data) {
for index in 0..self.num_children() {
let id = self.make_child_id(index);
Expand Down
12 changes: 10 additions & 2 deletions crates/kas-core/src/core/widget_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ impl<'a> Iterator for WidgetPathIter<'a> {
/// `a4`. To interpret these values, first subtract 8 from each digit but the
/// last digit, then read as base-8: `[1, 2, 8, 20]`.
///
/// # Representation
///
/// This type is small (64-bit) and non-zero: `Option<Id>` has the same
/// size as `Id`. It is also very cheap to `Clone`: usually only one `if`
/// check, and in the worst case a pointer dereference and ref-count increment.
Expand All @@ -226,8 +228,13 @@ impl<'a> Iterator for WidgetPathIter<'a> {
///
/// `Id` is neither `Send` nor `Sync`.
///
/// Identifiers are assigned when configured and when re-configured
/// (via [`Action::RECONFIGURE`] or [`ConfigCx::configure`]).
/// # Invalid state
///
/// When `Id` is [`Default`] constructed, it uses a special **invalid** state.
/// Any attempt to use or compare such an invalid state will cause a panic.
///
/// Widgets are initially constructed with an invalid `Id`, then assigned an
/// `Id` when configured (see [`Events::configure`]).
/// In most cases values are persistent but this is not guaranteed (e.g.
/// inserting or removing a child from a `List` widget will affect the
/// identifiers of all following children). View-widgets assign path components
Expand All @@ -236,6 +243,7 @@ impl<'a> Iterator for WidgetPathIter<'a> {
/// [`Display`]: std::fmt::Display
/// [`Action::RECONFIGURE`]: crate::Action::RECONFIGURE
/// [`ConfigCx::configure`]: crate::event::ConfigCx::configure
/// [`Events::configure`]: crate::Events::configure
#[allow(clippy::assigning_clones)]
#[derive(Clone)]
pub struct Id(IntOrPtr);
Expand Down
4 changes: 2 additions & 2 deletions crates/kas-core/src/decorations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ impl_scope! {

impl Layout for Self {
fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
self.core.rect = rect;
widget_set_rect!(rect);
self.text.set_rect(cx, rect, hints.combine(AlignHints::CENTER));
}
}
Expand Down Expand Up @@ -183,7 +183,7 @@ impl_scope! {
}

fn draw(&mut self, mut draw: DrawCx) {
draw.mark(self.core.rect, self.style);
draw.mark(self.rect(), self.style);
}
}

Expand Down
5 changes: 4 additions & 1 deletion crates/kas-core/src/event/cx/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::{Id, Node};
use std::ops::{Deref, DerefMut};

#[allow(unused)] use crate::event::{Event, EventCx};
#[allow(unused)] use crate::{Events, Layout};
#[allow(unused)] use crate::{Action, Events, Layout};

/// Widget configuration and update context
///
Expand Down Expand Up @@ -72,6 +72,9 @@ impl<'a> ConfigCx<'a> {
/// This method performs complete configuration of the widget by calling
/// [`Events::configure`], [`Events::update`], [`Events::configure_recurse`].
///
/// To trigger (re)-configuration of the entire widget tree, use
/// [`Action::RECONFIGURE`].
///
/// Pass the `id` to assign to the widget. This is usually constructed with
/// [`Events::make_child_id`].
#[inline]
Expand Down
4 changes: 2 additions & 2 deletions crates/kas-core/src/hidden.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::geom::Rect;
use crate::layout::AlignHints;
use crate::theme::{Text, TextClass};
use crate::{Events, Layout, Widget};
use kas_macros::{autoimpl, impl_scope};
use kas_macros::{autoimpl, impl_scope, widget_set_rect};

impl_scope! {
/// A simple text label
Expand Down Expand Up @@ -46,7 +46,7 @@ impl_scope! {

impl Layout for Self {
fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
self.core.rect = rect;
widget_set_rect!(rect);
self.text.set_rect(cx, rect, hints.combine(AlignHints::VERT_CENTER));
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/kas-core/src/layout/align.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub use crate::text::Align;
/// let rect = align
/// .complete(Align::Stretch, Align::Center)
/// .aligned_rect(pref_size, rect);
/// // self.core.rect = rect;
/// // widget_set_rect!(rect);
/// ```
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct AlignHints {
Expand Down
2 changes: 1 addition & 1 deletion crates/kas-core/src/layout/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ impl<V: Layout> Visitor<V> {

/// Apply a given `rect` to self
///
/// The caller is expected to set `self.core.rect = rect;`.
/// The caller is expected to call `widget_set_rect!(rect);`.
/// In other respects, this functions identically to [`Layout::set_rect`].
#[inline]
pub fn set_rect(mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
Expand Down
5 changes: 3 additions & 2 deletions crates/kas-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ mod root;

pub use crate::core::*;
pub use action::Action;
pub use kas_macros::{autoimpl, extends, impl_default, widget};
pub use kas_macros::{cell_collection, collection, impl_anon, impl_scope, widget_index};
pub use kas_macros::{autoimpl, extends, impl_default};
pub use kas_macros::{cell_collection, collection, impl_anon, impl_scope};
pub use kas_macros::{widget, widget_index, widget_set_rect};
#[doc(inline)] pub use popup::Popup;
#[doc(inline)] pub(crate) use popup::PopupDescriptor;
#[doc(inline)]
Expand Down
2 changes: 1 addition & 1 deletion crates/kas-core/src/popup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use crate::dir::Direction;
use crate::event::{ConfigCx, Event, EventCx, IsUsed, Scroll, Unused, Used};
use crate::{Events, Id, TileExt, Widget, WindowId};
use crate::{Events, Id, Tile, TileExt, Widget, WindowId};
use kas_macros::{impl_scope, widget_index};

#[allow(unused)] use crate::event::EventState;
Expand Down
4 changes: 3 additions & 1 deletion crates/kas-core/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ pub use crate::layout::{
#[doc(no_inline)] pub use crate::theme::{DrawCx, SizeCx};
#[doc(no_inline)] pub use crate::Action;
#[doc(no_inline)]
pub use crate::{autoimpl, impl_anon, impl_default, impl_scope, widget, widget_index};
pub use crate::{autoimpl, impl_anon, impl_default, impl_scope};
#[doc(no_inline)]
pub use crate::{widget, widget_index, widget_set_rect};
#[doc(no_inline)]
pub use crate::{Events, Layout, Tile, TileExt, Widget, Window, WindowCommand};
#[doc(no_inline)] pub use crate::{HasId, Id};
Expand Down
12 changes: 6 additions & 6 deletions crates/kas-core/src/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::geom::{Coord, Offset, Rect, Size};
use crate::layout::{self, AlignHints, AxisInfo, SizeRules};
use crate::theme::{DrawCx, FrameStyle, SizeCx};
use crate::{Action, Events, Icon, Id, Layout, Tile, TileExt, Widget};
use kas_macros::impl_scope;
use kas_macros::{impl_scope, widget_set_rect};
use smallvec::SmallVec;
use std::num::NonZeroU32;

Expand Down Expand Up @@ -119,7 +119,7 @@ impl_scope! {
}

fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
self.core.rect = rect;
widget_set_rect!(rect);
// Calculate position and size for nw, ne, and inner portions:
let s_nw: Size = self.dec_offset.cast();
let s_se = self.dec_size - s_nw;
Expand Down Expand Up @@ -153,10 +153,10 @@ impl_scope! {

impl Self {
pub(crate) fn try_probe(&mut self, data: &Data, coord: Coord) -> Option<Id> {
if !self.core.rect.contains(coord) {
if !self.rect().contains(coord) {
return None;
}
for (_, popup, translation) in self.popups.iter_mut().rev() {
for (_, popup, translation) in self.popups.iter().rev() {
if let Some(Some(id)) = self.inner.as_node(data).find_node(&popup.id, |mut node| node.try_probe(coord + *translation)) {
return Some(id);
}
Expand All @@ -181,7 +181,7 @@ impl_scope! {
#[cfg(winit)]
pub(crate) fn draw(&mut self, data: &Data, mut draw: DrawCx) {
if self.dec_size != Size::ZERO {
draw.frame(self.core.rect, FrameStyle::Window, Default::default());
draw.frame(self.rect(), FrameStyle::Window, Default::default());
if self.bar_h > 0 {
self.title_bar.draw(draw.re());
}
Expand Down Expand Up @@ -473,7 +473,7 @@ impl<Data: 'static> Window<Data> {
fn resize_popup(&mut self, cx: &mut ConfigCx, data: &Data, index: usize) {
// Notation: p=point/coord, s=size, m=margin
// r=window/root rect, c=anchor rect
let r = self.core.rect;
let r = self.rect();
let (_, ref mut popup, ref mut translation) = self.popups[index];

let is_reversed = popup.direction.is_reversed();
Expand Down
3 changes: 2 additions & 1 deletion crates/kas-core/src/runner/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ use crate::draw::{color::Rgba, AnimationState, DrawSharedImpl};
use crate::event::{ConfigCx, CursorIcon, EventState};
use crate::geom::{Coord, Rect, Size};
use crate::layout::SolveCache;
use crate::messages::MessageStack;
use crate::theme::{DrawCx, SizeCx, Theme, ThemeSize, Window as _};
use crate::{autoimpl, messages::MessageStack, Action, Id, Tile, TileExt, Widget, WindowId};
use crate::{autoimpl, Action, Id, Tile, Widget, WindowId};
use std::mem::take;
use std::sync::Arc;
use std::time::{Duration, Instant};
Expand Down
39 changes: 28 additions & 11 deletions crates/kas-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,13 +200,8 @@ pub fn impl_scope(input: TokenStream) -> TokenStream {
/// The struct must contain a field of type `widget_core!()` (usually named
/// `core`). The macro `widget_core!()` is a placeholder, expanded by
/// `#[widget]` and used to identify the field used (any name may be used).
/// This field *might* have type [`CoreData`] or might use a special generated
/// type; either way it has fields `id: Id` (assigned by during configure)
/// and `rect: Rect` (usually assigned by
/// `Layout::set_rect`). It may contain additional fields for layout data. The
/// type supports `Default` and `Clone` (although `Clone` actually
/// default-initializes all fields other than `rect` since clones of widgets
/// must themselves be configured).
/// This type implements [`Default`] and [`Clone`], though the clone is not an
/// exact clone (cloned widgets must still be configured).
///
/// Assuming the deriving type is a `struct` or `tuple struct`, fields support
/// the following attributes:
Expand Down Expand Up @@ -359,7 +354,6 @@ pub fn impl_scope(input: TokenStream) -> TokenStream {
/// [`Events`]: https://docs.rs/kas/latest/kas/trait.Events.html
/// [`CursorIcon`]: https://docs.rs/kas/latest/kas/event/enum.CursorIcon.html
/// [`IsUsed`]: https://docs.rs/kas/latest/kas/event/enum.IsUsed.html
/// [`CoreData`]: https://docs.rs/kas/latest/kas/struct.CoreData.html
/// [`Deref`]: std::ops::Deref
#[proc_macro_attribute]
#[proc_macro_error]
Expand Down Expand Up @@ -442,9 +436,32 @@ pub fn impl_anon(input: TokenStream) -> TokenStream {
#[proc_macro_error]
#[proc_macro]
pub fn widget_index(input: TokenStream) -> TokenStream {
let input2 = input.clone();
let _ = parse_macro_input!(input2 as widget_index::BaseInput);
input
let input = parse_macro_input!(input as widget_index::UnscopedInput);
input.into_token_stream().into()
}

/// Macro to set the `rect` stored in the widget core
///
/// Widgets have a hidden field of type [`Rect`] in their `widget_core!()`, used
/// to implement method [`Tile::rect`]. This macro assigns to that field.
///
/// This macro is usable only within an [`impl_scope!`] macro using the
/// [`widget`](macro@widget) attribute.
///
/// Example usage:
/// ```ignore
/// fn set_rect(&mut self, _: &mut ConfigCx, rect: Rect, _: AlignHints) {
/// widget_set_rect!(rect);
/// }
/// ```
///
/// [`Rect`]: https://docs.rs/kas/latest/kas/geom/struct.Rect.html
/// [`Tile::rect`]: https://docs.rs/kas/latest/kas/trait.Tile.html#method.rect
#[proc_macro_error]
#[proc_macro]
pub fn widget_set_rect(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as widget_index::UnscopedInput);
input.into_token_stream().into()
}

trait ExpandLayout {
Expand Down
Loading

0 comments on commit e929dba

Please sign in to comment.