initial commit - red rectangle
This commit is contained in:
commit
26570d6073
|
@ -0,0 +1,2 @@
|
|||
/target
|
||||
.idea
|
File diff suppressed because it is too large
Load Diff
|
@ -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"] }
|
|
@ -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.
|
|
@ -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}
|
|
@ -0,0 +1,12 @@
|
|||
import QtQuick 2.3
|
||||
|
||||
Rectangle {
|
||||
width: 200
|
||||
height: 500
|
||||
color: "red"
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "Hello, Erinn!"
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue