graphics-style 0.3.0

The styles of all graphics elements
Documentation
(* ::Package:: *)

(* ::Subsection::Closed:: *)
(*Prepare Data*)


SetDirectory@NotebookDirectory[];
styleRaw = Import["../meta-data.wl"];
styleGrouped = styleRaw["styleGroup"];
styleFlatten = DeleteDuplicatesBy[styleRaw["styleAtom"], #field&];
styleSubtype = Values[Association[(#field -> #)& /@ styleFlatten][[#subtype]]]&;


(* ::Subsection::Closed:: *)
(*Resolve*)


(* ::Subsubsection::Closed:: *)
(*Content*)


buildHead = "use super::*;";


getDrawXX[item_Association] := TemplateApply["
    /// Get default [<*\"`\"*>`typeOuter`<*\"`\"*>] when missing.
    #[serde(skip_serializing_if = \"Option::is_none\")]
	pub `field`: Option<`typeOuter`>,
",
    item
];
buildDrawXX[data_] := TemplateApply["
/// Get default style when not specified.
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
pub struct StyleContext {`1`}
",
    {
        getDrawXX /@ data // StringJoin
    }
];


getDrawXXInner[item_Association] := TemplateApply["
    /// Get the [<*\"`\"*>`typeOuter`<*\"`\"*>] from theme and state.
    pub fn `field`(&self) -> `typeOuter` {
        self.once.`field`.or(self.local.`field`).or(self.theme.`field`).unwrap_or_default()
    }
",
    item
];
buildDrawXXInner[data_] := {
    "impl StyleResolver {",
    getDrawXXInner /@ data,
    "}"
};


text = Flatten@{
    buildHead,
    buildDrawXX @ styleFlatten,
    buildDrawXXInner @ styleFlatten
};
Export["src/resolver/content.rs", StringRiffle[text , "\n\n"], "Text"];


(* ::Subsubsection::Closed:: *)
(*Resolved*)


buildHead = "use super::*;";


getDrawXX[item_Association] := TemplateApply["
    /// Get the config of [<*\"`\"*>crate::`typeOuter`<*\"`\"*>]
	pub `field`: `typeInner`,
",
    item
];
buildDrawXX[data_] := {
    TemplateApply["
/// Get default style when not specified.
#[derive(`derive`, Serialize, Deserialize)]
pub struct `typeSuper` {
",
        data
    ],
    getDrawXX /@ styleSubtype[data]
    ,
    "}"
};


getDrawXXField[item_Association] := TemplateApply[
    "`field`: style.`field`.unwrap_or(self.`field`()).value`isCopy`,",
    item
];
buildFnResolve[item_Association] := {
    TemplateApply["
    /// Get the [<*\"`\"*>crate::`typeSuper`<*\"`\"*>] from theme and state.
    pub fn resolve_`field`(&self, style: crate::`typeSuper`) -> `typeSuper` {
        `typeSuper` {
",
        item
    ],
    getDrawXXField /@ styleSubtype[item] // StringJoin,
    "}}"
};


text = Flatten@{
    buildHead,
    buildDrawXX /@ styleGrouped,
    "impl StyleResolver {",
    buildFnResolve /@ styleGrouped,
    "}"
};
Export["src/resolver/resolved.rs", StringRiffle[text, "\n\n"], "Text"];


(* ::Subsection::Closed:: *)
(*Shapes*)


(* ::Subsubsection::Closed:: *)
(*Shape*)


buildHead = "use super::*;";


getXX[item_Association] := TemplateApply["
/// `docs`
/// `details`
#[derive(`derive`, Serialize, Deserialize)]
#[serde(into = \"`typeInner`\", from = \"`typeInner`\")]
pub struct `typeOuter` {
    /// Actual value for [<*\"`\"*>StyleResolver::`field`<*\"`\"*>]
    pub value: `typeInner`,
}
",
    item
];
buildXX[data_] := getXX @ data;


getXXStyle[item_Association] := TemplateApply["
    /// `docs`, see more in [<*\"`\"*>`typeOuter`<*\"`\"*>].
	#[serde(skip_serializing_if = \"Option::is_none\")]
    pub `field`: Option<`typeOuter`>,
",
    item
];
buildXXStyle[data_] := { TemplateApply["
/// `docs`
/// `details`
#[derive(`derive`, Serialize, Deserialize)]
pub struct `typeSuper` {
",
    data
],
    getXXStyle /@ styleSubtype@data,
    "}"

};


text = Flatten@{
    buildHead,
    buildXXStyle /@ styleGrouped,
    getXX /@ styleFlatten
};
Export["src/shapes/shape.rs", StringRiffle[text , "\n\n"], "Text"];


(* ::Subsection:: *)
(*Traits*)


(* ::Subsubsection::Closed:: *)
(*From*)


buildHead = "use super::*;";


getDefault[item_Association] := TemplateApply["\
impl Default for `typeOuter` {
    fn default() -> Self {
        Self { value: `default` }
    }
}
",
    item
];
buildDefault[item_] := If[MissingQ@item["default"], "", getDefault@item];


getAddXX[item_Association] := TemplateApply["\
impl From<`typeInner`> for `typeOuter` {
    fn from(value: `typeInner`) -> Self {
        Self { value }
    }
}

impl Into<`typeInner`> for `typeOuter` {
    fn into(self) -> `typeInner` {
        self.value
    }
}
",
    item
];
buildFromXX[data_] := getAddXX@data;


getAddSelf[item_Association] := TemplateApply["self.`field` = rhs.`field`;", item];
getSelfClone[item_Association] := TemplateApply["self.`field` = rhs.`field`.clone();", item];
buildAddSelf[data_Association] := TemplateApply["\
impl AddAssign<Self> for `3` {
    fn add_assign(&mut self, rhs: Self) {`1`}
}

impl AddAssign<&Self> for `3` {
    fn add_assign(&mut self, rhs: &Self) {`2`}
}",
    {
        getAddSelf /@ styleSubtype@data // StringJoin,
        getSelfClone /@ styleSubtype@data // StringJoin,
        data["type"]
    }
];


getEq[item_Association] := TemplateApply["\
impl PartialEq<f32> for `typeOuter` {
    fn eq(&self, other: &f32) -> bool {
        self.value.eq(other)
    }
}

impl PartialOrd<f32> for `typeOuter` {
    fn partial_cmp(&self, other: &f32) -> Option<Ordering> {
        self.value.partial_cmp(other)
    }
}
",
    item
];
buildEq[data_] := If[data["typeInner"] === "f32", getEq@data, Nothing];


text = Flatten@{
    buildHead,
    buildDefault /@ styleFlatten,
    buildFromXX /@ styleFlatten,
    buildEq /@ styleFlatten
};
Export["src/traits/convert.rs", StringRiffle[text , "\n\n"], "Text"];


(* ::Subsubsection:: *)
(*AddAssign*)


buildHead = "use super::*;";


getAddSuper[item_Association] := TemplateApply["
impl AddAssign<`typeOuter`> for `typeSuper` {
    fn add_assign(&mut self, rhs: `typeOuter`) {
        self.`field` = Some(rhs);
    }
}

impl AddAssign<&`typeOuter`> for `typeSuper` {
    fn add_assign(&mut self, rhs: &`typeOuter`) {
        self.`field` = Some(rhs.clone());
    }
}
",
    item
];
buildSuper[data_] := getAddSuper@data;


getAddXX[item_Association] := TemplateApply["
impl AddAssign<`typeOuter`> for StyleContext {
    fn add_assign(&mut self, rhs: `typeOuter`) {
        self.`field` = Some(rhs);
    }
}

impl AddAssign<&`typeOuter`> for StyleContext {
    fn add_assign(&mut self, rhs: &`typeOuter`) {
        self.`field` = Some(rhs.clone());
    }
}
",
    item
];
buildAddXX[data_] := getAddXX@data;


getAddSelf[item_Association] := TemplateApply["self.`field` = rhs.`field`;", item];
getSelfClone[item_Association] := TemplateApply["self.`field` = rhs.`field`.clone();", item];
buildAddSelf[data_Association] := TemplateApply["\
impl AddAssign<Self> for `3` {
    fn add_assign(&mut self, rhs: Self) {`1`}
}

impl AddAssign<&Self> for `3` {
    fn add_assign(&mut self, rhs: &Self) {`2`}
}",
    {
        getAddSelf /@ styleSubtype@data // StringJoin,
        getSelfClone /@ styleSubtype@data // StringJoin,
        data["typeSuper"]
    }
];


upcast = Flatten@{
    buildHead,
    buildAddXX /@ styleFlatten,
    buildAddSelf /@ styleGrouped
};
Export["src/traits/add_assign.rs", StringRiffle[upcast , "\n\n"], "Text"];


(* ::Subsubsection:: *)
(*DrawStyle*)


buildHead = "use super::*;";


getDrawXX[item_Association] := TemplateApply["\
impl GraphicsStyle for `typeOuter` {
    fn draw_style(&self, state: &mut StyleContext) {
        state.`field` = Some(self.clone());
    }
}

",
    item
];
buildDrawXX[data_] := getDrawXX[data];


getDrawXXStyle[item_Association] := TemplateApply[
    "state.`field` = Some(self.`field`.unwrap_or_default());",
    item
];
buildDrawXXStyle[data_] := TemplateApply["\
impl GraphicsStyle for `2` {
    fn draw_style(&self, state: &mut StyleContext) {
`1`
    }
}
",
    {
        getDrawXXStyle /@ styleSubtype@data // StringJoin,
        data["typeSuper"]
    }
];


drawStyle = Flatten@{
    buildHead,
    buildDrawXX /@ styleFlatten,
    buildDrawXXStyle /@ styleGrouped
};
Export["src/traits/draw_style.rs", StringRiffle[drawStyle , "\n\n"], "Text"]'