mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-02 22:54:36 +00:00
Prepare for the ability to embed image data
The Image's source property used to be a string. Now it is a Resource enum, which can either be None or an absolute file path to the image on disk. This also replaces the internal Image type. The compiler internally resolves the img bang expression to a resource reference, which shall remain just an absolute path. For now the target generator passes that through, but in the future the target generator may choose a target specific way of embedding the data and thus generating a different Resource type in the final code (through compile_expression in the cpp and rust generator). The C++ binding is a bit messy as cbindgen doesn't really support exporting enums that can be constructed on the C++ side. So instead we use cbindgen to merely export the type internally and only use the tag from it then. The public API is then a custom Resource type that is meant to be binary compatible.
This commit is contained in:
parent
a756b7fa0e
commit
5bae6e01a5
18 changed files with 196 additions and 42 deletions
65
api/sixtyfps-cpp/include/sixtyfps_resource.h
Normal file
65
api/sixtyfps-cpp/include/sixtyfps_resource.h
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#pragma once
|
||||||
|
#include <string_view>
|
||||||
|
#include "sixtyfps_resource_internal.h"
|
||||||
|
#include "sixtyfps_string.h"
|
||||||
|
|
||||||
|
namespace sixtyfps {
|
||||||
|
|
||||||
|
union ResourceData {
|
||||||
|
SharedString absolute_file_path;
|
||||||
|
|
||||||
|
ResourceData() { }
|
||||||
|
~ResourceData() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Resource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Tag = internal::types::Resource::Tag;
|
||||||
|
|
||||||
|
Resource() : tag(Tag::None) { }
|
||||||
|
Resource(const SharedString &file_path) : tag(Tag::AbsoluteFilePath)
|
||||||
|
{
|
||||||
|
new (&data.absolute_file_path) SharedString(file_path);
|
||||||
|
}
|
||||||
|
Resource(const Resource &other) : tag(other.tag)
|
||||||
|
{
|
||||||
|
switch (tag) {
|
||||||
|
case Tag::None:
|
||||||
|
break;
|
||||||
|
case Tag::AbsoluteFilePath:
|
||||||
|
new (&data.absolute_file_path) SharedString(other.data.absolute_file_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~Resource() { destroy(); }
|
||||||
|
Resource &operator=(const Resource &other)
|
||||||
|
{
|
||||||
|
if (this == &other)
|
||||||
|
return *this;
|
||||||
|
destroy();
|
||||||
|
tag = other.tag;
|
||||||
|
switch (tag) {
|
||||||
|
case Tag::None:
|
||||||
|
break;
|
||||||
|
case Tag::AbsoluteFilePath:
|
||||||
|
new (&data.absolute_file_path) SharedString(other.data.absolute_file_path);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void destroy()
|
||||||
|
{
|
||||||
|
switch (tag) {
|
||||||
|
case Tag::None:
|
||||||
|
break;
|
||||||
|
case Tag::AbsoluteFilePath:
|
||||||
|
data.absolute_file_path.~SharedString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Tag tag;
|
||||||
|
ResourceData data;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
use neon::prelude::*;
|
use neon::prelude::*;
|
||||||
use sixtyfps_compilerlib::typeregister::Type;
|
use sixtyfps_compilerlib::typeregister::Type;
|
||||||
use sixtyfps_corelib::abi::datastructures::{ComponentBox, ComponentRef};
|
use sixtyfps_corelib::abi::datastructures::{ComponentBox, ComponentRef, Resource};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
mod persistent_context;
|
mod persistent_context;
|
||||||
|
@ -112,7 +112,7 @@ fn to_eval_value<'cx>(
|
||||||
}
|
}
|
||||||
Type::String => Ok(Value::String(val.to_string(cx)?.value().as_str().into())),
|
Type::String => Ok(Value::String(val.to_string(cx)?.value().as_str().into())),
|
||||||
Type::Color => todo!(),
|
Type::Color => todo!(),
|
||||||
Type::Image => todo!(),
|
Type::Resource => Ok(Value::String(val.to_string(cx)?.value().as_str().into())),
|
||||||
Type::Bool => Ok(Value::Bool(val.downcast_or_throw::<JsBoolean, _>(cx)?.value())),
|
Type::Bool => Ok(Value::Bool(val.downcast_or_throw::<JsBoolean, _>(cx)?.value())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,6 +124,10 @@ fn to_js_value<'cx>(val: interpreter::Value, cx: &mut impl Context<'cx>) -> Hand
|
||||||
Value::Number(n) => JsNumber::new(cx, n).as_value(cx),
|
Value::Number(n) => JsNumber::new(cx, n).as_value(cx),
|
||||||
Value::String(s) => JsString::new(cx, s.as_str()).as_value(cx),
|
Value::String(s) => JsString::new(cx, s.as_str()).as_value(cx),
|
||||||
Value::Bool(b) => JsBoolean::new(cx, b).as_value(cx),
|
Value::Bool(b) => JsBoolean::new(cx, b).as_value(cx),
|
||||||
|
Value::Resource(r) => match r {
|
||||||
|
Resource::None => JsUndefined::new().as_value(cx),
|
||||||
|
Resource::AbsoluteFilePath(path) => JsString::new(cx, path.as_str()).as_value(cx),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,7 @@ pub mod re_exports {
|
||||||
pub use sixtyfps_corelib::abi::signals::Signal;
|
pub use sixtyfps_corelib::abi::signals::Signal;
|
||||||
pub use sixtyfps_corelib::ComponentVTable_static;
|
pub use sixtyfps_corelib::ComponentVTable_static;
|
||||||
pub use sixtyfps_corelib::EvaluationContext;
|
pub use sixtyfps_corelib::EvaluationContext;
|
||||||
|
pub use sixtyfps_corelib::Resource;
|
||||||
pub use sixtyfps_corelib::SharedString;
|
pub use sixtyfps_corelib::SharedString;
|
||||||
pub use sixtyfps_rendering_backend_gl::sixtyfps_runtime_run_component_with_gl_renderer;
|
pub use sixtyfps_rendering_backend_gl::sixtyfps_runtime_run_component_with_gl_renderer;
|
||||||
pub use vtable::{self, *};
|
pub use vtable::{self, *};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use cgmath::{Matrix4, SquareMatrix, Vector3};
|
use cgmath::{Matrix4, SquareMatrix, Vector3};
|
||||||
use sixtyfps_corelib::abi::datastructures::{Color, RenderingPrimitive};
|
use sixtyfps_corelib::abi::datastructures::{Color, RenderingPrimitive, Resource};
|
||||||
use sixtyfps_corelib::graphics::{
|
use sixtyfps_corelib::graphics::{
|
||||||
Frame, GraphicsBackend, RenderingCache, RenderingPrimitivesBuilder,
|
Frame, GraphicsBackend, RenderingCache, RenderingPrimitivesBuilder,
|
||||||
};
|
};
|
||||||
|
@ -57,7 +57,7 @@ fn main() {
|
||||||
let image_primitive = rendering_primitives_builder.create(RenderingPrimitive::Image {
|
let image_primitive = rendering_primitives_builder.create(RenderingPrimitive::Image {
|
||||||
x: 0.,
|
x: 0.,
|
||||||
y: 0.,
|
y: 0.,
|
||||||
source: logo_path.to_str().unwrap().into(),
|
source: Resource::AbsoluteFilePath(logo_path.to_str().unwrap().into()),
|
||||||
});
|
});
|
||||||
|
|
||||||
render_cache.allocate_entry(image_primitive)
|
render_cache.allocate_entry(image_primitive)
|
||||||
|
|
|
@ -18,21 +18,34 @@ pub enum Expression {
|
||||||
/// Reference to the signal <name> in the <element> within the <Component>
|
/// Reference to the signal <name> in the <element> within the <Component>
|
||||||
///
|
///
|
||||||
/// Note: if we are to separate expression and statement, we probably do not need to have signal reference within expressions
|
/// Note: if we are to separate expression and statement, we probably do not need to have signal reference within expressions
|
||||||
SignalReference { component: Weak<Component>, element: Weak<RefCell<Element>>, name: String },
|
SignalReference {
|
||||||
|
component: Weak<Component>,
|
||||||
|
element: Weak<RefCell<Element>>,
|
||||||
|
name: String,
|
||||||
|
},
|
||||||
|
|
||||||
/// Reference to the signal <name> in the <element> within the <Component>
|
/// Reference to the signal <name> in the <element> within the <Component>
|
||||||
///
|
///
|
||||||
/// Note: if we are to separate expression and statement, we probably do not need to have signal reference within expressions
|
/// Note: if we are to separate expression and statement, we probably do not need to have signal reference within expressions
|
||||||
PropertyReference { component: Weak<Component>, element: Weak<RefCell<Element>>, name: String },
|
PropertyReference {
|
||||||
|
component: Weak<Component>,
|
||||||
|
element: Weak<RefCell<Element>>,
|
||||||
|
name: String,
|
||||||
|
},
|
||||||
|
|
||||||
/// Cast an expression to the given type
|
/// Cast an expression to the given type
|
||||||
Cast { from: Box<Expression>, to: Type },
|
Cast {
|
||||||
|
from: Box<Expression>,
|
||||||
|
to: Type,
|
||||||
|
},
|
||||||
|
|
||||||
/// a code block with different expression
|
/// a code block with different expression
|
||||||
CodeBlock(Vec<Expression>),
|
CodeBlock(Vec<Expression>),
|
||||||
|
|
||||||
/// A function call
|
/// A function call
|
||||||
FunctionCall { function: Box<Expression> },
|
FunctionCall {
|
||||||
|
function: Box<Expression>,
|
||||||
|
},
|
||||||
|
|
||||||
SelfAssignement {
|
SelfAssignement {
|
||||||
lhs: Box<Expression>,
|
lhs: Box<Expression>,
|
||||||
|
@ -40,6 +53,10 @@ pub enum Expression {
|
||||||
/// '+', '-', '/', or '*'
|
/// '+', '-', '/', or '*'
|
||||||
op: char,
|
op: char,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
ResourceReference {
|
||||||
|
absolute_source_path: String,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expression {
|
impl Expression {
|
||||||
|
@ -58,6 +75,7 @@ impl Expression {
|
||||||
Expression::CodeBlock(sub) => sub.last().map_or(Type::Invalid, |e| e.ty()),
|
Expression::CodeBlock(sub) => sub.last().map_or(Type::Invalid, |e| e.ty()),
|
||||||
Expression::FunctionCall { function } => function.ty(),
|
Expression::FunctionCall { function } => function.ty(),
|
||||||
Expression::SelfAssignement { .. } => Type::Invalid,
|
Expression::SelfAssignement { .. } => Type::Invalid,
|
||||||
|
Expression::ResourceReference { .. } => Type::Resource,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +99,7 @@ impl Expression {
|
||||||
visitor(&**lhs);
|
visitor(&**lhs);
|
||||||
visitor(&**rhs);
|
visitor(&**rhs);
|
||||||
}
|
}
|
||||||
|
Expression::ResourceReference { .. } => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,6 +122,7 @@ impl Expression {
|
||||||
visitor(&mut **lhs);
|
visitor(&mut **lhs);
|
||||||
visitor(&mut **rhs);
|
visitor(&mut **rhs);
|
||||||
}
|
}
|
||||||
|
Expression::ResourceReference { .. } => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,6 +138,7 @@ impl Expression {
|
||||||
Expression::CodeBlock(sub) => sub.len() == 1 && sub.first().unwrap().is_constant(),
|
Expression::CodeBlock(sub) => sub.len() == 1 && sub.first().unwrap().is_constant(),
|
||||||
Expression::FunctionCall { .. } => false,
|
Expression::FunctionCall { .. } => false,
|
||||||
Expression::SelfAssignement { .. } => false,
|
Expression::SelfAssignement { .. } => false,
|
||||||
|
Expression::ResourceReference { .. } => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -354,6 +354,9 @@ fn compile_expression(e: &crate::expression_tree::Expression) -> String {
|
||||||
),
|
),
|
||||||
_ => panic!("typechecking should make sure this was a PropertyReference"),
|
_ => panic!("typechecking should make sure this was a PropertyReference"),
|
||||||
},
|
},
|
||||||
|
ResourceReference { absolute_source_path } => {
|
||||||
|
format!(r#"sixtyfps::Resource(sixtyfps::SharedString("{}"))"#, absolute_source_path)
|
||||||
|
}
|
||||||
Uncompiled(_) => panic!(),
|
Uncompiled(_) => panic!(),
|
||||||
Invalid => format!("\n#error invalid expression\n"),
|
Invalid => format!("\n#error invalid expression\n"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -212,6 +212,9 @@ fn compile_expression(e: &Expression) -> TokenStream {
|
||||||
}
|
}
|
||||||
_ => panic!("typechecking should make sure this was a PropertyReference"),
|
_ => panic!("typechecking should make sure this was a PropertyReference"),
|
||||||
},
|
},
|
||||||
|
Expression::ResourceReference { absolute_source_path } => {
|
||||||
|
quote!(sixtyfps::re_exports::Resource::AbsoluteFilePath(sixtyfps::re_exports::SharedString::from(#absolute_source_path)))
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let error = format!("unsupported expression {:?}", e);
|
let error = format!("unsupported expression {:?}", e);
|
||||||
quote!(compile_error! {#error})
|
quote!(compile_error! {#error})
|
||||||
|
|
|
@ -163,18 +163,27 @@ impl Expression {
|
||||||
return Self::Invalid;
|
return Self::Invalid;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let path = std::path::Path::new(&s);
|
|
||||||
|
|
||||||
if path.is_absolute() {
|
let absolute_source_path = {
|
||||||
return Expression::StringLiteral(s);
|
let path = std::path::Path::new(&s);
|
||||||
}
|
|
||||||
let path = ctx.diag.path(node.span()).parent().unwrap().join(path);
|
if path.is_absolute() {
|
||||||
if path.is_absolute() {
|
s
|
||||||
return Expression::StringLiteral(path.to_string_lossy().to_string());
|
} else {
|
||||||
}
|
let path = ctx.diag.path(node.span()).parent().unwrap().join(path);
|
||||||
Expression::StringLiteral(
|
if path.is_absolute() {
|
||||||
std::env::current_dir().unwrap().join(path).to_string_lossy().to_string(),
|
path.to_string_lossy().to_string()
|
||||||
)
|
} else {
|
||||||
|
std::env::current_dir()
|
||||||
|
.unwrap()
|
||||||
|
.join(path)
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Expression::ResourceReference { absolute_source_path }
|
||||||
}
|
}
|
||||||
Some(x) => {
|
Some(x) => {
|
||||||
ctx.diag.push_error(format!("Unknown bang keyword `{}`", x), node.span());
|
ctx.diag.push_error(format!("Unknown bang keyword `{}`", x), node.span());
|
||||||
|
|
|
@ -5,7 +5,7 @@ SubElements := Rectangle {
|
||||||
color: blue;
|
color: blue;
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
source: "foo.png";
|
source: img!"foo.png";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ pub enum Type {
|
||||||
Int32,
|
Int32,
|
||||||
String,
|
String,
|
||||||
Color,
|
Color,
|
||||||
Image,
|
Resource,
|
||||||
Bool,
|
Bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ impl core::cmp::PartialEq for Type {
|
||||||
(Type::Int32, Type::Int32) => true,
|
(Type::Int32, Type::Int32) => true,
|
||||||
(Type::String, Type::String) => true,
|
(Type::String, Type::String) => true,
|
||||||
(Type::Color, Type::Color) => true,
|
(Type::Color, Type::Color) => true,
|
||||||
(Type::Image, Type::Image) => true,
|
(Type::Resource, Type::Resource) => true,
|
||||||
(Type::Bool, Type::Bool) => true,
|
(Type::Bool, Type::Bool) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ impl Display for Type {
|
||||||
Type::Int32 => write!(f, "int32"),
|
Type::Int32 => write!(f, "int32"),
|
||||||
Type::String => write!(f, "string"),
|
Type::String => write!(f, "string"),
|
||||||
Type::Color => write!(f, "color"),
|
Type::Color => write!(f, "color"),
|
||||||
Type::Image => write!(f, "image"),
|
Type::Resource => write!(f, "resource"),
|
||||||
Type::Bool => write!(f, "bool"),
|
Type::Bool => write!(f, "bool"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ impl Type {
|
||||||
pub fn is_property_type(&self) -> bool {
|
pub fn is_property_type(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
Self::Float32 | Self::Int32 | Self::String | Self::Color | Self::Image | Self::Bool
|
Self::Float32 | Self::Int32 | Self::String | Self::Color | Self::Resource | Self::Bool
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +95,6 @@ impl Type {
|
||||||
// FIXME: REMOVE
|
// FIXME: REMOVE
|
||||||
| (Type::Float32, Type::Color)
|
| (Type::Float32, Type::Color)
|
||||||
| (Type::Int32, Type::Color)
|
| (Type::Int32, Type::Color)
|
||||||
| (Type::String, Type::Image)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,7 +134,7 @@ impl TypeRegister {
|
||||||
instert_type(Type::Int32);
|
instert_type(Type::Int32);
|
||||||
instert_type(Type::String);
|
instert_type(Type::String);
|
||||||
instert_type(Type::Color);
|
instert_type(Type::Color);
|
||||||
instert_type(Type::Image);
|
instert_type(Type::Resource);
|
||||||
instert_type(Type::Bool);
|
instert_type(Type::Bool);
|
||||||
|
|
||||||
let mut rectangle = BuiltinElement::new("Rectangle");
|
let mut rectangle = BuiltinElement::new("Rectangle");
|
||||||
|
@ -147,7 +146,7 @@ impl TypeRegister {
|
||||||
r.types.insert("Rectangle".to_owned(), Type::Builtin(Rc::new(rectangle)));
|
r.types.insert("Rectangle".to_owned(), Type::Builtin(Rc::new(rectangle)));
|
||||||
|
|
||||||
let mut image = BuiltinElement::new("Image");
|
let mut image = BuiltinElement::new("Image");
|
||||||
image.properties.insert("source".to_owned(), Type::Image);
|
image.properties.insert("source".to_owned(), Type::Resource);
|
||||||
image.properties.insert("x".to_owned(), Type::Float32);
|
image.properties.insert("x".to_owned(), Type::Float32);
|
||||||
image.properties.insert("y".to_owned(), Type::Float32);
|
image.properties.insert("y".to_owned(), Type::Float32);
|
||||||
image.properties.insert("width".to_owned(), Type::Float32);
|
image.properties.insert("width".to_owned(), Type::Float32);
|
||||||
|
|
|
@ -204,6 +204,24 @@ impl Color {
|
||||||
pub const WHITE: Color = Color::from_rgb(255, 255, 255);
|
pub const WHITE: Color = Color::from_rgb(255, 255, 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A resource is a reference to binary data, for example images. They can be accessible on the file
|
||||||
|
/// system or embedded in the resulting binary. Or they might be URLs to a web server and a downloaded
|
||||||
|
/// is necessary before they can be used.
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum Resource {
|
||||||
|
/// A resource that does not represent any data.
|
||||||
|
None,
|
||||||
|
/// A resource that points to a file in the file system
|
||||||
|
AbsoluteFilePath(crate::SharedString),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Resource {
|
||||||
|
fn default() -> Self {
|
||||||
|
Resource::None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Each item return a RenderingPrimitive to the backend with information about what to draw.
|
/// Each item return a RenderingPrimitive to the backend with information about what to draw.
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -221,7 +239,7 @@ pub enum RenderingPrimitive {
|
||||||
Image {
|
Image {
|
||||||
x: f32,
|
x: f32,
|
||||||
y: f32,
|
y: f32,
|
||||||
source: crate::SharedString,
|
source: crate::Resource,
|
||||||
},
|
},
|
||||||
Text {
|
Text {
|
||||||
x: f32,
|
x: f32,
|
||||||
|
|
|
@ -16,7 +16,7 @@ When adding an item or a property, it needs to be kept in sync with different pl
|
||||||
#![allow(missing_docs)] // because documenting each property of items is redundent
|
#![allow(missing_docs)] // because documenting each property of items is redundent
|
||||||
|
|
||||||
use super::datastructures::{
|
use super::datastructures::{
|
||||||
CachedRenderingData, Color, Item, ItemConsts, LayoutInfo, Rect, RenderingPrimitive,
|
CachedRenderingData, Color, Item, ItemConsts, LayoutInfo, Rect, RenderingPrimitive, Resource,
|
||||||
};
|
};
|
||||||
use crate::rtti::*;
|
use crate::rtti::*;
|
||||||
use crate::{EvaluationContext, Property, SharedString, Signal};
|
use crate::{EvaluationContext, Property, SharedString, Signal};
|
||||||
|
@ -81,8 +81,7 @@ pub use crate::abi::datastructures::RectangleVTable;
|
||||||
#[derive(FieldOffsets, Default, BuiltinItem)]
|
#[derive(FieldOffsets, Default, BuiltinItem)]
|
||||||
/// The implementation of the `Image` element
|
/// The implementation of the `Image` element
|
||||||
pub struct Image {
|
pub struct Image {
|
||||||
/// FIXME: make it a image source
|
pub source: Property<Resource>,
|
||||||
pub source: Property<SharedString>,
|
|
||||||
pub x: Property<f32>,
|
pub x: Property<f32>,
|
||||||
pub y: Property<f32>,
|
pub y: Property<f32>,
|
||||||
pub width: Property<f32>,
|
pub width: Property<f32>,
|
||||||
|
|
|
@ -9,7 +9,8 @@ fn main() {
|
||||||
.map(|x| x.to_string())
|
.map(|x| x.to_string())
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
let exclude = ["SharedString"].iter().map(|x| x.to_string()).collect::<Vec<String>>();
|
let exclude =
|
||||||
|
["SharedString", "Resource"].iter().map(|x| x.to_string()).collect::<Vec<String>>();
|
||||||
|
|
||||||
let config = cbindgen::Config {
|
let config = cbindgen::Config {
|
||||||
pragma_once: true,
|
pragma_once: true,
|
||||||
|
@ -56,6 +57,23 @@ fn main() {
|
||||||
.expect("Unable to generate bindings")
|
.expect("Unable to generate bindings")
|
||||||
.write_to_file(include_dir.join("sixtyfps_signals_internal.h"));
|
.write_to_file(include_dir.join("sixtyfps_signals_internal.h"));
|
||||||
|
|
||||||
|
let mut resource_config = config.clone();
|
||||||
|
resource_config.export.include = ["Resource"].iter().map(|s| s.to_string()).collect();
|
||||||
|
resource_config.enumeration = cbindgen::EnumConfig {
|
||||||
|
derive_tagged_enum_copy_assignment: true,
|
||||||
|
derive_tagged_enum_copy_constructor: true,
|
||||||
|
derive_tagged_enum_destructor: true,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
resource_config.namespaces = Some(vec!["sixtyfps".into(), "internal".into(), "types".into()]);
|
||||||
|
resource_config.export.exclude.clear();
|
||||||
|
cbindgen::Builder::new()
|
||||||
|
.with_config(resource_config)
|
||||||
|
.with_src(crate_dir.join("abi/datastructures.rs"))
|
||||||
|
.generate()
|
||||||
|
.expect("Unable to generate bindings")
|
||||||
|
.write_to_file(include_dir.join("sixtyfps_resource_internal.h"));
|
||||||
|
|
||||||
cbindgen::Builder::new()
|
cbindgen::Builder::new()
|
||||||
.with_config(config)
|
.with_config(config)
|
||||||
.with_src(crate_dir.join("abi/datastructures.rs"))
|
.with_src(crate_dir.join("abi/datastructures.rs"))
|
||||||
|
@ -65,6 +83,7 @@ fn main() {
|
||||||
.with_include("sixtyfps_string.h")
|
.with_include("sixtyfps_string.h")
|
||||||
.with_include("sixtyfps_properties.h")
|
.with_include("sixtyfps_properties.h")
|
||||||
.with_include("sixtyfps_signals.h")
|
.with_include("sixtyfps_signals.h")
|
||||||
|
.with_include("sixtyfps_resource.h")
|
||||||
.generate()
|
.generate()
|
||||||
.expect("Unable to generate bindings")
|
.expect("Unable to generate bindings")
|
||||||
.write_to_file(include_dir.join("sixtyfps_internal.h"));
|
.write_to_file(include_dir.join("sixtyfps_internal.h"));
|
||||||
|
|
|
@ -28,6 +28,9 @@ pub mod rtti;
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use abi::string::SharedString;
|
pub use abi::string::SharedString;
|
||||||
|
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use abi::datastructures::Resource;
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use abi::properties::{EvaluationContext, Property};
|
pub use abi::properties::{EvaluationContext, Property};
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ macro_rules! declare_ValueType {
|
||||||
pub trait ValueType: 'static $(+ TryInto<$ty> + TryFrom<$ty>)* {}
|
pub trait ValueType: 'static $(+ TryInto<$ty> + TryFrom<$ty>)* {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
declare_ValueType![bool, u32, u64, i32, i64, f32, f64, crate::SharedString];
|
declare_ValueType![bool, u32, u64, i32, i64, f32, f64, crate::SharedString, crate::Resource];
|
||||||
|
|
||||||
pub trait PropertyInfo<Item, Value> {
|
pub trait PropertyInfo<Item, Value> {
|
||||||
fn get(&self, item: &Item, context: &crate::EvaluationContext) -> Result<Value, ()>;
|
fn get(&self, item: &Item, context: &crate::EvaluationContext) -> Result<Value, ()>;
|
||||||
|
|
|
@ -6,7 +6,7 @@ use object_tree::Element;
|
||||||
use sixtyfps_compilerlib::typeregister::Type;
|
use sixtyfps_compilerlib::typeregister::Type;
|
||||||
use sixtyfps_compilerlib::*;
|
use sixtyfps_compilerlib::*;
|
||||||
use sixtyfps_corelib::abi::datastructures::{
|
use sixtyfps_corelib::abi::datastructures::{
|
||||||
ComponentBox, ComponentRef, ComponentVTable, ItemTreeNode, ItemVTable,
|
ComponentBox, ComponentRef, ComponentVTable, ItemTreeNode, ItemVTable, Resource,
|
||||||
};
|
};
|
||||||
use sixtyfps_corelib::rtti::PropertyInfo;
|
use sixtyfps_corelib::rtti::PropertyInfo;
|
||||||
use sixtyfps_corelib::{rtti, EvaluationContext, Property, SharedString, Signal};
|
use sixtyfps_corelib::{rtti, EvaluationContext, Property, SharedString, Signal};
|
||||||
|
@ -153,7 +153,7 @@ pub fn load(
|
||||||
Type::Int32 => property_info::<u32>(),
|
Type::Int32 => property_info::<u32>(),
|
||||||
Type::String => property_info::<SharedString>(),
|
Type::String => property_info::<SharedString>(),
|
||||||
Type::Color => property_info::<u32>(),
|
Type::Color => property_info::<u32>(),
|
||||||
Type::Image => property_info::<SharedString>(),
|
Type::Resource => property_info::<Resource>(),
|
||||||
Type::Bool => property_info::<bool>(),
|
Type::Bool => property_info::<bool>(),
|
||||||
Type::Signal => {
|
Type::Signal => {
|
||||||
custom_signals.insert(name.clone(), builder.add_field_type::<Signal<()>>());
|
custom_signals.insert(name.clone(), builder.add_field_type::<Signal<()>>());
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use sixtyfps_compilerlib::expression_tree::Expression;
|
use sixtyfps_compilerlib::expression_tree::Expression;
|
||||||
use sixtyfps_compilerlib::typeregister::Type;
|
use sixtyfps_compilerlib::typeregister::Type;
|
||||||
use sixtyfps_corelib as corelib;
|
use sixtyfps_corelib as corelib;
|
||||||
use sixtyfps_corelib::{abi::datastructures::ItemRef, EvaluationContext, SharedString};
|
use sixtyfps_corelib::{abi::datastructures::ItemRef, EvaluationContext, Resource, SharedString};
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
|
|
||||||
pub trait ErasedPropertyInfo {
|
pub trait ErasedPropertyInfo {
|
||||||
|
@ -30,6 +30,7 @@ pub enum Value {
|
||||||
Number(f64),
|
Number(f64),
|
||||||
String(SharedString),
|
String(SharedString),
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
|
Resource(Resource),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl corelib::rtti::ValueType for Value {}
|
impl corelib::rtti::ValueType for Value {}
|
||||||
|
@ -59,6 +60,7 @@ macro_rules! declare_value_conversion {
|
||||||
declare_value_conversion!(Number => [u32, u64, i32, i64, f32, f64] );
|
declare_value_conversion!(Number => [u32, u64, i32, i64, f32, f64] );
|
||||||
declare_value_conversion!(String => [SharedString] );
|
declare_value_conversion!(String => [SharedString] );
|
||||||
declare_value_conversion!(Bool => [bool] );
|
declare_value_conversion!(Bool => [bool] );
|
||||||
|
declare_value_conversion!(Resource => [Resource] );
|
||||||
|
|
||||||
pub fn eval_expression(
|
pub fn eval_expression(
|
||||||
e: &Expression,
|
e: &Expression,
|
||||||
|
@ -160,5 +162,8 @@ pub fn eval_expression(
|
||||||
}
|
}
|
||||||
_ => panic!("typechecking should make sure this was a PropertyReference"),
|
_ => panic!("typechecking should make sure this was a PropertyReference"),
|
||||||
},
|
},
|
||||||
|
Expression::ResourceReference { absolute_source_path } => {
|
||||||
|
Value::Resource(Resource::AbsoluteFilePath(absolute_source_path.as_str().into()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use itertools::Itertools;
|
||||||
use lyon::tessellation::geometry_builder::{BuffersBuilder, VertexBuffers};
|
use lyon::tessellation::geometry_builder::{BuffersBuilder, VertexBuffers};
|
||||||
use lyon::tessellation::{FillAttributes, FillOptions, FillTessellator};
|
use lyon::tessellation::{FillAttributes, FillOptions, FillTessellator};
|
||||||
use sixtyfps_corelib::abi::datastructures::{
|
use sixtyfps_corelib::abi::datastructures::{
|
||||||
Color, ComponentVTable, Point, Rect, RenderingPrimitive, Size,
|
Color, ComponentVTable, Point, Rect, RenderingPrimitive, Resource, Size,
|
||||||
};
|
};
|
||||||
use sixtyfps_corelib::graphics::{
|
use sixtyfps_corelib::graphics::{
|
||||||
FillStyle, Frame as GraphicsFrame, GraphicsBackend, HasRenderingPrimitive,
|
FillStyle, Frame as GraphicsFrame, GraphicsBackend, HasRenderingPrimitive,
|
||||||
|
@ -306,11 +306,16 @@ impl RenderingPrimitivesBuilder for GLRenderingPrimitivesBuilder {
|
||||||
Some(self.create_path(&rect_path.build(), FillStyle::SolidColor(*color)))
|
Some(self.create_path(&rect_path.build(), FillStyle::SolidColor(*color)))
|
||||||
}
|
}
|
||||||
RenderingPrimitive::Image { x: _, y: _, source } => {
|
RenderingPrimitive::Image { x: _, y: _, source } => {
|
||||||
let mut image_path = std::env::current_exe().unwrap();
|
match source {
|
||||||
image_path.pop(); // pop of executable name
|
Resource::AbsoluteFilePath(path) => {
|
||||||
image_path.push(&*source.clone());
|
let mut image_path = std::env::current_exe().unwrap();
|
||||||
let image = image::open(image_path.as_path()).unwrap().into_rgba();
|
image_path.pop(); // pop of executable name
|
||||||
Some(self.create_image(image))
|
image_path.push(&*path.clone());
|
||||||
|
let image = image::open(image_path.as_path()).unwrap().into_rgba();
|
||||||
|
Some(self.create_image(image))
|
||||||
|
}
|
||||||
|
Resource::None => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
RenderingPrimitive::Text {
|
RenderingPrimitive::Text {
|
||||||
x: _,
|
x: _,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue