diff --git a/res/example.qml b/res/example.qml index 2bbde34..9e6b3ac 100644 --- a/res/example.qml +++ b/res/example.qml @@ -19,6 +19,7 @@ Grid { Rectangle { color: "blue" Text { + id: target anchors.centerIn: parent text: "Hello, World!" } @@ -48,6 +49,7 @@ Grid { text: "Hello, World!" onclick = [[ print("Hello World!"); + update_property("target", "text", "123"); ]] } } diff --git a/src/main.rs b/src/main.rs index 04286e9..45685c9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,7 @@ use orbtk::prelude::*; use rhai::{packages::*, Engine, EvalAltResult, INT}; +use rhai::RegisterFn; + extern crate pest; #[macro_use] extern crate pest_derive; @@ -7,8 +9,13 @@ extern crate pest_derive; use crate::Value::{QmlIdent, QmlNumber, QmlString}; use pest::iterators::{Pair, Pairs}; use pest::Parser; -use std::borrow::Borrow; +use std::borrow::{Borrow, BorrowMut}; use std::fs::read_to_string; +use std::sync::mpsc::{Sender, Receiver}; +use std::sync::mpsc; +use std::thread; +use crate::Action::Code; +use std::time::Duration; #[derive(Parser)] #[grammar = "../pest/qml.pest"] @@ -93,8 +100,10 @@ fn parse_qml(qml: Pairs) -> QML { } fn main() { + Application::new() .window(|ctx| { + let mut app_context:HashMap = HashMap::new(); 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)); let qml_doc = parse_qml(qml_tokens); @@ -109,34 +118,119 @@ fn main() { _ => 600.0, }; println!("{:?}", qml_doc); - Window::create() + let (tx, rx): (Sender<(String,String,String)>, Receiver<(String,String,String)>) = mpsc::channel(); + let w = Window::create() .title("QML") .position((100.0, 100.0)) .resizeable(true) .size(width, height) - .child(render_ctx(ctx, &top_level, 0, 0, &HashMap::new()).unwrap()) - .build(ctx) + .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)) + .build(ctx); + w }) .run(); } -fn parse_number(val: Option<&Value>, env: &HashMap) -> f64 { +#[derive(Copy, Clone, PartialEq)] +enum Action { + Code, +} + + +#[derive(AsAny)] +pub struct MainViewState { + action: Option, + qml: Vec<(String, QML)>, + rx: Option>, + state1: Option, + state2: Option +} + +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>) -> Self { + self + } + + fn child(self, child: Entity) -> Self { + self + } +} + +#[derive(AsAny)] +struct MVState { + tx: Option>, + rx: Option> +} + +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::(y.as_str(),String16::from("hijack")); + }, + _ => {} + } + }, + _ => {} + } + } +} + +impl Template for MainViewState { + +} + +fn parse_number(val: Option<&Value>) -> f64 { match val { Some(QmlNumber(num)) => num.clone(), - Some(QmlIdent(ident)) => match env.get(ident) { - Some(QmlNumber(num)) => num.clone(), - _ => 0.0, - }, _ => 0.0, } } fn render_ctx( + id: Entity, ctx: &mut BuildContext, qml: &Vec<(String, QML)>, row: u32, - col: u32, - env: &HashMap, + col: u32 ) -> Option { for (ident, child) in qml.iter() { match ident.as_str() { @@ -144,8 +238,8 @@ fn render_ctx( 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 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 { @@ -163,7 +257,7 @@ fn render_ctx( let mut gcol = 0u32; //rect = rect.attach(Grid::column(gcol as usize)); for (i, s) in child.children.iter() { - match render_ctx(ctx, &vec![(i.clone(), s.clone())], grow, gcol, &env) { + match render_ctx(id, ctx, &vec![(i.clone(), s.clone())], grow, gcol) { Some(entity) => { grid = grid.child(entity); grow += 1; @@ -179,8 +273,8 @@ fn render_ctx( return Some(grid.build(ctx)); } "Rectangle" => { - let width = parse_number(child.properties.get("width"), &env); - let height = parse_number(child.properties.get("height"), &env); + 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() { @@ -198,12 +292,9 @@ fn render_ctx( 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)); for (i, s) in child.children.iter() { - match render_ctx(ctx, &vec![(i.clone(), s.clone())], 0, 0, &env) { + match render_ctx(id, ctx, &vec![(i.clone(), s.clone())], 0, 0) { Some(entity) => { rect = rect.child(entity); } @@ -222,8 +313,9 @@ fn render_ctx( QmlString(code) => code.clone(), _ => String::new(), }; - button = button.on_click(move |x, y| -> bool { - rhai_script(code.clone()); + + button = button.on_click(move |states, _| -> bool { + state(id, states).action(code.clone()); return true; }); @@ -246,16 +338,24 @@ fn render_ctx( return Some(button.build(ctx)); } "Text" => { - let text = match child.properties.get("text").unwrap() { - QmlString(text) => text.clone(), + 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") { @@ -265,8 +365,8 @@ fn render_ctx( } _ => {} } - - return Some(tt.build(ctx)); + let entity = tt.build(ctx); + return Some(entity); } _ => println!("unknown ident {}", ident), } @@ -274,7 +374,7 @@ fn render_ctx( None } -fn rhai_script(run: String) { - let mut engine = Engine::new(); - engine.eval::<()>(run.as_str()); -} + +fn state<'a>(id: Entity, states: &'a mut StatesContext) -> &'a mut MVState { + states.get_mut(id) +} \ No newline at end of file