use super::Id;
use crate::geom::Rect;
use crate::layout::AxisInfo;
#[allow(unused)] use crate::{Events, Layout, Widget};
use std::ops::{Range, RangeInclusive};
#[derive(Clone, Debug)]
pub struct ChildIndices(usize, usize);
impl ChildIndices {
#[inline]
pub fn none() -> Self {
ChildIndices(0, 0)
}
#[inline]
pub fn one(index: usize) -> Self {
ChildIndices(index, index + 1)
}
#[inline]
pub fn range(range: impl Into<Self>) -> Self {
range.into()
}
#[inline]
pub(crate) fn as_range(&self) -> Range<usize> {
self.0..self.1
}
}
impl IntoIterator for ChildIndices {
type Item = usize;
type IntoIter = ChildIndicesIter;
#[inline]
fn into_iter(self) -> ChildIndicesIter {
ChildIndicesIter(self.0..self.1)
}
}
impl From<Range<usize>> for ChildIndices {
#[inline]
fn from(range: Range<usize>) -> Self {
ChildIndices(range.start, range.end)
}
}
impl From<RangeInclusive<usize>> for ChildIndices {
#[inline]
fn from(range: RangeInclusive<usize>) -> Self {
ChildIndices(*range.start(), *range.end() + 1)
}
}
#[derive(Clone, Debug)]
pub struct ChildIndicesIter(Range<usize>);
impl Iterator for ChildIndicesIter {
type Item = usize;
#[inline]
fn next(&mut self) -> Option<usize> {
self.0.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl ExactSizeIterator for ChildIndicesIter {}
impl DoubleEndedIterator for ChildIndicesIter {
#[inline]
fn next_back(&mut self) -> Option<usize> {
self.0.next_back()
}
}
#[macro_export]
macro_rules! widget_core {
() => {
compile_error!(
"This macro may only be used in a struct affected by the `#[widget]` attribute"
);
};
}
pub trait WidgetCore: Default {
fn id_ref(&self) -> &Id;
#[inline]
fn id(&self) -> Id {
self.id_ref().clone()
}
#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
fn status(&self) -> WidgetStatus;
#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
#[inline]
fn require_status(&self, status: WidgetStatus) {
self.status().require(self.id_ref(), status);
}
#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
#[inline]
fn require_status_size_rules(&self) {
self.require_status(WidgetStatus::SizeRulesY);
}
#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
#[inline]
fn require_status_set_rect(&self) {
self.require_status(WidgetStatus::SetRect);
}
#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
fn set_status(&mut self, status: WidgetStatus);
#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
fn update_status_configured(&mut self) {
let status = self.status().max(WidgetStatus::Configured);
self.set_status(status);
}
#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
fn update_status_size_rules(&mut self, axis: AxisInfo) {
let id = self.id_ref();
let mut status = self.status();
if axis.is_horizontal() {
status.require(id, WidgetStatus::Configured);
status = status.max(WidgetStatus::SizeRulesX);
} else {
status.require(id, WidgetStatus::SizeRulesX);
status = status.max(WidgetStatus::SizeRulesY);
}
self.set_status(status);
}
#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
#[inline]
fn set_status_set_rect(&mut self) {
self.set_status(WidgetStatus::SetRect);
}
}
pub trait WidgetCoreRect: WidgetCore {
fn rect(&self) -> Rect;
fn set_rect(&mut self, rect: Rect);
}
#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
#[derive(Default, Debug)]
pub struct DefaultCoreType {
pub _id: Id,
pub status: WidgetStatus,
}
impl WidgetCore for DefaultCoreType {
#[inline]
fn id_ref(&self) -> &Id {
&self._id
}
#[inline]
fn status(&self) -> WidgetStatus {
self.status
}
#[inline]
fn set_status(&mut self, status: WidgetStatus) {
self.status = status;
}
}
#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
#[derive(Default, Debug)]
pub struct DefaultCoreRectType {
pub _rect: Rect,
pub _id: Id,
pub status: WidgetStatus,
}
impl WidgetCore for DefaultCoreRectType {
#[inline]
fn id_ref(&self) -> &Id {
&self._id
}
#[inline]
fn status(&self) -> WidgetStatus {
self.status
}
#[inline]
fn set_status(&mut self, status: WidgetStatus) {
self.status = status;
}
}
impl WidgetCoreRect for DefaultCoreRectType {
#[inline]
fn rect(&self) -> Rect {
self._rect
}
#[inline]
fn set_rect(&mut self, rect: Rect) {
self._rect = rect;
}
}
#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
pub enum WidgetStatus {
#[default]
New,
Configured,
SizeRulesX,
SizeRulesY,
SetRect,
}
impl WidgetStatus {
fn require(self, id: &Id, expected: Self) {
if self < expected {
panic!("WidgetStatus of {id}: require {expected:?}, found {self:?}");
}
}
#[inline]
pub fn is_configured(self) -> bool {
self >= WidgetStatus::Configured
}
#[inline]
pub fn is_sized(self) -> bool {
self >= WidgetStatus::SetRect
}
}