kas_core/core/
data.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License in the LICENSE-APACHE file or at:
4//     https://www.apache.org/licenses/LICENSE-2.0
5
6//! Core data types
7
8use super::Id;
9#[allow(unused)] use crate::Widget;
10use crate::geom::Rect;
11use std::ops::Range;
12
13/// An opaque type indexible over `usize`
14///
15/// Currently, the only supported representation is a range. Construct using
16/// [`From`] impls, e.g. `(0..self.widgets.len()).into()`.
17//
18// NOTE: this API is extensible to other representations like an enum over
19// Range or Box<[usize]> (or Vec<usize>).
20#[derive(Clone, Debug)]
21pub struct ChildIndices(usize, usize);
22
23impl ChildIndices {
24    // pub fn iter(&self) -> ChildIndicesRefIter<'_> { .. }
25
26    /// Convert to a Range
27    #[inline]
28    pub(crate) fn as_range(&self) -> Range<usize> {
29        self.0..self.1
30    }
31}
32
33impl IntoIterator for ChildIndices {
34    type Item = usize;
35    type IntoIter = ChildIndicesIter;
36
37    #[inline]
38    fn into_iter(self) -> ChildIndicesIter {
39        ChildIndicesIter(self.0..self.1)
40    }
41}
42
43impl From<Range<usize>> for ChildIndices {
44    #[inline]
45    fn from(range: Range<usize>) -> Self {
46        ChildIndices(range.start, range.end)
47    }
48}
49
50/// Owning iterator over [`ChildIndices`]
51#[derive(Clone, Debug)]
52pub struct ChildIndicesIter(Range<usize>);
53
54impl Iterator for ChildIndicesIter {
55    type Item = usize;
56
57    #[inline]
58    fn next(&mut self) -> Option<usize> {
59        self.0.next()
60    }
61
62    #[inline]
63    fn size_hint(&self) -> (usize, Option<usize>) {
64        self.0.size_hint()
65    }
66}
67impl ExactSizeIterator for ChildIndicesIter {}
68impl DoubleEndedIterator for ChildIndicesIter {
69    #[inline]
70    fn next_back(&mut self) -> Option<usize> {
71        self.0.next_back()
72    }
73}
74
75/// Common widget data
76///
77/// This type may be used for a [`Widget`]'s `core: widget_core!()` field.
78#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
79#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
80#[derive(Default, Debug)]
81pub struct DefaultCoreType {
82    pub _rect: Rect,
83    pub _id: Id,
84    #[cfg(debug_assertions)]
85    pub status: WidgetStatus,
86}
87
88impl Clone for DefaultCoreType {
89    fn clone(&self) -> Self {
90        DefaultCoreType {
91            _rect: self._rect,
92            _id: Default::default(),
93            #[cfg(debug_assertions)]
94            status: self.status,
95        }
96    }
97}
98
99/// Widget state tracker
100///
101/// This struct is used to track status of widget operations and panic in case
102/// of inappropriate call order (such cases are memory safe but may cause
103/// incorrect widget behaviour).
104///
105/// It is not used in release builds.
106#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
107#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
108#[cfg(debug_assertions)]
109#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
110pub enum WidgetStatus {
111    #[default]
112    New,
113    Configured,
114    SizeRulesX,
115    SizeRulesY,
116    SetRect,
117}
118
119#[cfg(debug_assertions)]
120impl WidgetStatus {
121    fn require(&self, id: &Id, expected: Self) {
122        if *self < expected {
123            panic!("WidgetStatus of {id}: require {expected:?}, found {self:?}");
124        }
125    }
126
127    /// Configure
128    ///
129    /// Requires nothing. Re-configuration does not require repeating other actions.
130    pub fn configure(&mut self, _id: &Id) {
131        // re-configure does not require repeating other actions
132        *self = (*self).max(WidgetStatus::Configured);
133    }
134
135    /// Update
136    ///
137    /// Requires configure. Does not affect status (note that widgets are always
138    /// updated immediately after configure, hence `WidgetStatus::Configured`
139    /// implies that `update` has been called or is just about to be called).
140    pub fn update(&self, id: &Id) {
141        self.require(id, WidgetStatus::Configured);
142
143        // Update-after-configure is already guaranteed (see impls module).
144        // NOTE: Update-after-data-change should be required but is hard to
145        // detect; we could store a data hash but draw does not receive data.
146        // As such we don't bother recording this operation.
147    }
148
149    /// Size rules
150    ///
151    /// Requires a prior call to `configure`. When `axis.is_vertical()`,
152    /// requires a prior call to `size_rules` for the horizontal axis.
153    ///
154    /// Re-calling `size_rules` does not require additional actions.
155    pub fn size_rules(&mut self, id: &Id, axis: crate::layout::AxisInfo) {
156        if axis.is_horizontal() {
157            self.require(id, WidgetStatus::Configured);
158            *self = (*self).max(WidgetStatus::SizeRulesX);
159        } else {
160            self.require(id, WidgetStatus::SizeRulesX);
161            *self = (*self).max(WidgetStatus::SizeRulesY);
162        }
163    }
164
165    /// Set rect
166    ///
167    /// Requires calling `size_rules` for each axis. Re-calling `set_rect` does
168    /// not require additional actions.
169    pub fn set_rect(&mut self, id: &Id) {
170        self.require(id, WidgetStatus::SizeRulesY);
171        *self = WidgetStatus::SetRect;
172    }
173
174    /// Require that `set_rect` has been called
175    pub fn require_rect(&self, id: &Id) {
176        self.require(id, WidgetStatus::SetRect);
177    }
178}