rqml/src/main.rs

281 lines
9.9 KiB
Rust
Raw Normal View History

2020-07-04 18:35:37 +00:00
use orbtk::prelude::*;
2020-07-04 21:58:15 +00:00
use rhai::{packages::*, Engine, EvalAltResult, INT};
2020-07-04 18:35:37 +00:00
extern crate pest;
#[macro_use]
extern crate pest_derive;
2020-07-04 21:58:15 +00:00
use crate::Value::{QmlIdent, QmlNumber, QmlString};
2020-07-04 18:35:37 +00:00
use pest::iterators::{Pair, Pairs};
2020-07-04 21:58:15 +00:00
use pest::Parser;
2020-07-04 18:35:37 +00:00
use std::borrow::Borrow;
2020-07-04 22:09:24 +00:00
use std::fs::read_to_string;
2020-07-04 18:35:37 +00:00
#[derive(Parser)]
#[grammar = "../pest/qml.pest"]
struct QmlParser;
#[derive(Debug, Clone)]
enum Value {
QmlString(String),
QmlNumber(f64),
QmlIdent(String),
}
#[derive(Debug, Clone)]
struct QML {
properties: HashMap<String, Value>,
2020-07-04 21:58:15 +00:00
children: Vec<(String, QML)>,
2020-07-04 18:35:37 +00:00
}
fn parse_qml(qml: Pairs<Rule>) -> QML {
2020-07-04 21:58:15 +00:00
let mut qmldoc = QML {
properties: Default::default(),
children: vec![],
};
2020-07-04 18:35:37 +00:00
for pair in qml {
2020-07-04 21:58:15 +00:00
// println!("Rule {:?} Str {}", pair.as_rule(), pair.as_str());
2020-07-04 18:35:37 +00:00
match pair.as_rule() {
Rule::import => {
let mut tokens = pair.into_inner();
println!("Found new Import {} ", tokens.next().unwrap().as_str());
2020-07-04 21:58:15 +00:00
}
2020-07-04 18:35:37 +00:00
Rule::body => {
let mut tokens = pair.into_inner();
let ident = tokens.next().unwrap().as_str();
println!("Found new Body: {} ", ident);
2020-07-04 21:58:15 +00:00
qmldoc
.children
.push((String::from(ident), parse_qml(tokens.into_iter())));
}
2020-07-04 18:35:37 +00:00
Rule::property => {
let mut tokens = pair.into_inner();
let ident = tokens.next().unwrap().as_str();
let value = tokens.next().unwrap();
2020-07-04 21:58:15 +00:00
// let value = tokens.next().unwrap().as_str();
2020-07-04 18:35:37 +00:00
match value.as_rule() {
Rule::number => {
let num: f64 = value.as_str().parse().unwrap();
println!("Found new Property: {} {:?}", ident, num);
2020-07-04 21:58:15 +00:00
qmldoc
.properties
.insert(String::from(ident), QmlNumber(num));
2020-07-04 18:35:37 +00:00
}
Rule::string => {
println!("Found new Property: {} {}", ident, value.as_str());
2020-07-04 21:58:15 +00:00
qmldoc.properties.insert(
String::from(ident),
QmlString(String::from(value.into_inner().next().unwrap().as_str())),
);
2020-07-04 18:35:37 +00:00
}
Rule::ident => {
println!("Found new Property: {} {}", ident, value.as_str());
2020-07-04 21:58:15 +00:00
qmldoc
.properties
.insert(String::from(ident), QmlIdent(String::from(value.as_str())));
2020-07-04 18:35:37 +00:00
}
_ => {}
}
2020-07-04 22:06:15 +00:00
}
Rule::function => {
let mut tokens = pair.into_inner();
let ident = tokens.next().unwrap().as_str();
let value = tokens.concat();
qmldoc.properties.insert(
String::from(ident),
QmlString(String::from(value.clone().trim())),
);
}
2020-07-04 21:58:15 +00:00
_ => return parse_qml(pair.into_inner()),
2020-07-04 18:35:37 +00:00
}
}
qmldoc
}
fn main() {
Application::new()
.window(|ctx| {
2020-07-04 22:09:24 +00:00
let qml = read_to_string("./res/example.qml").unwrap();
let qml_tokens = QmlParser::parse(Rule::qml, qml.as_str()).unwrap_or_else(|e| panic!("{}", e));
2020-07-04 18:35:37 +00:00
let qml_doc = parse_qml(qml_tokens);
let top_level = qml_doc.children.clone();
2020-07-04 22:06:15 +00:00
let width = match top_level[0].1.properties.get("width") {
2020-07-04 21:58:15 +00:00
Some(QmlNumber(num)) => num.clone(),
_ => 600.0,
2020-07-04 18:35:37 +00:00
};
2020-07-04 22:06:15 +00:00
let height = match top_level[0].1.properties.get("height") {
2020-07-04 21:58:15 +00:00
Some(QmlNumber(num)) => num.clone(),
_ => 600.0,
2020-07-04 18:35:37 +00:00
};
2020-07-04 21:58:15 +00:00
println!("{:?}", qml_doc);
2020-07-04 18:35:37 +00:00
Window::create()
.title("QML")
.position((100.0, 100.0))
.resizeable(true)
.size(width, height)
2020-07-04 22:06:15 +00:00
.child(render_ctx(ctx, &top_level, 0, 0, &HashMap::new()).unwrap())
2020-07-04 18:35:37 +00:00
.build(ctx)
})
.run();
}
2020-07-04 21:58:15 +00:00
fn parse_number(val: Option<&Value>, env: &HashMap<String, Value>) -> f64 {
match val {
Some(QmlNumber(num)) => num.clone(),
2020-07-04 22:06:15 +00:00
Some(QmlIdent(ident)) => match env.get(ident) {
Some(QmlNumber(num)) => num.clone(),
_ => 0.0,
},
2020-07-04 21:58:15 +00:00
_ => 0.0,
}
}
2020-07-04 22:06:15 +00:00
fn render_ctx(
ctx: &mut BuildContext,
qml: &Vec<(String, QML)>,
row: u32,
col: u32,
env: &HashMap<String, Value>,
) -> Option<Entity> {
2020-07-04 18:35:37 +00:00
for (ident, child) in qml.iter() {
match ident.as_str() {
2020-07-04 21:58:15 +00:00
"Grid" => {
let mut grid = Grid::create();
grid = grid.attach(Grid::row(row as usize));
grid = grid.attach(Grid::column(col as usize));
let rows = parse_number(child.properties.get("rows"), &env) as u32;
let cols = parse_number(child.properties.get("cols"), &env) as u32;
let mut grid_rows = Rows::create();
for i in 0..rows {
grid_rows = grid_rows.row("stretch");
}
grid = grid.rows(grid_rows.build());
let mut grid_cols = Columns::create();
for i in 0..rows {
grid_cols = grid_cols.column("stretch");
}
grid = grid.columns(grid_cols.build());
let mut grow = 0u32;
let mut gcol = 0u32;
//rect = rect.attach(Grid::column(gcol as usize));
2020-07-04 22:06:15 +00:00
for (i, s) in child.children.iter() {
match render_ctx(ctx, &vec![(i.clone(), s.clone())], grow, gcol, &env) {
2020-07-04 21:58:15 +00:00
Some(entity) => {
grid = grid.child(entity);
2020-07-04 22:06:15 +00:00
grow += 1;
2020-07-04 21:58:15 +00:00
if grow as u32 == rows {
grow = 0;
2020-07-04 22:06:15 +00:00
gcol += 1;
2020-07-04 21:58:15 +00:00
}
2020-07-04 22:06:15 +00:00
}
2020-07-04 21:58:15 +00:00
_ => {}
}
}
return Some(grid.build(ctx));
2020-07-04 22:06:15 +00:00
}
2020-07-04 18:35:37 +00:00
"Rectangle" => {
2020-07-04 21:58:15 +00:00
let width = parse_number(child.properties.get("width"), &env);
let height = parse_number(child.properties.get("height"), &env);
let color = match child.properties.get("color") {
Some(QmlString(col)) => match col.as_str() {
"red" => Color::rgb(0xff, 00, 00),
"blue" => Color::rgb(0x00, 00, 0xff),
_ => Color::rgb(0xff, 0xff, 0xff),
},
_ => Color::rgb(0xff, 0xff, 0xff),
2020-07-04 18:35:37 +00:00
};
2020-07-04 21:58:15 +00:00
let mut rect = Container::create()
2020-07-04 22:06:15 +00:00
// .width(width)
// .height(height)
2020-07-04 21:58:15 +00:00
.background(color);
rect = rect.attach(Grid::row(row as usize));
rect = rect.attach(Grid::column(col as usize));
let mut env = env.clone();
env.insert(String::from("parent.width"), QmlNumber(width));
env.insert(String::from("parent.height"), QmlNumber(height));
2020-07-04 22:06:15 +00:00
for (i, s) in child.children.iter() {
match render_ctx(ctx, &vec![(i.clone(), s.clone())], 0, 0, &env) {
Some(entity) => {
rect = rect.child(entity);
}
2020-07-04 21:58:15 +00:00
_ => {}
}
}
return Some(rect.build(ctx));
}
"Button" => {
let mut button = Button::create();
button = button.attach(Grid::row(row as usize));
button = button.attach(Grid::column(col as usize));
let code = match child.properties.get("onclick").unwrap() {
QmlString(code) => code.clone(),
2020-07-04 22:06:15 +00:00
_ => String::new(),
2020-07-04 18:35:37 +00:00
};
2020-07-04 22:06:15 +00:00
button = button.on_click(move |x, y| -> bool {
2020-07-04 21:58:15 +00:00
rhai_script(code.clone());
2020-07-04 22:06:15 +00:00
return true;
});
2020-07-04 21:58:15 +00:00
let text = match child.properties.get("text").unwrap() {
QmlString(text) => text.clone(),
_ => String::new(),
2020-07-04 18:35:37 +00:00
};
2020-07-04 21:58:15 +00:00
match child.properties.get("anchors.centerIn") {
Some(QmlIdent(str)) => {
if str.eq("parent") {
button = button.vertical_alignment(Alignment::Center);
button = button.horizontal_alignment(Alignment::Center);
2020-07-04 18:35:37 +00:00
}
}
2020-07-04 21:58:15 +00:00
_ => {}
2020-07-04 18:35:37 +00:00
}
2020-07-04 21:58:15 +00:00
button = button.text(text);
return Some(button.build(ctx));
}
2020-07-04 18:35:37 +00:00
"Text" => {
let text = match child.properties.get("text").unwrap() {
QmlString(text) => text.clone(),
2020-07-04 21:58:15 +00:00
_ => String::new(),
2020-07-04 18:35:37 +00:00
};
let mut tt = TextBlock::create();
tt = tt.text(text);
2020-07-04 21:58:15 +00:00
tt = tt.attach(Grid::row(row as usize));
tt = tt.attach(Grid::column(col as usize));
2020-07-04 18:35:37 +00:00
2020-07-04 21:58:15 +00:00
match child.properties.get("anchors.centerIn") {
2020-07-04 22:06:15 +00:00
Some(QmlIdent(str)) => {
2020-07-04 18:35:37 +00:00
if str.eq("parent") {
tt = tt.vertical_alignment(Alignment::Center);
tt = tt.horizontal_alignment(Alignment::Center);
}
2020-07-04 21:58:15 +00:00
}
2020-07-04 18:35:37 +00:00
_ => {}
}
2020-07-04 21:58:15 +00:00
return Some(tt.build(ctx));
2020-07-04 18:35:37 +00:00
}
2020-07-04 21:58:15 +00:00
_ => println!("unknown ident {}", ident),
2020-07-04 18:35:37 +00:00
}
}
None
2020-07-04 21:58:15 +00:00
}
fn rhai_script(run: String) {
let mut engine = Engine::new();
engine.eval::<()>(run.as_str());
2020-07-04 22:06:15 +00:00
}