based/src/ui/primitives/display.rs
2025-01-21 09:00:45 +01:00

283 lines
7.7 KiB
Rust

use crate::ui::UIWidget;
use maud::{Markup, Render, html};
macro_rules! string_class_widget {
($name:ident) => {
pub struct $name(Box<dyn UIWidget>, String);
impl Render for $name {
fn render(&self) -> Markup {
self.render_with_class("")
}
}
impl UIWidget for $name {
fn can_inherit(&self) -> bool {
true
}
fn base_class(&self) -> Vec<String> {
vec![self.1.clone()]
}
fn extended_class(&self) -> Vec<String> {
let mut c = self.base_class();
c.extend_from_slice(&self.0.extended_class());
c
}
fn render_with_class(&self, class: &str) -> Markup {
if self.0.as_ref().can_inherit() {
self.0
.as_ref()
.render_with_class(&format!("{} {class}", self.base_class().join(" ")))
} else {
html! {
div class=(format!("{} {class}", self.base_class().join(" "))) {
(self.0.as_ref())
}
}
}
}
}
};
}
macro_rules! constructor {
($name:ident, $class:literal) => {
#[allow(non_snake_case)]
pub fn $name<T: UIWidget + 'static>(inner: T) -> Self {
Self(Box::new(inner), $class.to_string())
}
};
}
pub enum BreakValue {
Auto,
Avoid,
All,
AvoidPage,
Page,
Left,
Right,
Column,
}
impl BreakValue {
pub const fn to_value(&self) -> &str {
match self {
BreakValue::Auto => "auto",
BreakValue::Avoid => "avoid",
BreakValue::All => "all",
BreakValue::AvoidPage => "break-page",
BreakValue::Page => "page",
BreakValue::Left => "left",
BreakValue::Right => "right",
BreakValue::Column => "column",
}
}
}
#[allow(non_snake_case)]
pub fn BreakAfter<T: UIWidget + 'static>(value: BreakValue, inner: T) -> BreakWidget {
BreakWidget(Box::new(inner), false, value)
}
#[allow(non_snake_case)]
pub fn BreakBefore<T: UIWidget + 'static>(value: BreakValue, inner: T) -> BreakWidget {
BreakWidget(Box::new(inner), true, value)
}
pub struct BreakWidget(Box<dyn UIWidget>, bool, BreakValue);
impl Render for BreakWidget {
fn render(&self) -> Markup {
self.render_with_class("")
}
}
impl UIWidget for BreakWidget {
fn can_inherit(&self) -> bool {
true
}
fn base_class(&self) -> Vec<String> {
if self.1 {
vec![format!("break-before-{}", self.2.to_value())]
} else {
vec![format!("break-after-{}", self.2.to_value())]
}
}
fn extended_class(&self) -> Vec<String> {
let mut c = self.base_class();
c.extend_from_slice(&self.0.extended_class());
c
}
fn render_with_class(&self, class: &str) -> Markup {
if self.0.as_ref().can_inherit() {
self.0
.as_ref()
.render_with_class(&format!("{} {class}", self.base_class().join(" ")))
} else {
html! {
div class=(format!("{} {class}", self.base_class().join(" "))) {
(self.0.as_ref())
}
}
}
}
}
pub enum BreakInsideValue {
Auto,
Avoid,
AvoidPage,
AvoidColumn,
}
impl BreakInsideValue {
pub const fn to_value(&self) -> &str {
match self {
BreakInsideValue::Auto => "break-inside-auto",
BreakInsideValue::Avoid => "break-inside-avoid",
BreakInsideValue::AvoidPage => "break-inside-avoid-page",
BreakInsideValue::AvoidColumn => "break-inside-avoid-column",
}
}
}
#[allow(non_snake_case)]
pub fn BreakInside<T: UIWidget + 'static>(value: BreakValue, inner: T) -> BreakWidget {
BreakWidget(Box::new(inner), true, value)
}
pub struct BreakInsideWidget(Box<dyn UIWidget>, BreakValue);
impl Render for BreakInsideWidget {
fn render(&self) -> Markup {
self.render_with_class("")
}
}
impl UIWidget for BreakInsideWidget {
fn can_inherit(&self) -> bool {
true
}
fn base_class(&self) -> Vec<String> {
vec![self.1.to_value().to_string()]
}
fn extended_class(&self) -> Vec<String> {
let mut c = self.base_class();
c.extend_from_slice(&self.0.extended_class());
c
}
fn render_with_class(&self, class: &str) -> Markup {
if self.0.as_ref().can_inherit() {
self.0
.as_ref()
.render_with_class(&format!("{} {class}", self.base_class().join(" ")))
} else {
html! {
div class=(format!("{} {class}", self.base_class().join(" "))) {
(self.0.as_ref())
}
}
}
}
}
string_class_widget!(BoxDecorationBreak);
impl BoxDecorationBreak {
constructor!(Clone, "box-decoration-clone");
constructor!(Slice, "box-decoration-slice");
}
string_class_widget!(BoxSizing);
impl BoxSizing {
constructor!(Border, "box-border");
constructor!(Content, "box-content");
}
string_class_widget!(Display);
impl Display {
constructor!(Block, "block");
constructor!(InlineBlock, "inline-block");
constructor!(Inline, "inline");
constructor!(Flex, "flex");
constructor!(InlineFlex, "inline-flex");
constructor!(Table, "table");
constructor!(InlineTable, "inline-table");
constructor!(TableCaption, "table-caption");
constructor!(TableCell, "table-cell");
constructor!(TableColumn, "table-column");
constructor!(TableColumnGroup, "table-column-group");
constructor!(TableFooterGroup, "table-footer-group");
constructor!(TableHeaderGroup, "table-header-group");
constructor!(TableRowGroup, "table-row-group");
constructor!(TableRow, "table-row");
constructor!(FlowRoot, "flow-root");
constructor!(Grid, "grid");
constructor!(InlineGrid, "inline-grid");
constructor!(Contents, "contents");
constructor!(ListItem, "list-item");
constructor!(Hidden, "hidden");
}
string_class_widget!(Float);
impl Float {
constructor!(Start, "float-start");
constructor!(End, "float-end");
constructor!(Left, "float-left");
constructor!(Right, "float-right");
constructor!(None, "float-none");
}
string_class_widget!(Clear);
impl Clear {
constructor!(Start, "clear-start");
constructor!(End, "clear-end");
constructor!(Left, "clear-left");
constructor!(Right, "clear-right");
constructor!(Both, "clear-both");
constructor!(None, "clear-none");
}
string_class_widget!(ObjectFit);
impl ObjectFit {
constructor!(Contain, "object-contain");
constructor!(Cover, "object-cover");
constructor!(Fill, "object-fill");
constructor!(None, "object-none");
constructor!(ScaleDown, "object-scale-down");
}
string_class_widget!(Overflow);
impl Overflow {
constructor!(Auto, "overflow-auto");
constructor!(Hidden, "overflow-hidden");
constructor!(Clip, "overflow-clip");
constructor!(Visible, "overflow-visible");
constructor!(Scroll, "overflow-scroll");
constructor!(XAuto, "overflow-x-auto");
constructor!(YAuto, "overflow-y-auto");
constructor!(XHidden, "overflow-x-hidden");
constructor!(YHidden, "overflow-y-hidden");
constructor!(XClip, "overflow-x-clip");
constructor!(YClip, "overflow-y-clip");
constructor!(XVisible, "overflow-x-visible");
constructor!(YVisible, "overflow-y-visible");
constructor!(XScroll, "overflow-x-scroll");
constructor!(YScroll, "overflow-y-scroll");
}