mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-12-23 10:11:54 +00:00
172 lines
4.6 KiB
Rust
172 lines
4.6 KiB
Rust
use crate::layout_abstract_types::*;
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum LayoutAbstractNode {
|
|
Tag(LayoutAbstractTag),
|
|
Text(String),
|
|
}
|
|
|
|
impl LayoutAbstractNode {
|
|
pub fn new_tag(namespace: String, name: String) -> Self {
|
|
Self::Tag(LayoutAbstractTag::new(namespace, name))
|
|
}
|
|
|
|
pub fn new_text(text: String) -> Self {
|
|
Self::Text(text)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct LayoutAbstractTag {
|
|
pub namespace: String,
|
|
pub name: String,
|
|
/// Layout attributes, which are used by the layout engine.
|
|
pub layout_attributes: LayoutAttributes,
|
|
/// The special content attribute, representing the inner elements of this tag.
|
|
pub content: Option<AttributeValue>,
|
|
/// User-defined attributes, which are prefixed with ':'
|
|
pub attributes: Vec<Attribute>,
|
|
}
|
|
|
|
impl LayoutAbstractTag {
|
|
pub fn new(namespace: String, name: String) -> Self {
|
|
Self {
|
|
namespace,
|
|
name,
|
|
layout_attributes: Default::default(),
|
|
content: None,
|
|
attributes: Vec::new(),
|
|
}
|
|
}
|
|
|
|
pub fn add_attribute(&mut self, attribute: Attribute) {
|
|
// User-defined attribute
|
|
if attribute.name.chars().next().unwrap() == ':' {
|
|
self.attributes.push(attribute);
|
|
}
|
|
else {
|
|
self.add_builtin_attribute(attribute);
|
|
}
|
|
}
|
|
|
|
fn add_builtin_attribute(&mut self, attribute: Attribute) {
|
|
match &attribute.name[..] {
|
|
// The special `content` attribute
|
|
"content" => self.content = Some(attribute.value),
|
|
// Layout attributes, stored separately
|
|
"width" => self.layout_attributes.width = attribute.dimension(),
|
|
"height" => self.layout_attributes.height = attribute.dimension(),
|
|
"x-align" => self.layout_attributes.x_align = attribute.percent(),
|
|
"y-align" => self.layout_attributes.y_align = attribute.percent(),
|
|
"x-padding" => self.layout_attributes.padding.set_horizontal(attribute.dimension()),
|
|
"y-padding" => self.layout_attributes.padding.set_vertical(attribute.dimension()),
|
|
"padding" => self.layout_attributes.padding = attribute.box_dimensions(),
|
|
"x-spacing" => self.layout_attributes.spacing.set_horizontal(attribute.dimension()),
|
|
"y-spacing" => self.layout_attributes.spacing.set_vertical(attribute.dimension()),
|
|
"spacing" => self.layout_attributes.spacing = attribute.box_dimensions(),
|
|
_ => panic!("unknown builtin attribute {}", attribute.name),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct Attribute {
|
|
pub name: String,
|
|
pub value: AttributeValue,
|
|
}
|
|
|
|
impl Attribute {
|
|
pub fn new(name: String, value: AttributeValue) -> Self {
|
|
Self { name, value }
|
|
}
|
|
|
|
/// Extracts this attribute's values as typed values.
|
|
fn values(self) -> Vec<TypeValue> {
|
|
if let AttributeValue::TypeValue(values) = self.value {
|
|
values
|
|
.into_iter()
|
|
.map(|value| {
|
|
if let TypeValueOrArgument::TypeValue(value) = value {
|
|
value
|
|
}
|
|
else {
|
|
todo!("variable arguments are note yet supported")
|
|
}
|
|
})
|
|
.collect()
|
|
}
|
|
else {
|
|
todo!("variable arguments are not yet supported")
|
|
}
|
|
}
|
|
|
|
/// Converts this attribute's value into a single dimension.
|
|
fn dimension(self) -> Dimension {
|
|
let values = self.values();
|
|
assert_eq!(values.len(), 1, "expected a single value");
|
|
values[0].expect_dimension()
|
|
}
|
|
|
|
/// Extracts a percentage from this attribute's value.
|
|
fn percent(self) -> f32 {
|
|
match self.dimension() {
|
|
Dimension::Percent(value) => value,
|
|
_ => panic!("expected a percentage"),
|
|
}
|
|
}
|
|
|
|
/// Converts this attribute's values into box dimensions.
|
|
fn box_dimensions(self) -> BoxDimensions {
|
|
let values = self.values();
|
|
match values.len() {
|
|
1 => {
|
|
let value = values[0].expect_dimension();
|
|
BoxDimensions::all(value)
|
|
},
|
|
2 => {
|
|
let vertical = values[0].expect_dimension();
|
|
let horizontal = values[1].expect_dimension();
|
|
BoxDimensions::symmetric(vertical, horizontal)
|
|
},
|
|
4 => {
|
|
let top = values[0].expect_dimension();
|
|
let right = values[1].expect_dimension();
|
|
let bottom = values[2].expect_dimension();
|
|
let left = values[3].expect_dimension();
|
|
BoxDimensions::new(top, right, bottom, left)
|
|
},
|
|
_ => panic!("expected 1, 2 or 4 values"),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum AttributeValue {
|
|
VariableParameter(VariableParameter),
|
|
TypeValue(Vec<TypeValueOrArgument>),
|
|
}
|
|
|
|
/// Layout-specific attributes.
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
pub struct LayoutAttributes {
|
|
pub width: Dimension,
|
|
pub height: Dimension,
|
|
pub x_align: f32,
|
|
pub y_align: f32,
|
|
pub spacing: BoxDimensions,
|
|
pub padding: BoxDimensions,
|
|
}
|
|
|
|
impl Default for LayoutAttributes {
|
|
fn default() -> Self {
|
|
let zero_box = BoxDimensions::all(Dimension::AbsolutePx(0.0));
|
|
Self {
|
|
width: Dimension::Inner,
|
|
height: Dimension::Inner,
|
|
x_align: 0.0,
|
|
y_align: 0.0,
|
|
spacing: zero_box,
|
|
padding: zero_box,
|
|
}
|
|
}
|
|
}
|