Partial implementation of the WindowDom system

This commit is contained in:
Keavon Chambers
2020-09-01 14:06:47 -07:00
parent 062ed8bae2
commit 0a48f0fabb
4 changed files with 128 additions and 19 deletions
+12
View 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
+5 -5
View File
@@ -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)] #[derive(Debug, Clone, PartialEq)]
pub enum LayoutComponentNode { pub enum LayoutComponentNode {
Tag(LayoutComponentTag), Tag(LayoutComponentTag),
@@ -81,19 +81,19 @@ pub struct LayoutComponentDefinition {
/// Name of the component in "namespace:name" format /// Name of the component in "namespace:name" format
pub name: (String, String), pub name: (String, String),
/// User-defined attribute parameters, which are prefixed with ':' /// User-defined attribute parameters, which are prefixed with ':'
pub user_attributes: Vec<VariableParameter>, pub parameters: Vec<VariableParameter>,
} }
impl LayoutComponentDefinition { impl LayoutComponentDefinition {
/// Construct a definition for a layout component given its name in "namespace:name" format with an empty set of parameters /// 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 { pub fn new(name: (String, String)) -> Self {
let user_attributes = vec![]; let parameters = vec![];
Self { name, user_attributes } Self { name, parameters }
} }
/// Add a parameter definition (with its name, types, and default value) to this component definition /// Add a parameter definition (with its name, types, and default value) to this component definition
pub fn add_parameter(&mut self, parameter: VariableParameter) { pub fn add_parameter(&mut self, parameter: VariableParameter) {
self.user_attributes.push(parameter); self.parameters.push(parameter);
} }
} }
+11 -10
View File
@@ -7,15 +7,15 @@ use std::collections::HashSet;
use std::fs; use std::fs;
use std::io; use std::io;
pub struct LayoutSystem { pub struct LayoutSystem<'a> {
windows: Vec<WindowDom>, windows: Vec<WindowDom<'a>>,
loaded_components: ResourceCache<FlatComponent>, loaded_components: ResourceCache<FlatComponent>,
attribute_parser: AttributeParser, 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 /// 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 { Self {
windows: vec![], windows: vec![],
loaded_components: ResourceCache::new(), loaded_components: ResourceCache::new(),
@@ -24,17 +24,18 @@ impl LayoutSystem {
} }
/// Load and construct a new window from a layout component /// 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 // Preload the component and its dependencies
self.preload_component(name) self.preload_component(name)
.expect(&format!("Failure loading layout component '{}'", Self::component_name(name))[..]); .expect(&format!("Failure loading layout component '{}'", Self::component_name(name))[..]);
// Get the now-loaded component // Get the now-loaded component
let window_root_component_name = Self::component_name(name); 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 // 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); self.windows.push(new_window);
} }
@@ -67,7 +68,7 @@ impl LayoutSystem {
} }
// Go through each parameter attribute and preload any default values of layouts // 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() { for default in definition.type_sequence_default.iter() {
if let TypeValue::Layout(layouts) = default { if let TypeValue::Layout(layouts) = default {
for layout in layouts { for layout in layouts {
@@ -175,7 +176,7 @@ impl LayoutSystem {
}).collect::<Vec<_>>(); }).collect::<Vec<_>>();
cloned_tag.set_content(children); 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) Some(cloned_tag)
}) })
.collect::<Vec<_>>(); .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 /// 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; let (namespace, file) = name;
if namespace.len() > 0 { if namespace.len() > 0 {
format!("{}:{}", namespace, file) format!("{}:{}", namespace, file)
+100 -4
View File
@@ -1,9 +1,105 @@
use crate::layout_abstract_syntax::*; 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 { impl<'a> WindowDom<'a> {
pub fn new(root_component: &FlatComponent) -> WindowDom { pub fn new(root_component: &str, window_size: (u32, u32), loaded_components: &'a ResourceCache<FlatComponent>) -> WindowDom<'a> {
Self {} 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(&parameter.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)
} }
} }