use std::marker::PhantomData;
use zhc_utils::graphics::{Color, Font, FontSize, HAlign, Justify, Thickness, VAlign};
pub trait Class: 'static {
const STYLE: Style = Style::DEFAULT;
}
#[derive(Clone)]
pub struct Style {
pub font: Font,
pub font_size: FontSize,
pub font_halign: HAlign,
pub font_valign: VAlign,
pub font_color: Color,
pub padding: Thickness,
pub spacing: Thickness,
pub border_width: Thickness,
pub border_color: Color,
pub fill_color: Color,
pub corner_radius: Thickness,
pub halign: HAlign,
pub valign: VAlign,
pub hjustify: Justify,
pub vjustify: Justify,
pub draw_separators: bool,
}
impl Style {
pub const DEFAULT: Self = Style {
font: Font("Courier"),
font_size: FontSize::new(10.),
font_halign: HAlign::Left,
font_valign: VAlign::Center,
font_color: Color::BLACK,
padding: Thickness::new(2.),
spacing: Thickness::new(2.),
border_width: Thickness::new(0.2),
border_color: Color::TRANSPARENT,
fill_color: Color::TRANSPARENT,
corner_radius: Thickness::ZERO,
halign: HAlign::Center,
valign: VAlign::Center,
hjustify: Justify::Pack,
vjustify: Justify::Pack,
draw_separators: false,
};
pub fn modify(self, modifier: StyleModifier) -> Style {
Style {
font: modifier.font.unwrap_or(self.font),
font_size: modifier.font_size.unwrap_or(self.font_size),
font_halign: modifier.font_halign.unwrap_or(self.font_halign),
font_valign: modifier.font_valign.unwrap_or(self.font_valign),
font_color: modifier.font_color.unwrap_or(self.font_color),
padding: modifier.padding.unwrap_or(self.padding),
spacing: modifier.spacing.unwrap_or(self.spacing),
border_width: modifier.border_width.unwrap_or(self.border_width),
border_color: modifier.border_color.unwrap_or(self.border_color),
fill_color: modifier.fill_color.unwrap_or(self.fill_color),
corner_radius: modifier.corner_radius.unwrap_or(self.corner_radius),
halign: modifier.halign.unwrap_or(self.halign),
valign: modifier.valign.unwrap_or(self.valign),
hjustify: modifier.hjustify.unwrap_or(self.hjustify),
vjustify: modifier.vjustify.unwrap_or(self.vjustify),
draw_separators: modifier.draw_separators.unwrap_or(self.draw_separators),
}
}
}
impl Default for Style {
fn default() -> Self {
Self::DEFAULT
}
}
#[derive(Clone)]
pub struct StyleModifier {
pub font: Option<Font>,
pub font_size: Option<FontSize>,
pub font_halign: Option<HAlign>,
pub font_valign: Option<VAlign>,
pub font_color: Option<Color>,
pub padding: Option<Thickness>,
pub spacing: Option<Thickness>,
pub border_width: Option<Thickness>,
pub border_color: Option<Color>,
pub fill_color: Option<Color>,
pub corner_radius: Option<Thickness>,
pub halign: Option<HAlign>,
pub valign: Option<VAlign>,
pub hjustify: Option<Justify>,
pub vjustify: Option<Justify>,
pub draw_separators: Option<bool>,
}
impl Default for StyleModifier {
fn default() -> Self {
Self::DEFAULT
}
}
impl StyleModifier {
pub const DEFAULT: Self = StyleModifier {
font: None,
font_size: None,
font_halign: None,
font_valign: None,
font_color: None,
padding: None,
spacing: None,
border_width: None,
border_color: None,
fill_color: None,
corner_radius: None,
halign: None,
valign: None,
hjustify: None,
vjustify: None,
draw_separators: None,
};
}
pub struct Styler<C: Class> {
class: PhantomData<C>,
modifier: StyleModifier,
}
impl<C: Class> Styler<C> {
pub fn new(modifier: Option<StyleModifier>) -> Self {
let modifier = modifier.unwrap_or(StyleModifier::DEFAULT);
Styler {
class: PhantomData,
modifier,
}
}
pub fn get(&self) -> Style {
C::STYLE.clone().modify(self.modifier.clone())
}
}
pub struct NoClass;
impl Class for NoClass {}
pub struct OpInputPortClass;
impl Class for OpInputPortClass {
const STYLE: Style = Style {
fill_color: Color::AQUAMARINE,
border_color: Color::BLACK,
padding: Thickness::new(2.),
..Style::DEFAULT
};
}
pub struct OpInputsClass;
impl Class for OpInputsClass {
const STYLE: Style = Style {
fill_color: Color::TRANSPARENT,
border_color: Color::TRANSPARENT,
padding: Thickness::new(2.),
..Style::DEFAULT
};
}
pub struct OpBodyClass;
impl Class for OpBodyClass {
const STYLE: Style = Style {
padding: Thickness::new(4.),
..Style::DEFAULT
};
}
pub struct OpCommentClass;
impl Class for OpCommentClass {
const STYLE: Style = Style {
padding: Thickness::new(4.),
font_color: Color::GRAY,
..Style::DEFAULT
};
}
pub struct OpOutputPortClass;
impl Class for OpOutputPortClass {
const STYLE: Style = Style {
fill_color: Color::AQUAMARINE,
border_color: Color::BLACK,
padding: Thickness::new(2.),
..Style::DEFAULT
};
}
pub struct OpOutputsClass;
impl Class for OpOutputsClass {
const STYLE: Style = Style {
fill_color: Color::TRANSPARENT,
border_color: Color::TRANSPARENT,
padding: Thickness::new(2.),
..Style::DEFAULT
};
}
pub struct InputOpClass;
impl Class for InputOpClass {
const STYLE: Style = Style {
fill_color: Color::SEASHELL,
valign: VAlign::Top,
border_color: Color::GRAY,
border_width: Thickness::new(0.7),
corner_radius: Thickness::new(4.),
draw_separators: true,
..Style::DEFAULT
};
}
pub struct OpClass;
impl Class for OpClass {
const STYLE: Style = Style {
fill_color: Color::ALICEBLUE,
valign: VAlign::Top,
border_color: Color::GRAY,
border_width: Thickness::new(0.7),
corner_radius: Thickness::new(4.),
draw_separators: true,
..Style::DEFAULT
};
}
pub struct EffectOpClass;
impl Class for EffectOpClass {
const STYLE: Style = Style {
fill_color: Color::HONEYDEW,
valign: VAlign::Top,
border_color: Color::GRAY,
border_width: Thickness::new(0.7),
corner_radius: Thickness::new(4.),
draw_separators: true,
..Style::DEFAULT
};
}
pub struct DummyClass;
impl Class for DummyClass {
const STYLE: Style = Style {
padding: Thickness::new(10.),
..Style::DEFAULT
};
}
pub struct LayerClass;
impl Class for LayerClass {
const STYLE: Style = Style {
padding: Thickness::new(0.),
spacing: Thickness::new(10.),
hjustify: Justify::Space,
..Style::DEFAULT
};
}
pub struct LayerSpacerClass;
impl Class for LayerSpacerClass {
const STYLE: Style = Style {
hjustify: Justify::Space,
padding: Thickness::new(0.),
spacing: Thickness::new(0.),
..Style::DEFAULT
};
}
pub struct LayersClass;
impl Class for LayersClass {
const STYLE: Style = Style {
padding: Thickness::new(10.),
spacing: Thickness::new(0.),
..Style::DEFAULT
};
}
pub struct CurveClass;
impl Class for CurveClass {
const STYLE: Style = Style {
border_width: Thickness::new(1.),
border_color: Color::GRAY,
..Style::DEFAULT
};
}
pub struct GroupClass;
impl Class for GroupClass {
const STYLE: Style = Style {
fill_color: Color::CORNFLOWERBLUE.with_opacity(0.2),
corner_radius: Thickness::new(10.),
padding: Thickness::new(4.),
spacing: Thickness::new(2.),
border_width: Thickness::new(1.),
border_color: Color::CORNFLOWERBLUE.with_opacity(0.3),
valign: VAlign::Top,
..Style::DEFAULT
};
}
pub struct GroupTitleClass;
impl Class for GroupTitleClass {
const STYLE: Style = Style {
font_size: FontSize::new(8.),
font_color: Color::BLACK.with_opacity(0.6),
padding: Thickness::new(5.),
spacing: Thickness::new(0.),
font_halign: HAlign::Left,
halign: HAlign::Left,
..Style::DEFAULT
};
}
pub struct GroupInputPortClass;
impl Class for GroupInputPortClass {
const STYLE: Style = Style {
fill_color: Color::LIGHTSKYBLUE,
border_color: Color::BLACK,
padding: Thickness::new(0.),
spacing: Thickness::new(0.),
..Style::DEFAULT
};
}
pub struct GroupOutputPortClass;
impl Class for GroupOutputPortClass {
const STYLE: Style = Style {
fill_color: Color::LIGHTSKYBLUE,
border_color: Color::BLACK,
padding: Thickness::new(0.),
spacing: Thickness::new(0.),
..Style::DEFAULT
};
}
pub struct GroupInputsClass;
impl Class for GroupInputsClass {
const STYLE: Style = Style {
fill_color: Color::TRANSPARENT,
border_color: Color::BLACK,
padding: Thickness::new(0.),
spacing: Thickness::new(0.),
hjustify: Justify::Space,
..Style::DEFAULT
};
}
pub struct GroupOutputsClass;
impl Class for GroupOutputsClass {
const STYLE: Style = Style {
fill_color: Color::TRANSPARENT,
border_color: Color::BLACK,
padding: Thickness::new(0.),
spacing: Thickness::new(0.),
hjustify: Justify::Space,
..Style::DEFAULT
};
}