lib
This commit is contained in:
parent
5ec842f6ee
commit
49d0637fc8
|
@ -0,0 +1,244 @@
|
||||||
|
use orbtk::prelude::*;
|
||||||
|
use rhai::RegisterFn;
|
||||||
|
use rhai::{packages::*, Engine, EvalAltResult, INT};
|
||||||
|
use std::sync::mpsc::{Receiver, Sender};
|
||||||
|
use std::time::Duration;
|
||||||
|
pub mod parser;
|
||||||
|
use crate::parser::Value;
|
||||||
|
use crate::parser::QML;
|
||||||
|
use parser::Value::{QmlIdent, QmlNumber, QmlString};
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate pest_derive;
|
||||||
|
|
||||||
|
#[derive(AsAny)]
|
||||||
|
pub struct MainViewState {
|
||||||
|
pub qml: Vec<(String, QML)>,
|
||||||
|
pub rx: Option<Receiver<String>>,
|
||||||
|
pub state1: Option<MVState>,
|
||||||
|
pub state2: Option<MVState>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for MainViewState {
|
||||||
|
fn create() -> Self {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build(self, ctx: &mut BuildContext) -> Entity {
|
||||||
|
let top_level = self.qml.clone();
|
||||||
|
let widget = ctx.create_entity();
|
||||||
|
let this = render_ctx(widget, ctx, &top_level, 0, 0).unwrap();
|
||||||
|
ctx.register_state(this, Box::new(self.state2.unwrap()));
|
||||||
|
ctx.register_state(widget, Box::new(self.state1.unwrap()));
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_handler(self, handler: impl Into<Rc<dyn EventHandler>>) -> Self {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn child(self, child: Entity) -> Self {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(AsAny)]
|
||||||
|
pub struct MVState {
|
||||||
|
pub engine: Engine,
|
||||||
|
pub tx: Option<Sender<(String, String, String)>>,
|
||||||
|
pub rx: Option<Receiver<(String, String, String)>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MVState {
|
||||||
|
fn action(&mut self, action: String) {
|
||||||
|
match self.tx.clone() {
|
||||||
|
Some(tx) => {
|
||||||
|
self.engine
|
||||||
|
.register_fn("update_property", move |x: &str, y: &str, z: &str| {
|
||||||
|
tx.send((String::from(x), String::from(y), String::from(z)));
|
||||||
|
});
|
||||||
|
let result = self.engine.eval::<()>(action.as_str());
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State for MVState {
|
||||||
|
fn init(&mut self, registry: &mut Registry, ctx: &mut Context) {
|
||||||
|
self.update(registry, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, registry: &mut Registry, ctx: &mut Context) {
|
||||||
|
match &self.rx {
|
||||||
|
Some(rx) => match rx.recv_timeout(Duration::from_millis(1)) {
|
||||||
|
Ok((x, y, z)) => {
|
||||||
|
ctx.child(x.as_str())
|
||||||
|
.set::<String16>(y.as_str(), String16::from("hijack"));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Template for MainViewState {}
|
||||||
|
|
||||||
|
fn parse_number(val: Option<&Value>) -> f64 {
|
||||||
|
match val {
|
||||||
|
Some(QmlNumber(num)) => num.clone(),
|
||||||
|
_ => 0.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_ctx(
|
||||||
|
id: Entity,
|
||||||
|
ctx: &mut BuildContext,
|
||||||
|
qml: &Vec<(String, QML)>,
|
||||||
|
row: u32,
|
||||||
|
col: u32,
|
||||||
|
) -> Option<Entity> {
|
||||||
|
for (ident, child) in qml.iter() {
|
||||||
|
match ident.as_str() {
|
||||||
|
"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")) as u32;
|
||||||
|
let cols = parse_number(child.properties.get("cols")) 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));
|
||||||
|
for (i, s) in child.children.iter() {
|
||||||
|
match render_ctx(id, ctx, &vec![(i.clone(), s.clone())], grow, gcol) {
|
||||||
|
Some(entity) => {
|
||||||
|
grid = grid.child(entity);
|
||||||
|
grow += 1;
|
||||||
|
if grow as u32 == rows {
|
||||||
|
grow = 0;
|
||||||
|
gcol += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Some(grid.build(ctx));
|
||||||
|
}
|
||||||
|
"Rectangle" => {
|
||||||
|
let width = parse_number(child.properties.get("width"));
|
||||||
|
let height = parse_number(child.properties.get("height"));
|
||||||
|
|
||||||
|
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),
|
||||||
|
};
|
||||||
|
let mut rect = Container::create()
|
||||||
|
// .width(width)
|
||||||
|
// .height(height)
|
||||||
|
.background(color);
|
||||||
|
|
||||||
|
rect = rect.attach(Grid::row(row as usize));
|
||||||
|
rect = rect.attach(Grid::column(col as usize));
|
||||||
|
|
||||||
|
for (i, s) in child.children.iter() {
|
||||||
|
match render_ctx(id, ctx, &vec![(i.clone(), s.clone())], 0, 0) {
|
||||||
|
Some(entity) => {
|
||||||
|
rect = rect.child(entity);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(),
|
||||||
|
_ => String::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
button = button.on_click(move |states, _| -> bool {
|
||||||
|
state(id, states).action(code.clone());
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
let text = match child.properties.get("text").unwrap() {
|
||||||
|
QmlString(text) => text.clone(),
|
||||||
|
_ => String::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
button = button.text(text);
|
||||||
|
|
||||||
|
return Some(button.build(ctx));
|
||||||
|
}
|
||||||
|
"Text" => {
|
||||||
|
let text = match child.properties.get("text") {
|
||||||
|
Some(QmlString(text)) => text.clone(),
|
||||||
|
_ => String::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut tt = TextBlock::create();
|
||||||
|
tt = tt.text(text);
|
||||||
|
tt = tt.attach(Grid::row(row as usize));
|
||||||
|
tt = tt.attach(Grid::column(col as usize));
|
||||||
|
|
||||||
|
match child.properties.get("id") {
|
||||||
|
Some(QmlIdent(text)) => {
|
||||||
|
tt = tt.id(text.clone());
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
match child.properties.get("anchors.centerIn") {
|
||||||
|
Some(QmlIdent(str)) => {
|
||||||
|
if str.eq("parent") {
|
||||||
|
tt = tt.vertical_alignment(Alignment::Center);
|
||||||
|
tt = tt.horizontal_alignment(Alignment::Center);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
let entity = tt.build(ctx);
|
||||||
|
return Some(entity);
|
||||||
|
}
|
||||||
|
_ => println!("unknown ident {}", ident),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state<'a>(id: Entity, states: &'a mut StatesContext) -> &'a mut MVState {
|
||||||
|
states.get_mut(id)
|
||||||
|
}
|
385
src/main.rs
385
src/main.rs
|
@ -1,380 +1,51 @@
|
||||||
use orbtk::prelude::*;
|
use orbtk::prelude::*;
|
||||||
use rhai::{packages::*, Engine, EvalAltResult, INT};
|
|
||||||
use rhai::RegisterFn;
|
use rhai::RegisterFn;
|
||||||
|
use rhai::{packages::*, Engine, EvalAltResult, INT};
|
||||||
|
|
||||||
extern crate pest;
|
use rqml::parser::parse_qml;
|
||||||
#[macro_use]
|
use rqml::{MVState, MainViewState};
|
||||||
extern crate pest_derive;
|
|
||||||
|
|
||||||
use crate::Value::{QmlIdent, QmlNumber, QmlString};
|
|
||||||
use pest::iterators::{Pair, Pairs};
|
|
||||||
use pest::Parser;
|
|
||||||
use std::borrow::{Borrow, BorrowMut};
|
use std::borrow::{Borrow, BorrowMut};
|
||||||
use std::fs::read_to_string;
|
use std::fs::read_to_string;
|
||||||
use std::sync::mpsc::{Sender, Receiver};
|
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
|
use std::sync::mpsc::{Receiver, Sender};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use crate::Action::Code;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
#[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>,
|
|
||||||
children: Vec<(String, QML)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_qml(qml: Pairs<Rule>) -> QML {
|
|
||||||
let mut qmldoc = QML {
|
|
||||||
properties: Default::default(),
|
|
||||||
children: vec![],
|
|
||||||
};
|
|
||||||
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
|
|
||||||
.push((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())));
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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())),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
_ => return parse_qml(pair.into_inner()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qmldoc
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
||||||
Application::new()
|
Application::new()
|
||||||
.window(|ctx| {
|
.window(|ctx| {
|
||||||
let mut app_context:HashMap<String, Entity> = HashMap::new();
|
let mut app_context: HashMap<String, Entity> = HashMap::new();
|
||||||
let qml = read_to_string("./res/example.qml").unwrap();
|
let qml_doc = parse_qml("./res/example.qml");
|
||||||
let qml_tokens = QmlParser::parse(Rule::qml, qml.as_str()).unwrap_or_else(|e| panic!("{}", e));
|
|
||||||
let qml_doc = parse_qml(qml_tokens);
|
|
||||||
let top_level = qml_doc.children.clone();
|
let top_level = qml_doc.children.clone();
|
||||||
|
|
||||||
let width = match top_level[0].1.properties.get("width") {
|
|
||||||
Some(QmlNumber(num)) => num.clone(),
|
|
||||||
_ => 600.0,
|
|
||||||
};
|
|
||||||
let height = match top_level[0].1.properties.get("height") {
|
|
||||||
Some(QmlNumber(num)) => num.clone(),
|
|
||||||
_ => 600.0,
|
|
||||||
};
|
|
||||||
println!("{:?}", qml_doc);
|
println!("{:?}", qml_doc);
|
||||||
let (tx, rx): (Sender<(String,String,String)>, Receiver<(String,String,String)>) = mpsc::channel();
|
let (tx, rx): (
|
||||||
|
Sender<(String, String, String)>,
|
||||||
|
Receiver<(String, String, String)>,
|
||||||
|
) = mpsc::channel();
|
||||||
let w = Window::create()
|
let w = Window::create()
|
||||||
.title("QML")
|
.title("QML")
|
||||||
.position((100.0, 100.0))
|
.position((100.0, 100.0))
|
||||||
.resizeable(true)
|
.resizeable(true)
|
||||||
.size(width, height)
|
.size(600.0, 600.0)
|
||||||
.child(MainViewState{ action: None, qml: top_level.clone(), rx: None, state1: Some(MVState{tx:Some(tx.clone()),rx:None}),state2: Some(MVState{rx:Some(rx),tx:None})}.build(ctx))
|
.child(
|
||||||
|
MainViewState {
|
||||||
|
qml: top_level.clone(),
|
||||||
|
rx: None,
|
||||||
|
state1: Some(MVState {
|
||||||
|
tx: Some(tx.clone()),
|
||||||
|
rx: None,
|
||||||
|
engine: Engine::new(),
|
||||||
|
}),
|
||||||
|
state2: Some(MVState {
|
||||||
|
rx: Some(rx),
|
||||||
|
tx: None,
|
||||||
|
engine: Engine::new(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
.build(ctx),
|
||||||
|
)
|
||||||
.build(ctx);
|
.build(ctx);
|
||||||
w
|
w
|
||||||
})
|
})
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
|
||||||
enum Action {
|
|
||||||
Code,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(AsAny)]
|
|
||||||
pub struct MainViewState {
|
|
||||||
action: Option<Action>,
|
|
||||||
qml: Vec<(String, QML)>,
|
|
||||||
rx: Option<Receiver<String>>,
|
|
||||||
state1: Option<MVState>,
|
|
||||||
state2: Option<MVState>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Widget for MainViewState {
|
|
||||||
fn create() -> Self {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build(self, ctx: &mut BuildContext) -> Entity {
|
|
||||||
|
|
||||||
let top_level = self.qml.clone();
|
|
||||||
let widget = ctx.create_entity();
|
|
||||||
let this = render_ctx(widget, ctx, &top_level, 0, 0).unwrap();
|
|
||||||
ctx.register_state(this, Box::new(self.state2.unwrap()));
|
|
||||||
ctx.register_state(widget, Box::new(self.state1.unwrap()));
|
|
||||||
this
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert_handler(self, handler: impl Into<Rc<dyn EventHandler>>) -> Self {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn child(self, child: Entity) -> Self {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(AsAny)]
|
|
||||||
struct MVState {
|
|
||||||
tx: Option<Sender<(String,String,String)>>,
|
|
||||||
rx: Option<Receiver<(String,String,String)>>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MVState {
|
|
||||||
fn action(&mut self, action: String) {
|
|
||||||
match self.tx.clone() {
|
|
||||||
Some(tx) => {
|
|
||||||
let mut engine = Engine::new();
|
|
||||||
engine.register_fn("update_property", move |x: &str,y: &str,z: &str| {
|
|
||||||
tx.send((String::from(x), String::from(y), String::from(z)));
|
|
||||||
});
|
|
||||||
let result = engine.eval::<()>(action.as_str());
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl State for MVState {
|
|
||||||
fn init(&mut self, registry: &mut Registry, ctx: &mut Context) {
|
|
||||||
self.update(registry, ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, registry: &mut Registry, ctx: &mut Context) {
|
|
||||||
|
|
||||||
match &self.rx {
|
|
||||||
Some(rx)=> {
|
|
||||||
match rx.recv_timeout(Duration::from_millis(1)) {
|
|
||||||
Ok((x,y,z)) => {
|
|
||||||
|
|
||||||
ctx.child(x.as_str()).set::<String16>(y.as_str(),String16::from("hijack"));
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Template for MainViewState {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_number(val: Option<&Value>) -> f64 {
|
|
||||||
match val {
|
|
||||||
Some(QmlNumber(num)) => num.clone(),
|
|
||||||
_ => 0.0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_ctx(
|
|
||||||
id: Entity,
|
|
||||||
ctx: &mut BuildContext,
|
|
||||||
qml: &Vec<(String, QML)>,
|
|
||||||
row: u32,
|
|
||||||
col: u32
|
|
||||||
) -> Option<Entity> {
|
|
||||||
for (ident, child) in qml.iter() {
|
|
||||||
match ident.as_str() {
|
|
||||||
"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")) as u32;
|
|
||||||
let cols = parse_number(child.properties.get("cols")) 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));
|
|
||||||
for (i, s) in child.children.iter() {
|
|
||||||
match render_ctx(id, ctx, &vec![(i.clone(), s.clone())], grow, gcol) {
|
|
||||||
Some(entity) => {
|
|
||||||
grid = grid.child(entity);
|
|
||||||
grow += 1;
|
|
||||||
if grow as u32 == rows {
|
|
||||||
grow = 0;
|
|
||||||
gcol += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(grid.build(ctx));
|
|
||||||
}
|
|
||||||
"Rectangle" => {
|
|
||||||
let width = parse_number(child.properties.get("width"));
|
|
||||||
let height = parse_number(child.properties.get("height"));
|
|
||||||
|
|
||||||
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),
|
|
||||||
};
|
|
||||||
let mut rect = Container::create()
|
|
||||||
// .width(width)
|
|
||||||
// .height(height)
|
|
||||||
.background(color);
|
|
||||||
|
|
||||||
rect = rect.attach(Grid::row(row as usize));
|
|
||||||
rect = rect.attach(Grid::column(col as usize));
|
|
||||||
|
|
||||||
|
|
||||||
for (i, s) in child.children.iter() {
|
|
||||||
match render_ctx(id, ctx, &vec![(i.clone(), s.clone())], 0, 0) {
|
|
||||||
Some(entity) => {
|
|
||||||
rect = rect.child(entity);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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(),
|
|
||||||
_ => String::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
button = button.on_click(move |states, _| -> bool {
|
|
||||||
state(id, states).action(code.clone());
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
let text = match child.properties.get("text").unwrap() {
|
|
||||||
QmlString(text) => text.clone(),
|
|
||||||
_ => String::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
button = button.text(text);
|
|
||||||
|
|
||||||
return Some(button.build(ctx));
|
|
||||||
}
|
|
||||||
"Text" => {
|
|
||||||
let text = match child.properties.get("text") {
|
|
||||||
Some(QmlString(text)) => text.clone(),
|
|
||||||
_ => String::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
let mut tt = TextBlock::create();
|
|
||||||
tt = tt.text(text);
|
|
||||||
tt = tt.attach(Grid::row(row as usize));
|
|
||||||
tt = tt.attach(Grid::column(col as usize));
|
|
||||||
|
|
||||||
match child.properties.get("id") {
|
|
||||||
Some(QmlIdent(text)) => {
|
|
||||||
tt = tt.id(text.clone());
|
|
||||||
},
|
|
||||||
_ => { }
|
|
||||||
};
|
|
||||||
|
|
||||||
match child.properties.get("anchors.centerIn") {
|
|
||||||
Some(QmlIdent(str)) => {
|
|
||||||
if str.eq("parent") {
|
|
||||||
tt = tt.vertical_alignment(Alignment::Center);
|
|
||||||
tt = tt.horizontal_alignment(Alignment::Center);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
let entity = tt.build(ctx);
|
|
||||||
return Some(entity);
|
|
||||||
}
|
|
||||||
_ => println!("unknown ident {}", ident),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn state<'a>(id: Entity, states: &'a mut StatesContext) -> &'a mut MVState {
|
|
||||||
states.get_mut(id)
|
|
||||||
}
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
extern crate pest;
|
||||||
|
|
||||||
|
use crate::Value::{QmlIdent, QmlNumber, QmlString};
|
||||||
|
use pest::iterators::{Pair, Pairs};
|
||||||
|
use pest::Parser;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fs::read_to_string;
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[grammar = "../pest/qml.pest"]
|
||||||
|
struct QmlParser;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Value {
|
||||||
|
QmlString(String),
|
||||||
|
QmlNumber(f64),
|
||||||
|
QmlIdent(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct QML {
|
||||||
|
pub properties: HashMap<String, Value>,
|
||||||
|
pub children: Vec<(String, QML)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_qml(path: &str) -> QML {
|
||||||
|
let qml_file = read_to_string(path).unwrap();
|
||||||
|
let qml_tokens =
|
||||||
|
QmlParser::parse(Rule::qml, qml_file.as_str()).unwrap_or_else(|e| panic!("{}", e));
|
||||||
|
parse(qml_tokens)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(qml: Pairs<Rule>) -> QML {
|
||||||
|
let mut qmldoc = QML {
|
||||||
|
properties: Default::default(),
|
||||||
|
children: vec![],
|
||||||
|
};
|
||||||
|
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
|
||||||
|
.push((String::from(ident), parse(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())));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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())),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => return parse(pair.into_inner()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qmldoc
|
||||||
|
}
|
Loading…
Reference in New Issue