mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-19 10:58:04 +08:00
Add parsing of XML layout files into a ParsedLayoutNode tree
This commit is contained in:
@@ -3,7 +3,7 @@ use crate::window_events;
|
||||
use crate::pipeline::Pipeline;
|
||||
use crate::texture::Texture;
|
||||
use crate::resource_cache::ResourceCache;
|
||||
use crate::draw_command::DrawCommand;
|
||||
use crate::component_layout::ComponentLayout;
|
||||
use crate::gui_node::GuiNode;
|
||||
use winit::event::*;
|
||||
use winit::event_loop::*;
|
||||
@@ -75,6 +75,8 @@ impl Application {
|
||||
let gui_root_data = GuiNode::new(swap_chain_descriptor.width, swap_chain_descriptor.height, ColorPalette::get_color_srgb(ColorPalette::Accent));
|
||||
let gui_root = rctree::Node::new(gui_root_data);
|
||||
|
||||
ComponentLayout::new();
|
||||
|
||||
Self {
|
||||
surface,
|
||||
adapter,
|
||||
|
||||
116
src/component_layout.rs
Normal file
116
src/component_layout.rs
Normal file
@@ -0,0 +1,116 @@
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use crate::parsed_layout_node::*;
|
||||
|
||||
pub struct ComponentLayout {
|
||||
|
||||
}
|
||||
|
||||
impl ComponentLayout {
|
||||
pub fn new() -> ComponentLayout {
|
||||
let parsed_layout_tree = Self::parse_xml_file("gui/window/main.xml").unwrap();
|
||||
for node in parsed_layout_tree.descendants() {
|
||||
println!("{:?}", node);
|
||||
}
|
||||
Self {}
|
||||
}
|
||||
|
||||
pub fn parse_xml_file(path: &str) -> io::Result<rctree::Node<ParsedLayoutNode>> {
|
||||
let source = fs::read_to_string(path)?;
|
||||
let parsed = xmlparser::Tokenizer::from(&source[..]);
|
||||
|
||||
let mut stack: Vec<rctree::Node<ParsedLayoutNode>> = Vec::new();
|
||||
let mut current: Option<rctree::Node<ParsedLayoutNode>> = None;
|
||||
let mut result: Option<rctree::Node<ParsedLayoutNode>> = None;
|
||||
|
||||
for token in parsed {
|
||||
match token.unwrap() {
|
||||
xmlparser::Token::ElementStart { prefix, local, .. } => {
|
||||
let namespace = String::from(prefix.as_str());
|
||||
let tag_name = String::from(local.as_str());
|
||||
|
||||
let new_parsed_layout_node = ParsedLayoutNode::new_tag(namespace, tag_name);
|
||||
|
||||
let new_node = rctree::Node::new(new_parsed_layout_node);
|
||||
current = Some(new_node);
|
||||
}
|
||||
xmlparser::Token::Attribute { prefix, local, value, .. } => {
|
||||
let colon_prefixed = prefix.start() > 0 && (prefix.start() == prefix.end());
|
||||
let key = if colon_prefixed {
|
||||
let slice = local.as_str();
|
||||
let mut string = String::with_capacity(slice.len() + 1);
|
||||
string.push(':');
|
||||
string.push_str(slice);
|
||||
string
|
||||
} else { String::from(local.as_str()) };
|
||||
let value = String::from(value.as_str());
|
||||
let attribute = (key, value);
|
||||
|
||||
match &mut current {
|
||||
Some(current_node) => {
|
||||
match &mut *current_node.borrow_mut() {
|
||||
ParsedLayoutNode::Tag(tag) => {
|
||||
// Add this attribute to the current node that has not yet reached its closing angle bracket
|
||||
tag.add_attribute(attribute);
|
||||
}
|
||||
ParsedLayoutNode::Text(_) => {
|
||||
panic!("Error adding attribute to tag when parsing XML layout in file: {}", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
panic!("Error adding attribute to tag when parsing XML layout in file: {}", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
xmlparser::Token::ElementEnd { end, .. } => {
|
||||
match end {
|
||||
// After adding any attributes, the opening tag ends
|
||||
xmlparser::ElementEnd::Open => {
|
||||
// After adding any attributes, we are now a layer deeper which the stack keeps track of
|
||||
let node_to_push = current.take().expect(&format!("Invalid syntax when parsing XML layout in file {}", path)[..]);
|
||||
stack.push(node_to_push);
|
||||
}
|
||||
// After adding any attributes, the self-closing tag ends
|
||||
xmlparser::ElementEnd::Empty => {
|
||||
let parent_node = stack.last_mut().expect(&format!("Invalid syntax when parsing XML layout in file: {}", path)[..]);
|
||||
let new_child = current.take().expect(&format!("Invalid syntax when parsing XML layout in file: {}", path)[..]);
|
||||
parent_node.append(new_child);
|
||||
}
|
||||
// The closing tag is reached
|
||||
xmlparser::ElementEnd::Close(..) => {
|
||||
let popped_node = stack.pop().expect(&format!("Encountered extra closing tag when parsing XML layout in file: {}", path)[..]);
|
||||
match stack.last_mut() {
|
||||
Some(parent_node) => {
|
||||
parent_node.append(popped_node);
|
||||
}
|
||||
None => {
|
||||
match result {
|
||||
None => result = Some(popped_node),
|
||||
Some(_) => panic!("Encountered multiple root-level tags when parsing XML layout in file: {}", path),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
xmlparser::Token::Text { text } => {
|
||||
let parent_node = stack.last_mut().expect(&format!("Encountered text outside the root tag when parsing XML layout in file: {}", path)[..]);
|
||||
let text_string = String::from(text.as_str());
|
||||
|
||||
if !text_string.trim().is_empty() {
|
||||
let text_node = ParsedLayoutNode::new_text(text_string);
|
||||
let new_node = rctree::Node::new(text_node);
|
||||
parent_node.append(new_node);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
match result {
|
||||
None => panic!("Invalid syntax when parsing XML layout in file: {}", path),
|
||||
Some(tree) => Ok(tree)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,8 @@ mod draw_command;
|
||||
mod gui_node;
|
||||
mod gui_attributes;
|
||||
mod window_events;
|
||||
mod component_layout;
|
||||
mod parsed_layout_node;
|
||||
|
||||
use application::Application;
|
||||
use winit::event_loop::EventLoop;
|
||||
|
||||
38
src/parsed_layout_node.rs
Normal file
38
src/parsed_layout_node.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
#[derive(Debug)]
|
||||
pub enum ParsedLayoutNode {
|
||||
Tag(ParsedLayoutTag),
|
||||
Text(String),
|
||||
}
|
||||
|
||||
impl ParsedLayoutNode {
|
||||
pub fn new_tag(namespace: String, tag: String) -> Self {
|
||||
Self::Tag(ParsedLayoutTag::new(namespace, tag))
|
||||
}
|
||||
|
||||
pub fn new_text(text: String) -> Self {
|
||||
Self::Text(text)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ParsedLayoutTag {
|
||||
pub namespace: Option<String>,
|
||||
pub tag: String,
|
||||
pub attributes: Vec<(String, String)>,
|
||||
}
|
||||
|
||||
impl ParsedLayoutTag {
|
||||
pub fn new(namespace: String, tag: String) -> Self {
|
||||
let namespace = if namespace.is_empty() { None } else { Some(namespace) };
|
||||
|
||||
Self {
|
||||
namespace,
|
||||
tag,
|
||||
attributes: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_attribute(&mut self, attribute: (String, String)) {
|
||||
self.attributes.push(attribute);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user