use crate::*; pub trait HasSize { fn size (&self) -> &Measure; } #[macro_export] macro_rules! has_size { (<$E:ty>|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => { impl $(<$($L),*$($T $(: $U)?),*>)? HasSize<$E> for $Struct $(<$($L),*$($T),*>)? { fn size (&$self) -> &Measure<$E> { $cb } } } } impl LayoutDebug for E {} pub trait LayoutDebug { fn debug > (other: W) -> DebugOverlay { DebugOverlay(Default::default(), other) } } pub struct DebugOverlay>(PhantomData, pub W); /// A widget that tracks its render width and height #[derive(Default)] pub struct Measure { _engine: PhantomData, pub x: Arc, pub y: Arc, } impl Clone for Measure { fn clone (&self) -> Self { Self { _engine: Default::default(), x: self.x.clone(), y: self.y.clone(), } } } impl std::fmt::Debug for Measure { fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { f.debug_struct("Measure") .field("width", &self.x) .field("height", &self.y) .finish() } } impl Measure { pub fn w (&self) -> usize { self.x.load(Relaxed) } pub fn h (&self) -> usize { self.y.load(Relaxed) } pub fn wh (&self) -> [usize;2] { [self.w(), self.h()] } pub fn set_w (&self, w: impl Into) { self.x.store(w.into(), Relaxed) } pub fn set_h (&self, h: impl Into) { self.y.store(h.into(), Relaxed) } pub fn set_wh (&self, w: impl Into, h: impl Into) { self.set_w(w); self.set_h(h); } pub fn format (&self) -> String { format!("{}x{}", self.w(), self.h()) } pub fn new () -> Self { Self { _engine: PhantomData::default(), x: Arc::new(0.into()), y: Arc::new(0.into()), } } } impl Render for Measure { fn min_size (&self, _: [u16;2]) -> Perhaps<[u16;2]> { Ok(Some([0u16.into(), 0u16.into()].into())) } fn render (&self, to: &mut TuiOutput) -> Usually<()> { self.set_w(to.area().w()); self.set_h(to.area().h()); Ok(()) } } impl Measure { pub fn debug (&self) -> ShowMeasure { ShowMeasure(&self) } } pub struct ShowMeasure<'a>(&'a Measure); render!(|self: ShowMeasure<'a>|render(|to|Ok({ let w = self.0.w(); let h = self.0.h(); to.blit(&format!(" {w} x {h} "), to.area.x(), to.area.y(), Some( Style::default().bold().italic().bg(Color::Rgb(255, 0, 255)).fg(Color::Rgb(0,0,0)) )) })));