initial commit - red rectangle

This commit is contained in:
Sarah Jamie Lewis 2020-07-04 11:35:37 -07:00
commit 26570d6073
8 changed files with 2166 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
.idea

1928
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

13
Cargo.toml Normal file
View File

@ -0,0 +1,13 @@
[package]
name = "rqml"
version = "0.1.0"
authors = ["Sarah Jamie Lewis <sarah@openprivacy.ca>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
pest = "2.1.3"
pest_derive = "2.1.0"
orbtk = "0.3.1-alpha1"
specs = { version = "0.16.1", features = ["specs-derive"] }

5
README.md Normal file
View File

@ -0,0 +1,5 @@
rqml is an experimental ui toolkit for rust.
Parsing the QML files into a hierarchy
Parsing the hierarchy into something that can be rendered.

29
pest/qml.pest Normal file
View File

@ -0,0 +1,29 @@
COMMENT = _{ "/*" ~ (!"*/" ~ ANY)* ~ "*/" }
string = ${ "\"" ~ inner ~ "\"" }
inner = @{ char* }
char = {
!("\"" | "\\") ~ ANY
| "\\" ~ ("\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t")
| "\\" ~ ("u" ~ ASCII_HEX_DIGIT{4})
}
number = @{
"-"?
~ ("0" | ASCII_NONZERO_DIGIT ~ ASCII_DIGIT*)
~ ("." ~ ASCII_DIGIT*)?
~ (^"e" ~ ("+" | "-")? ~ ASCII_DIGIT+)?
}
alpha = { 'a'..'z' | 'A'..'Z' }
digit = { '0'..'9' }
ident = { (alpha | digit | ".")+}
version = {digit* ~ "." ~ digit*}
import = {"import" ~ WHITE_SPACE ~ ident ~ WHITE_SPACE ~ version ~ NEWLINE*}
property = {WHITE_SPACE* ~ ident ~ ":" ~ WHITE_SPACE* ~ (number|string |ident) ~ NEWLINE* }
body = {WHITE_SPACE* ~ ident ~ WHITE_SPACE ~ "{" ~ NEWLINE* ~ (property|body)+ ~ NEWLINE* ~ WHITE_SPACE* ~ "}" ~ NEWLINE?}
qml = {import* ~ NEWLINE* ~ body}

12
res/example.qml Normal file
View File

@ -0,0 +1,12 @@
import QtQuick 2.3
Rectangle {
width: 200
height: 500
color: "red"
Text {
anchors.centerIn: parent
text: "Hello, Erinn!"
}
}

18
src/components.rs Normal file
View File

@ -0,0 +1,18 @@
use specs::Component;
use specs::prelude::*;
#[derive(Component, Debug)]
pub struct Item {
pub(crate) name: String
}
#[derive(Component, Debug)]
pub struct Dimensions {
pub(crate) width: f64,
pub(crate) height: f64,
}
#[derive(Component, Debug)]
pub struct Text {
pub(crate) text: String
}

159
src/main.rs Normal file
View File

@ -0,0 +1,159 @@
use orbtk::prelude::*;
extern crate pest;
#[macro_use]
extern crate pest_derive;
use pest::Parser;
use pest::iterators::{Pair, Pairs};
use crate::Value::{QmlString, QmlNumber, QmlIdent};
use std::borrow::Borrow;
#[derive(Parser)]
#[grammar = "../pest/qml.pest"]
struct QmlParser;
pub mod components;
#[derive(Debug, Clone)]
enum Value {
QmlString(String),
QmlNumber(f64),
QmlIdent(String),
}
#[derive(Debug, Clone)]
struct QML {
properties: HashMap<String, Value>,
children: HashMap<String, QML>
}
fn parse_qml(qml: Pairs<Rule>) -> QML {
let mut qmldoc = QML { properties: Default::default(), children: Default::default()};
for pair in qml {
// println!("Rule {:?} Str {}", pair.as_rule(), pair.as_str());
match pair.as_rule() {
Rule::import => {
let mut tokens = pair.into_inner();
println!("Found new Import {} ", tokens.next().unwrap().as_str());
},
Rule::body => {
let mut tokens = pair.into_inner();
let ident = tokens.next().unwrap().as_str();
println!("Found new Body: {} ", ident);
qmldoc.children.insert(String::from(ident), parse_qml(tokens.into_iter()));
},
Rule::property => {
let mut tokens = pair.into_inner();
let ident = tokens.next().unwrap().as_str();
let value = tokens.next().unwrap();
// let value = tokens.next().unwrap().as_str();
match value.as_rule() {
Rule::number => {
let num: f64 = value.as_str().parse().unwrap();
println!("Found new Property: {} {:?}", ident, num);
qmldoc.properties.insert(String::from(ident), QmlNumber(num));
}
Rule::string => {
println!("Found new Property: {} {}", ident, value.as_str());
qmldoc.properties.insert(String::from(ident), QmlString(String::from(value.into_inner().next().unwrap().as_str())));
}
Rule::ident => {
println!("Found new Property: {} {}", ident, value.as_str());
qmldoc.properties.insert(String::from(ident), QmlIdent(String::from(value.as_str())));
}
_ => {}
}
},
_ => return parse_qml(pair.into_inner())
}
}
qmldoc
}
fn main() {
Application::new()
.window(|ctx| {
let qml = include_str!("../res/example.qml");
let qml_tokens = QmlParser::parse(Rule::qml, qml).unwrap_or_else(|e| panic!("{}", e));
let qml_doc = parse_qml(qml_tokens);
let top_level = qml_doc.children.clone();
let width = match top_level.get("Rectangle").unwrap().properties.get("width").unwrap() {
QmlNumber(num) => num.clone(),
_ => {0.0}
};
let height = match top_level.get("Rectangle").unwrap().properties.get("height").unwrap() {
QmlNumber(num) => num.clone(),
_ => {0.0}
};
println!("{:?}",qml_doc);
Window::create()
.title("QML")
.position((100.0, 100.0))
.resizeable(true)
.size(width, height)
.child(render_ctx(ctx, &top_level).unwrap())
.build(ctx)
})
.run();
}
fn render_ctx(ctx: &mut BuildContext, qml: &HashMap<String, QML>) -> Option<Entity> {
for (ident, child) in qml.iter() {
match ident.as_str() {
"Rectangle" => {
let width = match child.properties.get("width").unwrap() {
QmlNumber(num) => num.clone(),
_ => {0.0}
};
let height = match child.properties.get("height").unwrap() {
QmlNumber(num) => num.clone(),
_ => {0.0}
};
let color = match child.properties.get("color").unwrap() {
QmlString(col) => match col.as_str() {
"red" => Color::rgb(0xff,00,00),
_ => Color::rgb(0xff,0xff,0xff)
}
_ => Color::rgb(0xff,0xff,0xff)
};
if child.children.len() == 0 {
return Some(Container::create().width(width).height(height).background(color).build(ctx))
} else {
match render_ctx(ctx, child.children.borrow()) {
Some(entity) => {
return Some(Container::create().width(width).height(height).background(color).child(entity).build(ctx))
}
_ => return Some(Container::create().width(width).height(height).background(color).build(ctx))
}
}
},
"Text" => {
let text = match child.properties.get("text").unwrap() {
QmlString(text) => text.clone(),
_ => {String::new()}
};
let mut tt = TextBlock::create();
tt = tt.text(text);
match child.properties.get("anchors.centerIn").unwrap() {
QmlIdent(str) => {
if str.eq("parent") {
tt = tt.vertical_alignment(Alignment::Center);
tt = tt.horizontal_alignment(Alignment::Center);
}
},
_ => {}
}
return Some(tt.build(ctx))
}
_ => {println!("unknown ident {}", ident)}
}
}
None
}