use crate::layout::{LayoutRect, Length, Padding, Position, Size, ZIndex};
use crate::render::inline::InlineLayout;
use crate::runtime::editing::EditorState;
use crate::style::{Color, ComputedStyle, TuiStyle};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PseudoLayout {
pub rect: LayoutRect,
pub position: Position,
}
#[derive(Debug, Clone, PartialEq)]
pub struct AnonymousIfc {
pub rect: LayoutRect,
pub inline_layout: InlineLayout,
pub child_range: (usize, usize),
}
#[derive(Debug, Clone, Default, PartialEq)]
pub struct PresentationStyle {
pub fg: Option<Color>,
pub bg: Option<Color>,
pub border_fg: Option<Color>,
pub width: Option<Size>,
pub height: Option<Size>,
pub padding: Option<Padding>,
pub gap: Option<u16>,
pub top: Option<Length>,
pub right: Option<Length>,
pub bottom: Option<Length>,
pub left: Option<Length>,
pub z_index: Option<ZIndex>,
}
impl PresentationStyle {
pub fn is_empty(&self) -> bool {
self.fg.is_none()
&& self.bg.is_none()
&& self.border_fg.is_none()
&& self.width.is_none()
&& self.height.is_none()
&& self.padding.is_none()
&& self.gap.is_none()
&& self.top.is_none()
&& self.right.is_none()
&& self.bottom.is_none()
&& self.left.is_none()
&& self.z_index.is_none()
}
pub fn clear(&mut self) {
*self = PresentationStyle::default();
}
}
#[derive(Debug, Default, Clone, PartialEq)]
pub struct TuiExt {
pub inline_style: TuiStyle,
pub before_content: Option<String>,
pub after_content: Option<String>,
pub scroll_x: usize,
pub scroll_y: usize,
pub scroll_content_width: usize,
pub scroll_content_height: usize,
pub layout: LayoutRect,
pub content_layout: LayoutRect,
pub before_layout: Option<PseudoLayout>,
pub after_layout: Option<PseudoLayout>,
pub tree_has_positioned_pseudo: bool,
pub tree_has_collapse: bool,
pub inline_layout: Option<InlineLayout>,
pub anonymous_blocks: Vec<AnonymousIfc>,
pub computed: Option<ComputedStyle>,
pub computed_prev: Option<ComputedStyle>,
pub presentation: PresentationStyle,
pub computed_before: Option<ComputedStyle>,
pub computed_after: Option<ComputedStyle>,
pub computed_backdrop: Option<ComputedStyle>,
pub computed_selection: Option<ComputedStyle>,
pub computed_scrollbar: Option<ComputedStyle>,
pub computed_scrollbar_thumb: Option<ComputedStyle>,
pub style_dirty: bool,
pub layout_dirty: bool,
pub editor_state: Option<Box<EditorState>>,
pub canvas_paint: Option<crate::runtime::builtins::canvas::CanvasPaint>,
}
impl TuiExt {
pub fn new() -> Self {
Self::default()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::style::Color;
#[test]
fn defaults_are_sensible() {
let ext = TuiExt::new();
assert!(ext.inline_style.is_empty());
assert_eq!(ext.scroll_x, 0);
assert_eq!(ext.scroll_y, 0);
assert!(ext.inline_style.is_empty());
assert!(ext.before_content.is_none());
assert!(ext.after_content.is_none());
assert_eq!(ext.layout, LayoutRect::default());
assert!(ext.computed.is_none());
assert!(ext.computed_before.is_none());
assert!(ext.computed_after.is_none());
assert!(!ext.style_dirty);
assert!(!ext.layout_dirty);
}
#[test]
fn clone_preserves_fields() {
let ext = TuiExt {
inline_style: TuiStyle::new()
.fg(Color::Rgb(255, 0, 0))
.width(Size::Fixed(80))
.padding(Padding::all(2)),
..Default::default()
};
let cloned = ext.clone();
assert_eq!(
cloned.inline_style.fg,
Some(crate::style::Value::Specified(
crate::style::TuiColor::Literal(Color::Rgb(255, 0, 0))
))
);
assert_eq!(
cloned.inline_style.width,
Some(crate::style::Value::Specified(Size::Fixed(80)))
);
assert_eq!(
cloned.inline_style.padding,
Some(crate::style::Value::Specified(Padding::all(2)))
);
}
#[test]
fn partial_eq_works() {
let a = TuiExt {
inline_style: TuiStyle::new().width(Size::Fixed(10)),
..Default::default()
};
let b = TuiExt {
inline_style: TuiStyle::new().width(Size::Fixed(10)),
..Default::default()
};
let c = TuiExt {
inline_style: TuiStyle::new().width(Size::Fixed(11)),
..Default::default()
};
assert_eq!(a, b);
assert_ne!(a, c);
}
}