Partial implementation of the WindowDom system

This commit is contained in:
Keavon Chambers 2020-09-01 14:06:47 -07:00
parent 3205e8d274
commit a977da0adc
4 changed files with 128 additions and 19 deletions

12
dom_pseudocode.xml Normal file
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

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)]
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);
}
}

View file

@ -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)

View 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(&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)
}
}