mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-04 13:30:48 +00:00
Partial implementation of the WindowDom system
This commit is contained in:
parent
3205e8d274
commit
a977da0adc
4 changed files with 128 additions and 19 deletions
12
dom_pseudocode.xml
Normal file
12
dom_pseudocode.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<window:main>
|
||||
<col width="100%" height="100%">
|
||||
</col>
|
||||
</window:main>
|
||||
|
||||
|
||||
Start with the given root component
|
||||
For each child_component:
|
||||
Get the component of the associated child_component tag
|
||||
Create a DomNode for this component
|
||||
Give this DomNode its width and height and other layout attributes
|
||||
Recursively load its children
|
|
@ -45,7 +45,7 @@ pub type NodeOrDefTree = rctree::Node<LayoutComponentNodeOrDefinition>;
|
|||
|
||||
// ====================================================================================================
|
||||
|
||||
/// Representation of an XML node with either another XML tag (`LayoutComponentTag`) or a text node (just a `String`)
|
||||
/// Representation of an XML node with either another XML tag (`LayoutComponentTag`) or a text node (a vector of alternating `TemplateStringSegment::String`s and `TemplateStringSegment::Argument`s)
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum LayoutComponentNode {
|
||||
Tag(LayoutComponentTag),
|
||||
|
@ -81,19 +81,19 @@ pub struct LayoutComponentDefinition {
|
|||
/// Name of the component in "namespace:name" format
|
||||
pub name: (String, String),
|
||||
/// User-defined attribute parameters, which are prefixed with ':'
|
||||
pub user_attributes: Vec<VariableParameter>,
|
||||
pub parameters: Vec<VariableParameter>,
|
||||
}
|
||||
|
||||
impl LayoutComponentDefinition {
|
||||
/// Construct a definition for a layout component given its name in "namespace:name" format with an empty set of parameters
|
||||
pub fn new(name: (String, String)) -> Self {
|
||||
let user_attributes = vec![];
|
||||
Self { name, user_attributes }
|
||||
let parameters = vec![];
|
||||
Self { name, parameters }
|
||||
}
|
||||
|
||||
/// Add a parameter definition (with its name, types, and default value) to this component definition
|
||||
pub fn add_parameter(&mut self, parameter: VariableParameter) {
|
||||
self.user_attributes.push(parameter);
|
||||
self.parameters.push(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,15 +7,15 @@ use std::collections::HashSet;
|
|||
use std::fs;
|
||||
use std::io;
|
||||
|
||||
pub struct LayoutSystem {
|
||||
windows: Vec<WindowDom>,
|
||||
pub struct LayoutSystem<'a> {
|
||||
windows: Vec<WindowDom<'a>>,
|
||||
loaded_components: ResourceCache<FlatComponent>,
|
||||
attribute_parser: AttributeParser,
|
||||
}
|
||||
|
||||
impl LayoutSystem {
|
||||
impl<'a> LayoutSystem<'a> {
|
||||
/// Construct the `LayoutSystem` with zero windows, an empty cache of component XML layouts, and an `AttributeParser` with its regex parsers
|
||||
pub fn new() -> LayoutSystem {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
windows: vec![],
|
||||
loaded_components: ResourceCache::new(),
|
||||
|
@ -24,17 +24,18 @@ impl LayoutSystem {
|
|||
}
|
||||
|
||||
/// Load and construct a new window from a layout component
|
||||
pub fn add_window(&mut self, name: (&str, &str)) {
|
||||
pub fn add_window(&'a mut self, name: (&str, &str)) {
|
||||
// Preload the component and its dependencies
|
||||
self.preload_component(name)
|
||||
.expect(&format!("Failure loading layout component '{}'", Self::component_name(name))[..]);
|
||||
|
||||
// Get the now-loaded component
|
||||
let window_root_component_name = Self::component_name(name);
|
||||
let window_root_component = self.loaded_components.get(&window_root_component_name[..]).unwrap();
|
||||
// let window_root_component = self.loaded_components.get(&window_root_component_name[..]).unwrap();
|
||||
// println!("FC: {:#?}", window_root_component);
|
||||
|
||||
// Construct the window and save it
|
||||
let new_window = WindowDom::new(window_root_component);
|
||||
let new_window = WindowDom::new(&window_root_component_name[..], (1920, 1080), &self.loaded_components);
|
||||
self.windows.push(new_window);
|
||||
}
|
||||
|
||||
|
@ -67,7 +68,7 @@ impl LayoutSystem {
|
|||
}
|
||||
|
||||
// Go through each parameter attribute and preload any default values of layouts
|
||||
for definition in &component.own_info.user_attributes {
|
||||
for definition in &component.own_info.parameters {
|
||||
for default in definition.type_sequence_default.iter() {
|
||||
if let TypeValue::Layout(layouts) = default {
|
||||
for layout in layouts {
|
||||
|
@ -175,7 +176,7 @@ impl LayoutSystem {
|
|||
}).collect::<Vec<_>>();
|
||||
cloned_tag.set_content(children);
|
||||
|
||||
// Return this LayoutComponentTag within the component's root definition tag
|
||||
// Return this `LayoutComponentTag` within the component's root definition tag
|
||||
Some(cloned_tag)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
@ -338,7 +339,7 @@ impl LayoutSystem {
|
|||
}
|
||||
|
||||
/// Get a string in `namespace:name` format (or just `name` for primitives) given a namespace and component name
|
||||
fn component_name(name: (&str, &str)) -> String {
|
||||
pub fn component_name(name: (&str, &str)) -> String {
|
||||
let (namespace, file) = name;
|
||||
if namespace.len() > 0 {
|
||||
format!("{}:{}", namespace, file)
|
||||
|
|
|
@ -1,9 +1,105 @@
|
|||
use crate::layout_abstract_syntax::*;
|
||||
use crate::layout_abstract_types::*;
|
||||
use crate::{layout_system::*, resource_cache::ResourceCache};
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct WindowDom {}
|
||||
pub struct WindowDom<'a> {
|
||||
pub dom: rctree::Node<DomNode>,
|
||||
loaded_components: &'a ResourceCache<FlatComponent>,
|
||||
}
|
||||
|
||||
impl WindowDom {
|
||||
pub fn new(root_component: &FlatComponent) -> WindowDom {
|
||||
Self {}
|
||||
impl<'a> WindowDom<'a> {
|
||||
pub fn new(root_component: &str, window_size: (u32, u32), loaded_components: &'a ResourceCache<FlatComponent>) -> WindowDom<'a> {
|
||||
let mut layout_attributes = LayoutAttributes::default();
|
||||
layout_attributes.width = Dimension::AbsolutePx(window_size.0 as f64);
|
||||
layout_attributes.height = Dimension::AbsolutePx(window_size.1 as f64);
|
||||
|
||||
let dom = Self::build_dom_from_component(root_component, &layout_attributes, &vec![], loaded_components);
|
||||
Self { dom, loaded_components }
|
||||
}
|
||||
|
||||
fn build_dom_from_component(
|
||||
root_component: &str,
|
||||
layout_attributes: &LayoutAttributes,
|
||||
parameters: &Vec<AttributeArg>,
|
||||
loaded_components: &'a ResourceCache<FlatComponent>,
|
||||
) -> rctree::Node<DomNode> {
|
||||
// Instantiate the DOM node and put it in a tree node
|
||||
let component = loaded_components.get(root_component).unwrap();
|
||||
let dom_node = DomNode::from_component(component, layout_attributes, parameters);
|
||||
let mut tree = rctree::Node::new(dom_node);
|
||||
|
||||
// Recursively build the child `DomNode` tree node instances
|
||||
let child_nodes = component
|
||||
.child_components
|
||||
.iter()
|
||||
.map(|child| {
|
||||
// Get the child name used as the component cache key
|
||||
let (namespace, name) = &child.name;
|
||||
let component_name = LayoutSystem::component_name((namespace, name));
|
||||
|
||||
// Recursively build the child `DomNode` component instance
|
||||
Self::build_dom_from_component(&component_name[..], &child.layout_arguments, &child.user_arguments, loaded_components)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Append each child `DomNode` tree node
|
||||
for child in child_nodes {
|
||||
tree.append(child);
|
||||
}
|
||||
|
||||
// Return the tree that has been recursively built with sibling and child components
|
||||
tree
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DomNode {
|
||||
pub cache_name: String,
|
||||
pub layout_attributes: LayoutAttributes,
|
||||
pub variable_bindings: HashMap<String, Vec<TypeValueOrArgument>>,
|
||||
}
|
||||
|
||||
impl DomNode {
|
||||
pub fn new(cache_name: String, layout_attributes: LayoutAttributes, variable_bindings: HashMap<String, Vec<TypeValueOrArgument>>) -> Self {
|
||||
Self {
|
||||
cache_name,
|
||||
layout_attributes,
|
||||
variable_bindings,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_component(component: &FlatComponent, layout_attributes: &LayoutAttributes, parameters: &Vec<AttributeArg>) -> Self {
|
||||
// Cached name of the loaded component
|
||||
let (namespace, name) = &component.own_info.name;
|
||||
let cache_name = LayoutSystem::component_name((&namespace[..], &name[..]));
|
||||
|
||||
// Every VARIABLE_NAME binding defined as a parameter on this component
|
||||
let mut variable_bindings = component
|
||||
.own_info
|
||||
.parameters
|
||||
.iter()
|
||||
.map(|parameter| {
|
||||
(
|
||||
// HashMap key is the parameter name
|
||||
parameter.name.clone(),
|
||||
// HashMap value is the parameter's defined default value
|
||||
parameter
|
||||
.type_sequence_default
|
||||
.iter()
|
||||
.map(|value| TypeValueOrArgument::TypeValue(value.clone()))
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
// Overwrite the defaults for given parameters
|
||||
for parameter in parameters {
|
||||
if !variable_bindings.contains_key(¶meter.name[..]) {
|
||||
panic!("Invalid argument {} given to the {} component", parameter.name, cache_name);
|
||||
}
|
||||
|
||||
variable_bindings.insert(parameter.name.clone(), parameter.value.clone());
|
||||
}
|
||||
|
||||
Self::new(cache_name, layout_attributes.clone(), variable_bindings)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue