mirror of
https://github.com/danbulant/cushy
synced 2026-06-19 22:41:10 +00:00
Added Widget::summarize
Debug printing widgets was quite verbose. While developing a widget, you often want to see a full debug printout, but this feature assumes that debug printing a WidgetInstance should show a summary of the widget, not a full debug printout containing cached glyph information of every label. By default, summarize just calls Debug, but this extra layer allows widgets to provide a more condensed summary and exclude details like caches. Originally, adding dbg!() around the theme example's UI yielded a whopping 20,324 lines of text. The summary code only prints 3,858 lines.
This commit is contained in:
parent
d1e21178e0
commit
0e6796318b
15 changed files with 222 additions and 28 deletions
|
|
@ -1,4 +1,5 @@
|
|||
use std::borrow::Cow;
|
||||
use std::fmt::Debug;
|
||||
use std::ops::Deref;
|
||||
|
||||
use interner::global::{GlobalString, StringPool};
|
||||
|
|
@ -12,7 +13,7 @@ static NAMES: StringPool<ahash::RandomState> =
|
|||
/// string exists. By ensuring all instances of each unique string are the same
|
||||
/// exact underlying instance, optimizations can be made that avoid string
|
||||
/// comparisons.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Name(GlobalString<ahash::RandomState>);
|
||||
|
||||
impl Name {
|
||||
|
|
@ -22,6 +23,12 @@ impl Name {
|
|||
}
|
||||
}
|
||||
|
||||
impl Debug for Name {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
Debug::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Name {
|
||||
type Target = str;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
use std::any::Any;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::hash_map;
|
||||
use std::fmt::Debug;
|
||||
use std::fmt::{Debug, Write};
|
||||
use std::ops::{
|
||||
Add, AddAssign, Bound, Deref, Div, Mul, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo,
|
||||
RangeToInclusive,
|
||||
|
|
@ -29,7 +29,7 @@ use crate::value::{Dynamic, IntoValue, Value};
|
|||
pub mod components;
|
||||
|
||||
/// A collection of style components organized by their name.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Styles(Arc<StyleData>);
|
||||
|
||||
impl Styles {
|
||||
|
|
@ -172,7 +172,21 @@ impl Styles {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
impl Debug for Styles {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut map = f.debug_struct("Styles");
|
||||
let mut component_name = String::new();
|
||||
for (name, component) in &self.0.components {
|
||||
component_name.clear();
|
||||
write!(&mut component_name, "{name:?}")?;
|
||||
|
||||
map.field(&component_name, component);
|
||||
}
|
||||
map.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
struct StyleData {
|
||||
components: AHashMap<ComponentName, Value<Component>>,
|
||||
}
|
||||
|
|
@ -519,7 +533,7 @@ impl TryFrom<Component> for CornerRadii<Dimension> {
|
|||
}
|
||||
|
||||
/// A 1-dimensional measurement that may be automatically calculated.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum FlexibleDimension {
|
||||
/// Automatically calculate this dimension.
|
||||
Auto,
|
||||
|
|
@ -532,6 +546,15 @@ impl FlexibleDimension {
|
|||
pub const ZERO: Self = Self::Dimension(Dimension::ZERO);
|
||||
}
|
||||
|
||||
impl Debug for FlexibleDimension {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Auto => f.write_str("Auto"),
|
||||
Self::Dimension(arg0) => Debug::fmt(arg0, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FlexibleDimension {
|
||||
fn default() -> Self {
|
||||
Self::ZERO
|
||||
|
|
@ -557,7 +580,7 @@ impl From<Lp> for FlexibleDimension {
|
|||
}
|
||||
|
||||
/// A 1-dimensional measurement.
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
pub enum Dimension {
|
||||
/// Physical Pixels
|
||||
Px(Px),
|
||||
|
|
@ -565,6 +588,15 @@ pub enum Dimension {
|
|||
Lp(Lp),
|
||||
}
|
||||
|
||||
impl Debug for Dimension {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Px(arg0) => Debug::fmt(arg0, f),
|
||||
Self::Lp(arg0) => Debug::fmt(arg0, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Dimension {
|
||||
fn default() -> Self {
|
||||
Self::ZERO
|
||||
|
|
@ -907,7 +939,7 @@ where
|
|||
}
|
||||
|
||||
/// A fully-qualified style component name.
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Hash)]
|
||||
#[derive(Clone, Eq, PartialEq, Hash)]
|
||||
pub struct ComponentName {
|
||||
/// The group name.
|
||||
pub group: Name,
|
||||
|
|
@ -925,6 +957,12 @@ impl ComponentName {
|
|||
}
|
||||
}
|
||||
|
||||
impl Debug for ComponentName {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}.{:?}", &self.group, &self.name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static Lazy<ComponentName>> for ComponentName {
|
||||
fn from(value: &'static Lazy<ComponentName>) -> Self {
|
||||
(**value).clone()
|
||||
|
|
|
|||
70
src/value.rs
70
src/value.rs
|
|
@ -624,14 +624,7 @@ where
|
|||
T: Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.0.state() {
|
||||
Ok(state) => f
|
||||
.debug_struct("Dynamic")
|
||||
.field("value", &state.wrapped.value)
|
||||
.field("generation", &state.wrapped.generation)
|
||||
.finish(),
|
||||
Err(_) => f.debug_tuple("Dynamic").field(&"<unable to lock>").finish(),
|
||||
}
|
||||
Debug::fmt(&DebugDynamicData(&self.0), f)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -722,12 +715,20 @@ impl From<String> for Dynamic<String> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DynamicMutexGuard<'a, T> {
|
||||
dynamic: &'a DynamicData<T>,
|
||||
guard: MutexGuard<'a, State<T>>,
|
||||
}
|
||||
|
||||
impl<T> Debug for DynamicMutexGuard<'_, T>
|
||||
where
|
||||
T: Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.guard.debug("DynamicMutexGuard", f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for DynamicMutexGuard<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
let mut during_state = self.dynamic.during_callback_state.lock().ignore_poison();
|
||||
|
|
@ -755,7 +756,6 @@ struct LockState {
|
|||
locked_thread: ThreadId,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DynamicData<T> {
|
||||
state: Mutex<State<T>>,
|
||||
during_callback_state: Mutex<Option<LockState>>,
|
||||
|
|
@ -859,6 +859,20 @@ impl<T> DynamicData<T> {
|
|||
}
|
||||
}
|
||||
|
||||
struct DebugDynamicData<'a, T>(&'a Arc<DynamicData<T>>);
|
||||
|
||||
impl<T> Debug for DebugDynamicData<'_, T>
|
||||
where
|
||||
T: Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.0.state() {
|
||||
Ok(state) => state.debug("Dynamic", f),
|
||||
Err(_) => f.debug_tuple("Dynamic").field(&"<unable to lock>").finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An error occurred while updating a value in a [`Dynamic`].
|
||||
pub enum ReplaceError<T> {
|
||||
/// The value was already equal to the one set.
|
||||
|
|
@ -953,6 +967,16 @@ impl<T> State<T> {
|
|||
|
||||
ChangeCallbacks(self.callbacks.clone())
|
||||
}
|
||||
|
||||
fn debug(&self, name: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
where
|
||||
T: Debug,
|
||||
{
|
||||
f.debug_struct(name)
|
||||
.field("value", &self.wrapped.value)
|
||||
.field("generation", &self.wrapped.generation.0)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Debug for State<T>
|
||||
|
|
@ -1167,7 +1191,6 @@ impl<T> PartialEq<WeakDynamic<T>> for Dynamic<T> {
|
|||
}
|
||||
|
||||
/// A reader that tracks the last generation accessed through this reader.
|
||||
#[derive(Debug)]
|
||||
pub struct DynamicReader<T> {
|
||||
source: Arc<DynamicData<T>>,
|
||||
read_generation: Generation,
|
||||
|
|
@ -1308,6 +1331,18 @@ impl<T> context::sealed::Trackable for DynamicReader<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Debug for DynamicReader<T>
|
||||
where
|
||||
T: Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("DynamicReader")
|
||||
.field("source", &DebugDynamicData(&self.source))
|
||||
.field("read_generation", &self.read_generation.0)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for DynamicReader<T> {
|
||||
fn clone(&self) -> Self {
|
||||
self.source.state().expect("deadlocked").readers += 1;
|
||||
|
|
@ -1514,7 +1549,6 @@ impl GetWidget<usize> for Vec<WidgetInstance> {
|
|||
impl<T, W> Switchable<T> for W where W: IntoDynamic<T> {}
|
||||
|
||||
/// A value that may be either constant or dynamic.
|
||||
#[derive(Debug)]
|
||||
pub enum Value<T> {
|
||||
/// A value that will not ever change externally.
|
||||
Constant(T),
|
||||
|
|
@ -1651,6 +1685,18 @@ impl<T> IntoDynamic<T> for Value<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Debug for Value<T>
|
||||
where
|
||||
T: Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Constant(arg0) => Debug::fmt(arg0, f),
|
||||
Self::Dynamic(arg0) => Debug::fmt(arg0, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for Value<T>
|
||||
where
|
||||
T: Clone,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use std::any::Any;
|
||||
use std::clone::Clone;
|
||||
use std::fmt::Debug;
|
||||
use std::fmt::{self, Debug};
|
||||
use std::ops::{ControlFlow, Deref, DerefMut};
|
||||
use std::panic::UnwindSafe;
|
||||
use std::sync::atomic::{self, AtomicU64};
|
||||
|
|
@ -51,6 +51,15 @@ pub trait Widget: Send + UnwindSafe + Debug + 'static {
|
|||
/// Redraw the contents of this widget.
|
||||
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>);
|
||||
|
||||
/// Writes a summary of this widget into `fmt`.
|
||||
///
|
||||
/// The default implementation calls [`Debug::fmt`]. This function allows
|
||||
/// widget authors to print only publicly relevant information that will
|
||||
/// appear when debug formatting a [`WidgetInstance`].
|
||||
fn summarize(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
Debug::fmt(self, f)
|
||||
}
|
||||
|
||||
/// Layout this widget and returns the ideal size based on its contents and
|
||||
/// the `available_space`.
|
||||
#[allow(unused_variables)]
|
||||
|
|
@ -284,6 +293,15 @@ pub trait WrapperWidget: Debug + Send + UnwindSafe + 'static {
|
|||
/// Returns the child widget.
|
||||
fn child_mut(&mut self) -> &mut WidgetRef;
|
||||
|
||||
/// Writes a summary of this widget into `fmt`.
|
||||
///
|
||||
/// The default implementation calls [`Debug::fmt`]. This function allows
|
||||
/// widget authors to print only publicly relevant information that will
|
||||
/// appear when debug formatting a [`WidgetInstance`].
|
||||
fn summarize(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
Debug::fmt(self, f)
|
||||
}
|
||||
|
||||
/// Returns the behavior this widget should apply when positioned at the
|
||||
/// root of the window.
|
||||
#[allow(unused_variables)]
|
||||
|
|
@ -650,6 +668,10 @@ where
|
|||
fn allow_blur(&mut self, context: &mut EventContext<'_, '_>) -> bool {
|
||||
T::allow_blur(self, context)
|
||||
}
|
||||
|
||||
fn summarize(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
T::summarize(self, fmt)
|
||||
}
|
||||
}
|
||||
|
||||
/// A type that can create a [`WidgetInstance`].
|
||||
|
|
@ -1119,11 +1141,20 @@ where
|
|||
}
|
||||
|
||||
/// An instance of a [`Widget`].
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone)]
|
||||
pub struct WidgetInstance {
|
||||
data: Arc<WidgetInstanceData>,
|
||||
}
|
||||
|
||||
impl Debug for WidgetInstance {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.data.widget.try_lock() {
|
||||
Ok(widget) => widget.summarize(f),
|
||||
Err(_) => f.debug_struct("WidgetInstance").finish_non_exhaustive(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct WidgetInstanceData {
|
||||
id: WidgetId,
|
||||
|
|
@ -1372,9 +1403,7 @@ pub struct ManagedWidget {
|
|||
|
||||
impl Debug for ManagedWidget {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ManagedWidget")
|
||||
.field("widget", &self.widget)
|
||||
.finish_non_exhaustive()
|
||||
Debug::fmt(&self.widget, f)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1567,7 +1596,7 @@ impl WidgetGuard<'_> {
|
|||
}
|
||||
|
||||
/// A list of [`Widget`]s.
|
||||
#[derive(Debug, Default, Eq, PartialEq)]
|
||||
#[derive(Default, Eq, PartialEq)]
|
||||
#[must_use]
|
||||
pub struct Children {
|
||||
ordered: Vec<WidgetInstance>,
|
||||
|
|
@ -1647,6 +1676,12 @@ impl Children {
|
|||
}
|
||||
}
|
||||
|
||||
impl Debug for Children {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
Debug::fmt(&self.ordered, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Dynamic<Children> {
|
||||
/// Returns `self` as a vertical [`Stack`] of rows.
|
||||
#[must_use]
|
||||
|
|
@ -1687,7 +1722,7 @@ impl DerefMut for Children {
|
|||
}
|
||||
|
||||
/// A child widget
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub enum WidgetRef {
|
||||
/// An unmounted child widget
|
||||
Unmounted(WidgetInstance),
|
||||
|
|
@ -1732,6 +1767,15 @@ impl AsRef<WidgetId> for WidgetRef {
|
|||
}
|
||||
}
|
||||
|
||||
impl Debug for WidgetRef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Unmounted(arg0) => Debug::fmt(arg0, f),
|
||||
Self::Mounted(arg0) => Debug::fmt(arg0, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The unique id of a [`WidgetInstance`].
|
||||
///
|
||||
/// Each [`WidgetInstance`] is guaranteed to have a unique [`WidgetId`] across
|
||||
|
|
|
|||
|
|
@ -329,6 +329,13 @@ impl VisualState {
|
|||
}
|
||||
|
||||
impl Widget for Button {
|
||||
fn summarize(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
fmt.debug_struct("Button")
|
||||
.field("content", &self.content)
|
||||
.field("kind", &self.kind)
|
||||
.finish()
|
||||
}
|
||||
|
||||
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||
#![allow(clippy::similar_names)]
|
||||
|
||||
|
|
|
|||
|
|
@ -104,6 +104,13 @@ impl WrapperWidget for Collapse {
|
|||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
fn summarize(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
fmt.debug_struct("Collapse")
|
||||
.field("collapse", &self.collapse)
|
||||
.field("child", &self.child)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
|||
|
|
@ -224,6 +224,14 @@ impl WrapperWidget for Container {
|
|||
size: padded.into_unsigned(),
|
||||
}
|
||||
}
|
||||
|
||||
fn summarize(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
fmt.debug_struct("Container")
|
||||
.field("background", &self.background)
|
||||
.field("padding", &self.padding)
|
||||
.field("child", &self.child)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// The selected background configuration of a [`Container`].
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ use crate::widgets::Space;
|
|||
/// `Slider` in a `Data` widget to store the animation handle.
|
||||
#[derive(Debug)]
|
||||
pub struct Data<T> {
|
||||
_data: T,
|
||||
#[allow(dead_code)] // This affects formatting in Debug to rename it.
|
||||
data: T,
|
||||
child: WidgetRef,
|
||||
}
|
||||
|
||||
|
|
@ -27,7 +28,7 @@ impl<T> Data<T> {
|
|||
/// Returns a new instance that wraps `widget` and stores `value`.
|
||||
pub fn new_wrapping(value: T, widget: impl MakeWidget) -> Self {
|
||||
Self {
|
||||
_data: value,
|
||||
data: value,
|
||||
child: WidgetRef::new(widget),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -192,6 +192,13 @@ impl<const COLUMNS: usize> Widget for Grid<COLUMNS> {
|
|||
|
||||
content_size
|
||||
}
|
||||
|
||||
fn summarize(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
fmt.debug_struct("Grid")
|
||||
.field("dimensions", &self.columns)
|
||||
.field("entries", &self.rows)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// The orientation (Row/Column) of an [`Grid`] or
|
||||
|
|
|
|||
|
|
@ -935,6 +935,8 @@ where
|
|||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Input")
|
||||
.field("text", &self.value)
|
||||
.field("mask_symbol", &self.mask_symbol)
|
||||
.field("placeholder", &self.placeholder)
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,6 +86,10 @@ impl Widget for Label {
|
|||
|
||||
prepared.size.try_cast().unwrap_or_default()
|
||||
}
|
||||
|
||||
fn summarize(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
fmt.debug_tuple("Label").field(&self.text).finish()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_make_widget {
|
||||
|
|
|
|||
|
|
@ -277,6 +277,13 @@ impl Widget for Scroll {
|
|||
HANDLED
|
||||
}
|
||||
}
|
||||
|
||||
fn summarize(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
fmt.debug_struct("Scroll")
|
||||
.field("enabled", &self.enabled)
|
||||
.field("contents", &self.contents)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
fn constrain_child(constraint: ConstraintLimit, measured: Px) -> UPx {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use crate::widget::{MakeWidget, MakeWidgetWithId, WidgetInstance};
|
|||
use crate::widgets::button::{ButtonBackground, ButtonHoverBackground, ButtonKind};
|
||||
|
||||
/// A selectable, labeled widget representing a value.
|
||||
#[derive(Debug)]
|
||||
pub struct Select<T> {
|
||||
/// The value this button represents.
|
||||
pub value: T,
|
||||
|
|
|
|||
|
|
@ -728,6 +728,14 @@ where
|
|||
// using a mouse wheel as an input is annoying.
|
||||
HANDLED
|
||||
}
|
||||
|
||||
fn summarize(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
fmt.debug_struct("Slider")
|
||||
.field("value", &self.value)
|
||||
.field("min", &self.minimum)
|
||||
.field("max", &self.maximum)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
struct TrackSpec {
|
||||
|
|
|
|||
|
|
@ -169,4 +169,11 @@ impl Widget for Stack {
|
|||
|
||||
content_size
|
||||
}
|
||||
|
||||
fn summarize(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
fmt.debug_struct("Stack")
|
||||
.field("orientation", &self.layout.orientation)
|
||||
.field("children", &self.children)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue