use crate::*; use std::sync::{Arc, atomic::{AtomicUsize, Ordering::Relaxed}}; //use ratatui::prelude::{Style, Color}; // TODO: 🡘 🡙 ←🡙→ indicator to expand window when too small 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 } } } } /// A widget that tracks its render width and height #[derive(Default)] pub struct Measure { _engine: PhantomData, pub x: Arc, pub y: Arc, } impl Content for Measure { fn render (&self, to: &mut E::Output) { self.x.store(to.area().w().into(), Relaxed); self.y.store(to.area().h().into(), Relaxed); } } 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()), } } pub fn of > (&self, item: T) -> Bsp, T> { Bsp::b(Fill::xy(&self), item) } } ///// A scrollable area. //pub struct Scroll(pub F, pub Direction, pub u64, PhantomData) //where //E: Engine, //F: Send + Sync + Fn(&mut dyn FnMut(&dyn Content)->Usually<()>)->Usually<()>; //pub trait ContentDebug { //fn debug > (other: W) -> DebugOverlay { //DebugOverlay(Default::default(), other) //} //} //impl ContentDebug for E {} //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 TuiOut) -> Usually<()> { //self.set_w(to.area().w()); //self.set_h(to.area().h()); //Ok(()) //} //} //impl Measure { //pub fn debug (&self) -> ShowMeasure { //ShowMeasure(&self) //} //} //render!(|self: ShowMeasure<'a>|render(|to: &mut TuiOut|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)) //)) //}))); //pub struct ShowMeasure<'a>(&'a Measure); //pub struct DebugOverlay>(PhantomData, pub W); //impl> Render for DebugOverlay { //fn min_size (&self, to: [u16;2]) -> Perhaps<[u16;2]> { //self.1.min_size(to) //} //fn render (&self, to: &mut TuiOut) -> Usually<()> { //let [x, y, w, h] = to.area(); //self.1.render(to)?; //Ok(to.blit(&format!("{w}x{h}+{x}+{y}"), x, y, Some(Style::default().green()))) //} //}