mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 14:21:16 +00:00
Use the new interpreter API in things that depends on it
This commit is contained in:
parent
8372d3f6d8
commit
48333370a6
10 changed files with 165 additions and 161 deletions
|
@ -18,8 +18,8 @@ name = "sixtyfps_node_native"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
once_cell = "1.5"
|
once_cell = "1.5"
|
||||||
sixtyfps-compilerlib = { version = "=0.0.5", path="../../../sixtyfps_compiler", features = ["display-diagnostics"] }
|
sixtyfps-compilerlib = { version = "=0.0.5", path="../../../sixtyfps_compiler" }
|
||||||
sixtyfps-interpreter = { version = "=0.0.5", path="../../../sixtyfps_runtime/interpreter" }
|
sixtyfps-interpreter = { version = "=0.0.5", path="../../../sixtyfps_runtime/interpreter", features = ["display-diagnostics"] }
|
||||||
sixtyfps-corelib = { version = "=0.0.5", path="../../../sixtyfps_runtime/corelib" }
|
sixtyfps-corelib = { version = "=0.0.5", path="../../../sixtyfps_runtime/corelib" }
|
||||||
scoped-tls-hkt = "0.1"
|
scoped-tls-hkt = "0.1"
|
||||||
neon = "0.7.0"
|
neon = "0.7.0"
|
||||||
|
|
|
@ -13,13 +13,11 @@ use rand::RngCore;
|
||||||
use sixtyfps_compilerlib::langtype::Type;
|
use sixtyfps_compilerlib::langtype::Type;
|
||||||
use sixtyfps_corelib::{ImageReference, SharedVector};
|
use sixtyfps_corelib::{ImageReference, SharedVector};
|
||||||
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
mod js_model;
|
mod js_model;
|
||||||
mod persistent_context;
|
mod persistent_context;
|
||||||
|
|
||||||
struct WrappedComponentType(Option<Rc<sixtyfps_interpreter::ComponentDescription>>);
|
struct WrappedComponentType(Option<sixtyfps_interpreter::ComponentDefinition>);
|
||||||
struct WrappedComponentRc(Option<sixtyfps_interpreter::ComponentRc>);
|
struct WrappedComponentRc(Option<sixtyfps_interpreter::ComponentInstance>);
|
||||||
|
|
||||||
/// We need to do some gymnastic with closures to pass the ExecuteContext with the right lifetime
|
/// We need to do some gymnastic with closures to pass the ExecuteContext with the right lifetime
|
||||||
type GlobalContextCallback<'c> =
|
type GlobalContextCallback<'c> =
|
||||||
|
@ -64,21 +62,16 @@ fn load(mut cx: FunctionContext) -> JsResult<JsValue> {
|
||||||
}
|
}
|
||||||
None => vec![],
|
None => vec![],
|
||||||
};
|
};
|
||||||
let mut compiler_config = sixtyfps_compilerlib::CompilerConfiguration::new(
|
let compiler_config =
|
||||||
sixtyfps_compilerlib::generator::OutputFormat::Interpreter,
|
sixtyfps_interpreter::CompilerConfiguration::new().with_include_paths(include_paths);
|
||||||
);
|
let (c, diags) = spin_on::spin_on(sixtyfps_interpreter::ComponentDefinition::from_path(
|
||||||
compiler_config.include_paths = include_paths;
|
path,
|
||||||
let source = std::fs::read_to_string(&path).or_else(|e| cx.throw_error(e.to_string()))?;
|
compiler_config,
|
||||||
let (c, warnings) =
|
));
|
||||||
match spin_on::spin_on(sixtyfps_interpreter::load(source, path.into(), compiler_config)) {
|
|
||||||
(Ok(c), warnings) => (c, warnings),
|
|
||||||
(Err(()), errors) => {
|
|
||||||
errors.print();
|
|
||||||
return cx.throw_error("Compilation error");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
warnings.print();
|
sixtyfps_interpreter::print_diagnostics(&diags);
|
||||||
|
|
||||||
|
let c = if let Some(c) = c { c } else { return cx.throw_error("Compilation error") };
|
||||||
|
|
||||||
let mut obj = SixtyFpsComponentType::new::<_, JsValue, _>(&mut cx, std::iter::empty())?;
|
let mut obj = SixtyFpsComponentType::new::<_, JsValue, _>(&mut cx, std::iter::empty())?;
|
||||||
cx.borrow_mut(&mut obj, |mut obj| obj.0 = Some(c));
|
cx.borrow_mut(&mut obj, |mut obj| obj.0 = Some(c));
|
||||||
|
@ -119,7 +112,7 @@ fn make_callback_handler<'cx>(
|
||||||
|
|
||||||
fn create<'cx>(
|
fn create<'cx>(
|
||||||
cx: &mut CallContext<'cx, impl neon::object::This>,
|
cx: &mut CallContext<'cx, impl neon::object::This>,
|
||||||
component_type: Rc<sixtyfps_interpreter::ComponentDescription>,
|
component_type: sixtyfps_interpreter::ComponentDefinition,
|
||||||
) -> JsResult<'cx, JsValue> {
|
) -> JsResult<'cx, JsValue> {
|
||||||
let component = component_type.clone().create();
|
let component = component_type.clone().create();
|
||||||
let persistent_context = persistent_context::PersistentContext::new(cx);
|
let persistent_context = persistent_context::PersistentContext::new(cx);
|
||||||
|
@ -138,17 +131,16 @@ fn create<'cx>(
|
||||||
.clone();
|
.clone();
|
||||||
if let Type::Callback { return_type, .. } = ty {
|
if let Type::Callback { return_type, .. } = ty {
|
||||||
let fun = value.downcast_or_throw::<JsFunction, _>(cx)?;
|
let fun = value.downcast_or_throw::<JsFunction, _>(cx)?;
|
||||||
component_type
|
component
|
||||||
.set_callback_handler(
|
.set_callback(
|
||||||
component.borrow(),
|
|
||||||
prop_name.as_str(),
|
prop_name.as_str(),
|
||||||
make_callback_handler(cx, &persistent_context, fun, return_type),
|
make_callback_handler(cx, &persistent_context, fun, return_type),
|
||||||
)
|
)
|
||||||
.or_else(|_| cx.throw_error(format!("Cannot set callback")))?;
|
.or_else(|_| cx.throw_error(format!("Cannot set callback")))?;
|
||||||
} else {
|
} else {
|
||||||
let value = to_eval_value(value, ty, cx, &persistent_context)?;
|
let value = to_eval_value(value, ty, cx, &persistent_context)?;
|
||||||
component_type
|
component
|
||||||
.set_property(component.borrow(), prop_name.as_str(), value)
|
.set_property(prop_name.as_str(), value)
|
||||||
.or_else(|_| cx.throw_error(format!("Cannot assign property")))?;
|
.or_else(|_| cx.throw_error(format!("Cannot assign property")))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -300,7 +292,7 @@ declare_types! {
|
||||||
let this = cx.this();
|
let this = cx.this();
|
||||||
let ct = cx.borrow(&this, |x| x.0.clone());
|
let ct = cx.borrow(&this, |x| x.0.clone());
|
||||||
let ct = ct.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
let ct = ct.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
||||||
Ok(cx.string(ct.id()).as_value(&mut cx))
|
Ok(cx.string(ct.name()).as_value(&mut cx))
|
||||||
}
|
}
|
||||||
method properties(mut cx) {
|
method properties(mut cx) {
|
||||||
let this = cx.this();
|
let this = cx.this();
|
||||||
|
@ -337,33 +329,31 @@ declare_types! {
|
||||||
Ok(WrappedComponentRc(None))
|
Ok(WrappedComponentRc(None))
|
||||||
}
|
}
|
||||||
method run(mut cx) {
|
method run(mut cx) {
|
||||||
let mut this = cx.this();
|
let this = cx.this();
|
||||||
let component = cx.borrow(&mut this, |x| x.0.clone());
|
let component = cx.borrow(&this, |x| x.0.as_ref().map(|c| c.clone_strong()));
|
||||||
let component = component.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
let component = component.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
||||||
run_scoped(&mut cx,this.downcast().unwrap(), || {
|
run_scoped(&mut cx,this.downcast().unwrap(), || {
|
||||||
component.window().show();
|
component.run();
|
||||||
sixtyfps_interpreter::run_event_loop();
|
|
||||||
component.window().hide();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
Ok(JsUndefined::new().as_value(&mut cx))
|
Ok(JsUndefined::new().as_value(&mut cx))
|
||||||
}
|
}
|
||||||
method show(mut cx) {
|
method show(mut cx) {
|
||||||
let mut this = cx.this();
|
let this = cx.this();
|
||||||
let component = cx.borrow(&mut this, |x| x.0.clone());
|
let component = cx.borrow(&this, |x| x.0.as_ref().map(|c| c.clone_strong()));
|
||||||
let component = component.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
let component = component.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
||||||
run_scoped(&mut cx,this.downcast().unwrap(), || {
|
run_scoped(&mut cx,this.downcast().unwrap(), || {
|
||||||
component.window().show();
|
component.show();
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
Ok(JsUndefined::new().as_value(&mut cx))
|
Ok(JsUndefined::new().as_value(&mut cx))
|
||||||
}
|
}
|
||||||
method hide(mut cx) {
|
method hide(mut cx) {
|
||||||
let mut this = cx.this();
|
let this = cx.this();
|
||||||
let component = cx.borrow(&mut this, |x| x.0.clone());
|
let component = cx.borrow(&this, |x| x.0.as_ref().map(|c| c.clone_strong()));
|
||||||
let component = component.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
let component = component.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
||||||
run_scoped(&mut cx,this.downcast().unwrap(), || {
|
run_scoped(&mut cx,this.downcast().unwrap(), || {
|
||||||
component.window().hide();
|
component.hide();
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
Ok(JsUndefined::new().as_value(&mut cx))
|
Ok(JsUndefined::new().as_value(&mut cx))
|
||||||
|
@ -371,14 +361,10 @@ declare_types! {
|
||||||
method get_property(mut cx) {
|
method get_property(mut cx) {
|
||||||
let prop_name = cx.argument::<JsString>(0)?.value();
|
let prop_name = cx.argument::<JsString>(0)?.value();
|
||||||
let this = cx.this();
|
let this = cx.this();
|
||||||
let lock = cx.lock();
|
let component = cx.borrow(&this, |x| x.0.as_ref().map(|c| c.clone_strong()));
|
||||||
let x = this.borrow(&lock).0.clone();
|
let component = component.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
||||||
let component = x.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
|
||||||
generativity::make_guard!(guard);
|
|
||||||
let component = component.unerase(guard);
|
|
||||||
let value = run_scoped(&mut cx,this.downcast().unwrap(), || {
|
let value = run_scoped(&mut cx,this.downcast().unwrap(), || {
|
||||||
component.description()
|
component.get_property(prop_name.as_str())
|
||||||
.get_property(component.borrow(), prop_name.as_str())
|
|
||||||
.map_err(|_| format!("Cannot read property"))
|
.map_err(|_| format!("Cannot read property"))
|
||||||
})?;
|
})?;
|
||||||
to_js_value(value, &mut cx)
|
to_js_value(value, &mut cx)
|
||||||
|
@ -386,12 +372,9 @@ declare_types! {
|
||||||
method set_property(mut cx) {
|
method set_property(mut cx) {
|
||||||
let prop_name = cx.argument::<JsString>(0)?.value();
|
let prop_name = cx.argument::<JsString>(0)?.value();
|
||||||
let this = cx.this();
|
let this = cx.this();
|
||||||
let lock = cx.lock();
|
let component = cx.borrow(&this, |x| x.0.as_ref().map(|c| c.clone_strong()));
|
||||||
let x = this.borrow(&lock).0.clone();
|
let component = component.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
||||||
let component = x.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
let ty = component.definition().properties()
|
||||||
generativity::make_guard!(guard);
|
|
||||||
let component = component.unerase(guard);
|
|
||||||
let ty = component.description().properties()
|
|
||||||
.get(&prop_name)
|
.get(&prop_name)
|
||||||
.ok_or(())
|
.ok_or(())
|
||||||
.or_else(|()| {
|
.or_else(|()| {
|
||||||
|
@ -403,8 +386,7 @@ declare_types! {
|
||||||
persistent_context::PersistentContext::from_object(&mut cx, this.downcast().unwrap())?;
|
persistent_context::PersistentContext::from_object(&mut cx, this.downcast().unwrap())?;
|
||||||
|
|
||||||
let value = to_eval_value(cx.argument::<JsValue>(1)?, ty, &mut cx, &persistent_context)?;
|
let value = to_eval_value(cx.argument::<JsValue>(1)?, ty, &mut cx, &persistent_context)?;
|
||||||
component.description()
|
component.set_property(prop_name.as_str(), value)
|
||||||
.set_property(component.borrow(), prop_name.as_str(), value)
|
|
||||||
.or_else(|_| cx.throw_error(format!("Cannot assign property")))?;
|
.or_else(|_| cx.throw_error(format!("Cannot assign property")))?;
|
||||||
|
|
||||||
Ok(JsUndefined::new().as_value(&mut cx))
|
Ok(JsUndefined::new().as_value(&mut cx))
|
||||||
|
@ -413,12 +395,9 @@ declare_types! {
|
||||||
let callback_name = cx.argument::<JsString>(0)?.value();
|
let callback_name = cx.argument::<JsString>(0)?.value();
|
||||||
let arguments = cx.argument::<JsArray>(1)?.to_vec(&mut cx)?;
|
let arguments = cx.argument::<JsArray>(1)?.to_vec(&mut cx)?;
|
||||||
let this = cx.this();
|
let this = cx.this();
|
||||||
let lock = cx.lock();
|
let component = cx.borrow(&this, |x| x.0.as_ref().map(|c| c.clone_strong()));
|
||||||
let x = this.borrow(&lock).0.clone();
|
let component = component.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
||||||
let component = x.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
let ty = component.definition().properties().get(&callback_name)
|
||||||
generativity::make_guard!(guard);
|
|
||||||
let component = component.unerase(guard);
|
|
||||||
let ty = component.description().properties().get(&callback_name)
|
|
||||||
.ok_or(())
|
.ok_or(())
|
||||||
.or_else(|()| {
|
.or_else(|()| {
|
||||||
cx.throw_error(format!("Callback {} not found in the component", callback_name))
|
cx.throw_error(format!("Callback {} not found in the component", callback_name))
|
||||||
|
@ -443,9 +422,8 @@ declare_types! {
|
||||||
};
|
};
|
||||||
|
|
||||||
let res = run_scoped(&mut cx,this.downcast().unwrap(), || {
|
let res = run_scoped(&mut cx,this.downcast().unwrap(), || {
|
||||||
component.description()
|
component.invoke_callback(callback_name.as_str(), args.as_slice())
|
||||||
.invoke_callback(component.borrow(), callback_name.as_str(), args.as_slice())
|
.map_err(|_| "Cannot emit callback".to_string())
|
||||||
.map_err(|()| "Cannot emit callback".to_string())
|
|
||||||
})?;
|
})?;
|
||||||
to_js_value(res, &mut cx)
|
to_js_value(res, &mut cx)
|
||||||
}
|
}
|
||||||
|
@ -456,21 +434,17 @@ declare_types! {
|
||||||
let this = cx.this();
|
let this = cx.this();
|
||||||
let persistent_context =
|
let persistent_context =
|
||||||
persistent_context::PersistentContext::from_object(&mut cx, this.downcast().unwrap())?;
|
persistent_context::PersistentContext::from_object(&mut cx, this.downcast().unwrap())?;
|
||||||
let lock = cx.lock();
|
let component = cx.borrow(&this, |x| x.0.as_ref().map(|c| c.clone_strong()));
|
||||||
let x = this.borrow(&lock).0.clone();
|
let component = component.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
||||||
let component = x.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
|
||||||
generativity::make_guard!(guard);
|
|
||||||
let component = component.unerase(guard);
|
|
||||||
|
|
||||||
let ty = component.description().properties().get(&callback_name)
|
let ty = component.definition().properties().get(&callback_name)
|
||||||
.ok_or(())
|
.ok_or(())
|
||||||
.or_else(|()| {
|
.or_else(|()| {
|
||||||
cx.throw_error(format!("Callback {} not found in the component", callback_name))
|
cx.throw_error(format!("Callback {} not found in the component", callback_name))
|
||||||
})?
|
})?
|
||||||
.clone();
|
.clone();
|
||||||
if let Type::Callback {return_type, ..} = ty {
|
if let Type::Callback {return_type, ..} = ty {
|
||||||
component.description().set_callback_handler(
|
component.set_callback(
|
||||||
component.borrow(),
|
|
||||||
callback_name.as_str(),
|
callback_name.as_str(),
|
||||||
make_callback_handler(&mut cx, &persistent_context, handler, return_type)
|
make_callback_handler(&mut cx, &persistent_context, handler, return_type)
|
||||||
).or_else(|_| cx.throw_error(format!("Cannot set callback")))?;
|
).or_else(|_| cx.throw_error(format!("Cannot set callback")))?;
|
||||||
|
@ -485,12 +459,10 @@ declare_types! {
|
||||||
let x = cx.argument::<JsNumber>(0)?.value() as f32;
|
let x = cx.argument::<JsNumber>(0)?.value() as f32;
|
||||||
let y = cx.argument::<JsNumber>(1)?.value() as f32;
|
let y = cx.argument::<JsNumber>(1)?.value() as f32;
|
||||||
let this = cx.this();
|
let this = cx.this();
|
||||||
let lock = cx.lock();
|
let component = cx.borrow(&this, |x| x.0.as_ref().map(|c| c.clone_strong()));
|
||||||
let comp = this.borrow(&lock).0.clone();
|
let component = component.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
||||||
let component = comp.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
|
||||||
let win = component.window();
|
|
||||||
run_scoped(&mut cx,this.downcast().unwrap(), || {
|
run_scoped(&mut cx,this.downcast().unwrap(), || {
|
||||||
sixtyfps_corelib::tests::sixtyfps_send_mouse_click(&vtable::VRc::into_dyn(component), x, y, &win);
|
sixtyfps_interpreter::testing::send_mouse_click(&component, x, y);
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
Ok(JsUndefined::new().as_value(&mut cx))
|
Ok(JsUndefined::new().as_value(&mut cx))
|
||||||
|
@ -499,11 +471,10 @@ declare_types! {
|
||||||
method send_keyboard_string_sequence(mut cx) {
|
method send_keyboard_string_sequence(mut cx) {
|
||||||
let sequence = cx.argument::<JsString>(0)?.value();
|
let sequence = cx.argument::<JsString>(0)?.value();
|
||||||
let this = cx.this();
|
let this = cx.this();
|
||||||
let lock = cx.lock();
|
let component = cx.borrow(&this, |x| x.0.as_ref().map(|c| c.clone_strong()));
|
||||||
let comp = this.borrow(&lock).0.clone();
|
let component = component.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
||||||
let component = comp.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
|
||||||
run_scoped(&mut cx,this.downcast().unwrap(), || {
|
run_scoped(&mut cx,this.downcast().unwrap(), || {
|
||||||
sixtyfps_corelib::tests::send_keyboard_string_sequence(&sequence.into(), Default::default(), &component.window());
|
sixtyfps_interpreter::testing::send_keyboard_string_sequence(&component, sequence.into());
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
Ok(JsUndefined::new().as_value(&mut cx))
|
Ok(JsUndefined::new().as_value(&mut cx))
|
||||||
|
|
|
@ -11,6 +11,9 @@ homepage = "https://sixtyfps.io"
|
||||||
[lib]
|
[lib]
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
display-diagnostics = ["sixtyfps-compilerlib/display-diagnostics"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
sixtyfps-corelib = { version = "=0.0.5", path = "../corelib", features = ["rtti"] }
|
sixtyfps-corelib = { version = "=0.0.5", path = "../corelib", features = ["rtti"] }
|
||||||
sixtyfps-rendering-backend-default = { version = "=0.0.5", path = "../../sixtyfps_runtime/rendering_backends/default", features = ["sixtyfps-rendering-backend-gl"] }
|
sixtyfps-rendering-backend-default = { version = "=0.0.5", path = "../../sixtyfps_runtime/rendering_backends/default", features = ["sixtyfps-rendering-backend-gl"] }
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
Please contact info@sixtyfps.io for more information.
|
Please contact info@sixtyfps.io for more information.
|
||||||
LICENSE END */
|
LICENSE END */
|
||||||
|
|
||||||
#![warn(missing_docs)]
|
|
||||||
|
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
use sixtyfps_corelib::{Brush, ImageReference, PathData, SharedString, SharedVector};
|
use sixtyfps_corelib::{Brush, ImageReference, PathData, SharedString, SharedVector};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -361,7 +359,12 @@ impl ComponentDefinition {
|
||||||
Err(d) => return (None, vec![d]),
|
Err(d) => return (None, vec![d]),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (c, diag) = crate::load(source, path.into(), config.config).await;
|
// We create here a 'static guard. That's alright because we make sure
|
||||||
|
// in this module that we only use erased component
|
||||||
|
let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };
|
||||||
|
|
||||||
|
let (c, diag) =
|
||||||
|
crate::dynamic_component::load(source, path.into(), config.config, guard).await;
|
||||||
(c.ok().map(|inner| Self { inner }), diag.into_iter().collect())
|
(c.ok().map(|inner| Self { inner }), diag.into_iter().collect())
|
||||||
}
|
}
|
||||||
/// Compile some .60 code into a ComponentDefinition
|
/// Compile some .60 code into a ComponentDefinition
|
||||||
|
@ -373,7 +376,17 @@ impl ComponentDefinition {
|
||||||
source_code: &str,
|
source_code: &str,
|
||||||
config: CompilerConfiguration,
|
config: CompilerConfiguration,
|
||||||
) -> (Option<Self>, Vec<Diagnostic>) {
|
) -> (Option<Self>, Vec<Diagnostic>) {
|
||||||
let (c, diag) = crate::load(source_code.into(), Default::default(), config.config).await;
|
// We create here a 'static guard. That's alright because we make sure
|
||||||
|
// in this module that we only use erased component
|
||||||
|
let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };
|
||||||
|
|
||||||
|
let (c, diag) = crate::dynamic_component::load(
|
||||||
|
source_code.into(),
|
||||||
|
Default::default(),
|
||||||
|
config.config,
|
||||||
|
guard,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
(c.ok().map(|inner| Self { inner }), diag.into_iter().collect())
|
(c.ok().map(|inner| Self { inner }), diag.into_iter().collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,6 +421,16 @@ impl ComponentDefinition {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Print the diagnostics to stderr
|
||||||
|
#[cfg(feature = "display-diagnostics")]
|
||||||
|
pub fn print_diagnostics(diagnostics: &[Diagnostic]) {
|
||||||
|
let mut build_diagnostics = sixtyfps_compilerlib::diagnostics::BuildDiagnostics::default();
|
||||||
|
for d in diagnostics {
|
||||||
|
build_diagnostics.push_compiler_error(d.clone())
|
||||||
|
}
|
||||||
|
build_diagnostics.print();
|
||||||
|
}
|
||||||
|
|
||||||
/// This represent an instance of a dynamic component
|
/// This represent an instance of a dynamic component
|
||||||
pub struct ComponentInstance {
|
pub struct ComponentInstance {
|
||||||
inner: vtable::VRc<
|
inner: vtable::VRc<
|
||||||
|
@ -417,6 +440,14 @@ pub struct ComponentInstance {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComponentInstance {
|
impl ComponentInstance {
|
||||||
|
/// Return the definition for this instance
|
||||||
|
pub fn definition(&self) -> ComponentDefinition {
|
||||||
|
// We create here a 'static guard. That's alright because we make sure
|
||||||
|
// in this module that we only use erased component
|
||||||
|
let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };
|
||||||
|
ComponentDefinition { inner: self.inner.unerase(guard).description() }
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the value for a public property of this component
|
/// Return the value for a public property of this component
|
||||||
pub fn get_property(&self, name: &str) -> Result<Value, GetPropertyError> {
|
pub fn get_property(&self, name: &str) -> Result<Value, GetPropertyError> {
|
||||||
generativity::make_guard!(guard);
|
generativity::make_guard!(guard);
|
||||||
|
@ -426,7 +457,7 @@ impl ComponentInstance {
|
||||||
.map_err(|()| GetPropertyError::NoSuchProperty)
|
.map_err(|()| GetPropertyError::NoSuchProperty)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the value for a public property of this component
|
/// Set the value for a public property of this component
|
||||||
pub fn set_property(&self, name: &str, value: Value) -> Result<(), SetPropertyError> {
|
pub fn set_property(&self, name: &str, value: Value) -> Result<(), SetPropertyError> {
|
||||||
generativity::make_guard!(guard);
|
generativity::make_guard!(guard);
|
||||||
let comp = self.inner.unerase(guard);
|
let comp = self.inner.unerase(guard);
|
||||||
|
@ -477,7 +508,7 @@ impl ComponentInstance {
|
||||||
/// and [`Self::hide`].
|
/// and [`Self::hide`].
|
||||||
pub fn run(&self) {
|
pub fn run(&self) {
|
||||||
self.show();
|
self.show();
|
||||||
crate::run_event_loop();
|
sixtyfps_rendering_backend_default::backend().run_event_loop();
|
||||||
self.hide();
|
self.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -594,3 +625,27 @@ impl CompilerConfiguration {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A few helper function usefull for tests
|
||||||
|
pub mod testing {
|
||||||
|
/// Wrapper around [`sixtyfps_corelib::tests::sixtyfps_send_mouse_click`]
|
||||||
|
pub fn send_mouse_click(comp: &super::ComponentInstance, x: f32, y: f32) {
|
||||||
|
sixtyfps_corelib::tests::sixtyfps_send_mouse_click(
|
||||||
|
&vtable::VRc::into_dyn(comp.inner.clone()),
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
&comp.inner.window(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
/// Wrapper around [`sixtyfps_corelib::tests::send_keyboard_string_sequence`]
|
||||||
|
pub fn send_keyboard_string_sequence(
|
||||||
|
comp: &super::ComponentInstance,
|
||||||
|
string: sixtyfps_corelib::SharedString,
|
||||||
|
) {
|
||||||
|
sixtyfps_corelib::tests::send_keyboard_string_sequence(
|
||||||
|
&string,
|
||||||
|
Default::default(),
|
||||||
|
&comp.inner.window(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -371,6 +371,7 @@ impl<'id> ComponentDescription<'id> {
|
||||||
///
|
///
|
||||||
/// Returns an error if the component is not an instance corresponding to this ComponentDescription,
|
/// Returns an error if the component is not an instance corresponding to this ComponentDescription,
|
||||||
/// or if the property with this name does not exist in this component
|
/// or if the property with this name does not exist in this component
|
||||||
|
#[allow(unused)]
|
||||||
pub fn set_binding(
|
pub fn set_binding(
|
||||||
&self,
|
&self,
|
||||||
component: ComponentRef,
|
component: ComponentRef,
|
||||||
|
@ -612,10 +613,19 @@ fn rtti_for_flickable() -> (&'static str, Rc<ItemRTTI>) {
|
||||||
pub async fn load<'id>(
|
pub async fn load<'id>(
|
||||||
source: String,
|
source: String,
|
||||||
path: std::path::PathBuf,
|
path: std::path::PathBuf,
|
||||||
compiler_config: CompilerConfiguration,
|
mut compiler_config: CompilerConfiguration,
|
||||||
guard: generativity::Guard<'id>,
|
guard: generativity::Guard<'id>,
|
||||||
) -> (Result<Rc<ComponentDescription<'id>>, ()>, sixtyfps_compilerlib::diagnostics::BuildDiagnostics)
|
) -> (Result<Rc<ComponentDescription<'id>>, ()>, sixtyfps_compilerlib::diagnostics::BuildDiagnostics)
|
||||||
{
|
{
|
||||||
|
if compiler_config.style.is_none() && std::env::var("SIXTYFPS_STYLE").is_err() {
|
||||||
|
// Defaults to native if it exists:
|
||||||
|
compiler_config.style = Some(if sixtyfps_rendering_backend_default::HAS_NATIVE_STYLE {
|
||||||
|
"native".to_owned()
|
||||||
|
} else {
|
||||||
|
"ugly".to_owned()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let mut diag = BuildDiagnostics::default();
|
let mut diag = BuildDiagnostics::default();
|
||||||
let syntax_node = parser::parse(source, Some(path.as_path()), &mut diag);
|
let syntax_node = parser::parse(source, Some(path.as_path()), &mut diag);
|
||||||
if diag.has_error() {
|
if diag.has_error() {
|
||||||
|
|
|
@ -14,61 +14,31 @@ LICENSE END */
|
||||||
This crate should not be used directly by application using SixtyFPS.
|
This crate should not be used directly by application using SixtyFPS.
|
||||||
You should use the `sixtyfps` crate instead
|
You should use the `sixtyfps` crate instead
|
||||||
*/
|
*/
|
||||||
|
#![warn(missing_docs)]
|
||||||
#![doc(html_logo_url = "https://sixtyfps.io/resources/logo.drawio.svg")]
|
#![doc(html_logo_url = "https://sixtyfps.io/resources/logo.drawio.svg")]
|
||||||
|
|
||||||
|
mod api;
|
||||||
mod dynamic_component;
|
mod dynamic_component;
|
||||||
mod dynamic_type;
|
mod dynamic_type;
|
||||||
mod eval;
|
mod eval;
|
||||||
mod global_component;
|
mod global_component;
|
||||||
mod value_model;
|
mod value_model;
|
||||||
|
|
||||||
/// FIXME: re-export everything from abi, but and everything else should be private
|
#[doc(inline)]
|
||||||
pub mod api;
|
pub use api::*;
|
||||||
|
|
||||||
pub use api::Value;
|
|
||||||
|
|
||||||
pub use sixtyfps_compilerlib::CompilerConfiguration;
|
|
||||||
use sixtyfps_corelib::component::ComponentVTable;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
pub fn new_compiler_configuration() -> CompilerConfiguration {
|
|
||||||
sixtyfps_compilerlib::CompilerConfiguration::new(
|
|
||||||
sixtyfps_compilerlib::generator::OutputFormat::Interpreter,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type ComponentDescription = dynamic_component::ComponentDescription<'static>;
|
|
||||||
pub type ComponentBox = dynamic_component::ComponentBox<'static>;
|
|
||||||
pub type ComponentRc = vtable::VRc<ComponentVTable, dynamic_component::ErasedComponentBox>;
|
|
||||||
pub async fn load(
|
|
||||||
source: String,
|
|
||||||
path: std::path::PathBuf,
|
|
||||||
mut compiler_config: CompilerConfiguration,
|
|
||||||
) -> (Result<Rc<ComponentDescription>, ()>, sixtyfps_compilerlib::diagnostics::BuildDiagnostics) {
|
|
||||||
if compiler_config.style.is_none() && std::env::var("SIXTYFPS_STYLE").is_err() {
|
|
||||||
// Defaults to native if it exists:
|
|
||||||
compiler_config.style = Some(if sixtyfps_rendering_backend_default::HAS_NATIVE_STYLE {
|
|
||||||
"native".to_owned()
|
|
||||||
} else {
|
|
||||||
"ugly".to_owned()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
dynamic_component::load(source, path, compiler_config, unsafe {
|
|
||||||
generativity::Guard::new(generativity::Id::new())
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_event_loop() {
|
|
||||||
sixtyfps_rendering_backend_default::backend().run_event_loop();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// This function can be used to register a custom TrueType font with SixtyFPS,
|
||||||
|
/// for use with the `font-family` property. The provided path must refer to a valid TrueType
|
||||||
|
/// font.
|
||||||
pub fn register_font_from_path<P: AsRef<std::path::Path>>(
|
pub fn register_font_from_path<P: AsRef<std::path::Path>>(
|
||||||
path: P,
|
path: P,
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
sixtyfps_rendering_backend_default::backend().register_font_from_path(path.as_ref())
|
sixtyfps_rendering_backend_default::backend().register_font_from_path(path.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This function can be used to register a custom TrueType font with SixtyFPS,
|
||||||
|
/// for use with the `font-family` property. The provided slice must be a valid TrueType
|
||||||
|
/// font.
|
||||||
pub fn register_font_from_memory(data: &[u8]) -> Result<(), Box<dyn std::error::Error>> {
|
pub fn register_font_from_memory(data: &[u8]) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
sixtyfps_rendering_backend_default::backend().register_font_from_memory(data)
|
sixtyfps_rendering_backend_default::backend().register_font_from_memory(data)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ sixtyfps-compilerlib = { path = "../../../sixtyfps_compiler", features = ["displ
|
||||||
test_driver_lib = { path = "../driverlib" }
|
test_driver_lib = { path = "../driverlib" }
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
spin_on = "0.1"
|
spin_on = "0.1"
|
||||||
|
itertools = "0.10"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
test_driver_lib = { path = "../driverlib" }
|
test_driver_lib = { path = "../driverlib" }
|
||||||
|
|
|
@ -7,30 +7,28 @@
|
||||||
This file is also available under commercial licensing terms.
|
This file is also available under commercial licensing terms.
|
||||||
Please contact info@sixtyfps.io for more information.
|
Please contact info@sixtyfps.io for more information.
|
||||||
LICENSE END */
|
LICENSE END */
|
||||||
|
use itertools::Itertools;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
pub fn test(testcase: &test_driver_lib::TestCase) -> Result<(), Box<dyn Error>> {
|
pub fn test(testcase: &test_driver_lib::TestCase) -> Result<(), Box<dyn Error>> {
|
||||||
let source = std::fs::read_to_string(&testcase.absolute_path)?;
|
let source = std::fs::read_to_string(&testcase.absolute_path)?;
|
||||||
|
|
||||||
let include_paths = test_driver_lib::extract_include_paths(&source)
|
let include_paths = test_driver_lib::extract_include_paths(&source)
|
||||||
.map(std::path::PathBuf::from)
|
.map(std::path::PathBuf::from)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let mut config = sixtyfps_compilerlib::CompilerConfiguration::new(
|
let mut config =
|
||||||
sixtyfps_compilerlib::generator::OutputFormat::Interpreter,
|
sixtyfps_interpreter::CompilerConfiguration::new().with_include_paths(include_paths);
|
||||||
);
|
|
||||||
config.include_paths = include_paths;
|
|
||||||
|
|
||||||
let (component, _warnings) = match spin_on::spin_on(sixtyfps_interpreter::load(
|
// FIXME: use from_source instead of from_path
|
||||||
source,
|
let (component, diags) = spin_on::spin_on(
|
||||||
testcase.absolute_path.clone(),
|
sixtyfps_interpreter::ComponentDefinition::from_path(&testcase.absolute_path, config),
|
||||||
config,
|
);
|
||||||
)) {
|
|
||||||
(Ok(c), diagnostics) => (c, diagnostics),
|
let component = match component {
|
||||||
(Err(()), errors) => {
|
None => {
|
||||||
let vec = errors.to_string_vec();
|
sixtyfps_interpreter::print_diagnostics(&diags);
|
||||||
errors.print();
|
return Err(diags.into_iter().map(|d| d.to_string()).join("\n").into());
|
||||||
return Err(vec.join("\n").into());
|
|
||||||
}
|
}
|
||||||
|
Some(c) => c,
|
||||||
};
|
};
|
||||||
|
|
||||||
component.create();
|
component.create();
|
||||||
|
|
|
@ -10,8 +10,7 @@ homepage = "https://sixtyfps.io"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
sixtyfps-corelib = { version = "=0.0.5", path="../../sixtyfps_runtime/corelib" }
|
sixtyfps-corelib = { version = "=0.0.5", path="../../sixtyfps_runtime/corelib" }
|
||||||
sixtyfps-interpreter = { version = "=0.0.5", path = "../../sixtyfps_runtime/interpreter" }
|
sixtyfps-interpreter = { version = "=0.0.5", path = "../../sixtyfps_runtime/interpreter", features = ["display-diagnostics"] }
|
||||||
sixtyfps-compilerlib = { version = "=0.0.5", path = "../../sixtyfps_compiler", features = ["display-diagnostics"] }
|
|
||||||
vtable = { version = "0.1", path="../../helper_crates/vtable" }
|
vtable = { version = "0.1", path="../../helper_crates/vtable" }
|
||||||
structopt = "0.3.14"
|
structopt = "0.3.14"
|
||||||
codemap-diagnostic = "0.1.1"
|
codemap-diagnostic = "0.1.1"
|
||||||
|
|
|
@ -28,7 +28,6 @@ struct Cli {
|
||||||
|
|
||||||
fn main() -> std::io::Result<()> {
|
fn main() -> std::io::Result<()> {
|
||||||
let args = Cli::from_args();
|
let args = Cli::from_args();
|
||||||
let source = std::fs::read_to_string(&args.path)?;
|
|
||||||
|
|
||||||
args.load_font.map(|fonts| {
|
args.load_font.map(|fonts| {
|
||||||
fonts.iter().for_each(|font_path| {
|
fonts.iter().for_each(|font_path| {
|
||||||
|
@ -38,26 +37,24 @@ fn main() -> std::io::Result<()> {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut compiler_config = sixtyfps_compilerlib::CompilerConfiguration::new(
|
let mut compiler_config =
|
||||||
sixtyfps_compilerlib::generator::OutputFormat::Interpreter,
|
sixtyfps_interpreter::CompilerConfiguration::new().with_include_paths(args.include_paths);
|
||||||
);
|
if !args.style.is_empty() {
|
||||||
compiler_config.include_paths = args.include_paths;
|
compiler_config = compiler_config.with_style(args.style);
|
||||||
compiler_config.style = if args.style.is_empty() { None } else { Some(args.style) };
|
}
|
||||||
|
|
||||||
let c = match spin_on::spin_on(sixtyfps_interpreter::load(source, args.path, compiler_config)) {
|
let (c, diags) = spin_on::spin_on(sixtyfps_interpreter::ComponentDefinition::from_path(
|
||||||
(Ok(c), warnings) => {
|
args.path,
|
||||||
warnings.print();
|
compiler_config,
|
||||||
c
|
));
|
||||||
}
|
sixtyfps_interpreter::print_diagnostics(&diags);
|
||||||
(Err(()), errors) => {
|
|
||||||
errors.print();
|
let c = match c {
|
||||||
std::process::exit(-1);
|
Some(c) => c,
|
||||||
}
|
None => std::process::exit(-1),
|
||||||
};
|
};
|
||||||
|
|
||||||
let component = c.create();
|
let component = c.create();
|
||||||
component.window().show();
|
component.run();
|
||||||
sixtyfps_interpreter::run_event_loop();
|
|
||||||
component.window().hide();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue