Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hide all fields of widget_core!() #470

Merged
merged 8 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading