mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 14:21:16 +00:00
Rename Rectangle.color to Rectangle.background
Add support for built-in property aliases and rename `color` to `background` - in preparation for it also changing to type brush. Right now the alias is silent, a deprecation and overall change will come in a subsequent change.
This commit is contained in:
parent
c479fd132d
commit
1f091cb1c0
16 changed files with 250 additions and 131 deletions
|
@ -19,7 +19,8 @@ LICENSE END */
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Rectangle := _ {
|
Rectangle := _ {
|
||||||
property <color> color;
|
property <color> background;
|
||||||
|
property <color> color <=> background;
|
||||||
property <length> x;
|
property <length> x;
|
||||||
property <length> y;
|
property <length> y;
|
||||||
property <length> width;
|
property <length> width;
|
||||||
|
|
|
@ -420,13 +420,13 @@ impl Expression {
|
||||||
Expression::NumberLiteral(_, unit) => unit.ty(),
|
Expression::NumberLiteral(_, unit) => unit.ty(),
|
||||||
Expression::BoolLiteral(_) => Type::Bool,
|
Expression::BoolLiteral(_) => Type::Bool,
|
||||||
Expression::TwoWayBinding(NamedReference { element, name }, _) => {
|
Expression::TwoWayBinding(NamedReference { element, name }, _) => {
|
||||||
element.upgrade().unwrap().borrow().lookup_property(name)
|
element.upgrade().unwrap().borrow().lookup_property(name).property_type
|
||||||
}
|
}
|
||||||
Expression::CallbackReference(NamedReference { element, name }) => {
|
Expression::CallbackReference(NamedReference { element, name }) => {
|
||||||
element.upgrade().unwrap().borrow().lookup_property(name)
|
element.upgrade().unwrap().borrow().lookup_property(name).property_type
|
||||||
}
|
}
|
||||||
Expression::PropertyReference(NamedReference { element, name }) => {
|
Expression::PropertyReference(NamedReference { element, name }) => {
|
||||||
element.upgrade().unwrap().borrow().lookup_property(name)
|
element.upgrade().unwrap().borrow().lookup_property(name).property_type
|
||||||
}
|
}
|
||||||
Expression::BuiltinFunctionReference(funcref) => funcref.ty(),
|
Expression::BuiltinFunctionReference(funcref) => funcref.ty(),
|
||||||
Expression::MemberFunction { member, .. } => member.ty(),
|
Expression::MemberFunction { member, .. } => member.ty(),
|
||||||
|
@ -456,7 +456,7 @@ impl Expression {
|
||||||
Type::Object { fields, .. } => {
|
Type::Object { fields, .. } => {
|
||||||
fields.get(name.as_str()).unwrap_or(&Type::Invalid).clone()
|
fields.get(name.as_str()).unwrap_or(&Type::Invalid).clone()
|
||||||
}
|
}
|
||||||
Type::Component(c) => c.root_element.borrow().lookup_property(name.as_str()),
|
Type::Component(c) => c.root_element.borrow().lookup_property(name).property_type,
|
||||||
_ => Type::Invalid,
|
_ => Type::Invalid,
|
||||||
},
|
},
|
||||||
Expression::Cast { to, .. } => to.clone(),
|
Expression::Cast { to, .. } => to.clone(),
|
||||||
|
|
|
@ -337,7 +337,7 @@ fn handle_property_binding(
|
||||||
let item = elem.borrow();
|
let item = elem.borrow();
|
||||||
let component = item.enclosing_component.upgrade().unwrap();
|
let component = item.enclosing_component.upgrade().unwrap();
|
||||||
let id = &item.id;
|
let id = &item.id;
|
||||||
let prop_type = item.lookup_property(prop_name);
|
let prop_type = item.lookup_property(prop_name).property_type;
|
||||||
if let Type::Callback { args, .. } = &prop_type {
|
if let Type::Callback { args, .. } = &prop_type {
|
||||||
let callback_accessor_prefix = if item.property_declarations.contains_key(prop_name) {
|
let callback_accessor_prefix = if item.property_declarations.contains_key(prop_name) {
|
||||||
String::new()
|
String::new()
|
||||||
|
@ -2059,14 +2059,14 @@ impl<'a> LayoutTreeItem<'a> {
|
||||||
let path_layout_item_data =
|
let path_layout_item_data =
|
||||||
|elem: &ElementRc, elem_cpp: &str, component_cpp: &str| {
|
|elem: &ElementRc, elem_cpp: &str, component_cpp: &str| {
|
||||||
let prop_ref = |n: &str| {
|
let prop_ref = |n: &str| {
|
||||||
if elem.borrow().lookup_property(n) == Type::Length {
|
if elem.borrow().lookup_property(n).property_type == Type::Length {
|
||||||
format!("&{}.{}", elem_cpp, n)
|
format!("&{}.{}", elem_cpp, n)
|
||||||
} else {
|
} else {
|
||||||
"nullptr".to_owned()
|
"nullptr".to_owned()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let prop_value = |n: &str| {
|
let prop_value = |n: &str| {
|
||||||
if elem.borrow().lookup_property(n) == Type::Length {
|
if elem.borrow().lookup_property(n).property_type == Type::Length {
|
||||||
let value_accessor = access_member(
|
let value_accessor = access_member(
|
||||||
&elem,
|
&elem,
|
||||||
n,
|
n,
|
||||||
|
|
|
@ -146,7 +146,7 @@ fn handle_property_binding(
|
||||||
init: &mut Vec<TokenStream>,
|
init: &mut Vec<TokenStream>,
|
||||||
) {
|
) {
|
||||||
let rust_property = access_member(item_rc, prop_name, component, quote!(_self), false);
|
let rust_property = access_member(item_rc, prop_name, component, quote!(_self), false);
|
||||||
let prop_type = item_rc.borrow().lookup_property(prop_name);
|
let prop_type = item_rc.borrow().lookup_property(prop_name).property_type;
|
||||||
if matches!(prop_type, Type::Callback{..}) {
|
if matches!(prop_type, Type::Callback{..}) {
|
||||||
let tokens_for_expression = compile_expression(binding_expression, &component);
|
let tokens_for_expression = compile_expression(binding_expression, &component);
|
||||||
init.push(quote!(
|
init.push(quote!(
|
||||||
|
@ -1774,7 +1774,7 @@ impl<'a> LayoutTreeItem<'a> {
|
||||||
let path_layout_item_data =
|
let path_layout_item_data =
|
||||||
|elem: &ElementRc, elem_rs: TokenStream, component_rust: TokenStream| {
|
|elem: &ElementRc, elem_rs: TokenStream, component_rust: TokenStream| {
|
||||||
let prop_ref = |n: &str| {
|
let prop_ref = |n: &str| {
|
||||||
if elem.borrow().lookup_property(n) == Type::Length {
|
if elem.borrow().lookup_property(n).property_type == Type::Length {
|
||||||
let n = format_ident!("{}", n);
|
let n = format_ident!("{}", n);
|
||||||
quote! {Some(& #elem_rs.#n)}
|
quote! {Some(& #elem_rs.#n)}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1782,7 +1782,7 @@ impl<'a> LayoutTreeItem<'a> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let prop_value = |n: &str| {
|
let prop_value = |n: &str| {
|
||||||
if elem.borrow().lookup_property(n) == Type::Length {
|
if elem.borrow().lookup_property(n).property_type == Type::Length {
|
||||||
let accessor = access_member(
|
let accessor = access_member(
|
||||||
&elem,
|
&elem,
|
||||||
n,
|
n,
|
||||||
|
|
|
@ -7,8 +7,10 @@
|
||||||
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 std::borrow::Cow;
|
||||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||||
use std::{fmt::Display, rc::Rc};
|
use std::fmt::Display;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::expression_tree::{Expression, Unit};
|
use crate::expression_tree::{Expression, Unit};
|
||||||
use crate::object_tree::Component;
|
use crate::object_tree::Component;
|
||||||
|
@ -193,18 +195,39 @@ impl Type {
|
||||||
!matches!(self, Self::Duration | Self::Easing | Self::Angle)
|
!matches!(self, Self::Duration | Self::Easing | Self::Angle)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup_property(&self, name: &str) -> Type {
|
pub fn lookup_property<'a>(&self, name: &'a str) -> PropertyLookupResult<'a> {
|
||||||
match self {
|
match self {
|
||||||
Type::Component(c) => c.root_element.borrow().lookup_property(name),
|
Type::Component(c) => c.root_element.borrow().lookup_property(name),
|
||||||
Type::Builtin(b) => b.properties.get(name).cloned().unwrap_or_else(|| {
|
Type::Builtin(b) => {
|
||||||
|
let resolved_name =
|
||||||
|
if let Some(alias_name) = b.native_class.lookup_alias(name.as_ref()) {
|
||||||
|
Cow::Owned(alias_name.to_string())
|
||||||
|
} else {
|
||||||
|
Cow::Borrowed(name)
|
||||||
|
};
|
||||||
|
let property_type =
|
||||||
|
b.properties.get(resolved_name.as_ref()).cloned().unwrap_or_else(|| {
|
||||||
if b.is_non_item_type {
|
if b.is_non_item_type {
|
||||||
Type::Invalid
|
Type::Invalid
|
||||||
} else {
|
} else {
|
||||||
crate::typeregister::reserved_property(name)
|
crate::typeregister::reserved_property(resolved_name.as_ref())
|
||||||
}
|
}
|
||||||
}),
|
});
|
||||||
Type::Native(n) => n.lookup_property(name).unwrap_or_default(),
|
PropertyLookupResult { resolved_name, property_type }
|
||||||
_ => Type::Invalid,
|
}
|
||||||
|
Type::Native(n) => {
|
||||||
|
let resolved_name = if let Some(alias_name) = n.lookup_alias(name.as_ref()) {
|
||||||
|
Cow::Owned(alias_name.to_string())
|
||||||
|
} else {
|
||||||
|
Cow::Borrowed(name)
|
||||||
|
};
|
||||||
|
let property_type = n.lookup_property(resolved_name.as_ref()).unwrap_or_default();
|
||||||
|
PropertyLookupResult { resolved_name, property_type }
|
||||||
|
}
|
||||||
|
_ => PropertyLookupResult {
|
||||||
|
resolved_name: Cow::Borrowed(name),
|
||||||
|
property_type: Type::Invalid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,6 +415,7 @@ pub struct NativeClass {
|
||||||
pub class_name: String,
|
pub class_name: String,
|
||||||
pub vtable_symbol: String,
|
pub vtable_symbol: String,
|
||||||
pub properties: HashMap<String, Type>,
|
pub properties: HashMap<String, Type>,
|
||||||
|
pub deprecated_aliases: HashMap<String, String>,
|
||||||
pub cpp_type: Option<String>,
|
pub cpp_type: Option<String>,
|
||||||
pub rust_type_constructor: Option<String>,
|
pub rust_type_constructor: Option<String>,
|
||||||
}
|
}
|
||||||
|
@ -441,6 +465,18 @@ impl NativeClass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn lookup_alias(&self, name: &str) -> Option<&str> {
|
||||||
|
if let Some(alias_target) = self.deprecated_aliases.get(name) {
|
||||||
|
Some(alias_target)
|
||||||
|
} else if self.properties.contains_key(name) {
|
||||||
|
None
|
||||||
|
} else if let Some(parent_class) = &self.parent {
|
||||||
|
parent_class.lookup_alias(name)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn lookup_property_distance(self: Rc<Self>, name: &str) -> (usize, Rc<Self>) {
|
fn lookup_property_distance(self: Rc<Self>, name: &str) -> (usize, Rc<Self>) {
|
||||||
let mut distance = 0;
|
let mut distance = 0;
|
||||||
let mut class = self;
|
let mut class = self;
|
||||||
|
@ -559,6 +595,11 @@ fn test_select_minimal_class_based_on_property_usage() {
|
||||||
assert_eq!(reduce_to_second.class_name, second.class_name);
|
assert_eq!(reduce_to_second.class_name, second.class_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct PropertyLookupResult<'a> {
|
||||||
|
pub resolved_name: std::borrow::Cow<'a, str>,
|
||||||
|
pub property_type: Type,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Enumeration {
|
pub struct Enumeration {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
|
@ -9,9 +9,9 @@
|
||||||
LICENSE END */
|
LICENSE END */
|
||||||
//! Datastructures used to represent layouts in the compiler
|
//! Datastructures used to represent layouts in the compiler
|
||||||
|
|
||||||
use crate::diagnostics::BuildDiagnostics;
|
|
||||||
use crate::langtype::Type;
|
use crate::langtype::Type;
|
||||||
use crate::object_tree::{ElementRc, PropertyDeclaration};
|
use crate::object_tree::{ElementRc, PropertyDeclaration};
|
||||||
|
use crate::{diagnostics::BuildDiagnostics, langtype::PropertyLookupResult};
|
||||||
use crate::{
|
use crate::{
|
||||||
expression_tree::{Expression, NamedReference, Path},
|
expression_tree::{Expression, NamedReference, Path},
|
||||||
object_tree::Component,
|
object_tree::Component,
|
||||||
|
@ -69,9 +69,11 @@ pub struct LayoutItem {
|
||||||
impl LayoutItem {
|
impl LayoutItem {
|
||||||
pub fn rect(&self) -> Cow<LayoutRect> {
|
pub fn rect(&self) -> Cow<LayoutRect> {
|
||||||
if let Some(e) = &self.element {
|
if let Some(e) = &self.element {
|
||||||
let p = |name: &str| {
|
let p = |unresolved_name: &str| {
|
||||||
if e.borrow().lookup_property(name) == Type::Length {
|
let PropertyLookupResult { resolved_name, property_type } =
|
||||||
Some(NamedReference::new(e, name))
|
e.borrow().lookup_property(unresolved_name);
|
||||||
|
if property_type == Type::Length {
|
||||||
|
Some(NamedReference::new(e, resolved_name.as_ref()))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,11 +81,15 @@ pub fn load_builtins(register: &mut TypeRegister) {
|
||||||
let mut n = NativeClass::new_with_properties(
|
let mut n = NativeClass::new_with_properties(
|
||||||
&id,
|
&id,
|
||||||
e.PropertyDeclaration()
|
e.PropertyDeclaration()
|
||||||
.map(|p| {
|
.flat_map(|p| {
|
||||||
(
|
if p.TwoWayBinding().is_some() {
|
||||||
|
None // aliases are handled further down
|
||||||
|
} else {
|
||||||
|
Some((
|
||||||
identifier_text(&p.DeclaredIdentifier()).unwrap(),
|
identifier_text(&p.DeclaredIdentifier()).unwrap(),
|
||||||
object_tree::type_from_node(p.Type(), *diag.borrow_mut(), register),
|
object_tree::type_from_node(p.Type(), *diag.borrow_mut(), register),
|
||||||
)
|
))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.chain(e.CallbackDeclaration().map(|s| {
|
.chain(e.CallbackDeclaration().map(|s| {
|
||||||
(
|
(
|
||||||
|
@ -108,6 +112,21 @@ pub fn load_builtins(register: &mut TypeRegister) {
|
||||||
)
|
)
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
|
n.deprecated_aliases = e
|
||||||
|
.PropertyDeclaration()
|
||||||
|
.flat_map(|p| {
|
||||||
|
if let Some(twb) = p.TwoWayBinding() {
|
||||||
|
let alias_name = identifier_text(&p.DeclaredIdentifier()).unwrap();
|
||||||
|
let alias_target = identifier_text(&twb.Expression().QualifiedName().expect(
|
||||||
|
"internal error: built-in aliases can only be declared within the type",
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
Some((alias_name, alias_target))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
n.cpp_type = parse_annotation("cpp_type", &e.node).map(|x| x.unwrap());
|
n.cpp_type = parse_annotation("cpp_type", &e.node).map(|x| x.unwrap());
|
||||||
n.rust_type_constructor =
|
n.rust_type_constructor =
|
||||||
parse_annotation("rust_type_constructor", &e.node).map(|x| x.unwrap());
|
parse_annotation("rust_type_constructor", &e.node).map(|x| x.unwrap());
|
||||||
|
|
|
@ -14,12 +14,13 @@ LICENSE END */
|
||||||
use crate::diagnostics::{FileDiagnostics, Spanned, SpannedWithSourceFile};
|
use crate::diagnostics::{FileDiagnostics, Spanned, SpannedWithSourceFile};
|
||||||
use crate::expression_tree::{self, Unit};
|
use crate::expression_tree::{self, Unit};
|
||||||
use crate::expression_tree::{Expression, ExpressionSpanned, NamedReference};
|
use crate::expression_tree::{Expression, ExpressionSpanned, NamedReference};
|
||||||
|
use crate::langtype::PropertyLookupResult;
|
||||||
use crate::langtype::{NativeClass, Type};
|
use crate::langtype::{NativeClass, Type};
|
||||||
use crate::parser::{identifier_text, syntax_nodes, SyntaxKind, SyntaxNodeWithSourceFile};
|
use crate::parser::{identifier_text, syntax_nodes, SyntaxKind, SyntaxNodeWithSourceFile};
|
||||||
use crate::typeregister::TypeRegister;
|
use crate::typeregister::TypeRegister;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
|
use std::{borrow::Cow, cell::RefCell};
|
||||||
|
|
||||||
/// The full document (a complete file)
|
/// The full document (a complete file)
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
|
@ -418,9 +419,13 @@ impl Element {
|
||||||
for prop_decl in node.PropertyDeclaration() {
|
for prop_decl in node.PropertyDeclaration() {
|
||||||
let type_node = prop_decl.Type();
|
let type_node = prop_decl.Type();
|
||||||
let prop_type = type_from_node(type_node.clone(), diag, tr);
|
let prop_type = type_from_node(type_node.clone(), diag, tr);
|
||||||
let prop_name = identifier_text(&prop_decl.DeclaredIdentifier()).unwrap();
|
let unresolved_prop_name = identifier_text(&prop_decl.DeclaredIdentifier()).unwrap();
|
||||||
|
let PropertyLookupResult {
|
||||||
|
resolved_name: prop_name,
|
||||||
|
property_type: maybe_existing_prop_type,
|
||||||
|
} = r.lookup_property(&unresolved_prop_name);
|
||||||
|
|
||||||
if !matches!(r.lookup_property(&prop_name), Type::Invalid) {
|
if !matches!(maybe_existing_prop_type, Type::Invalid) {
|
||||||
diag.push_error(
|
diag.push_error(
|
||||||
format!("Cannot override property '{}'", prop_name),
|
format!("Cannot override property '{}'", prop_name),
|
||||||
&prop_decl.DeclaredIdentifier().child_token(SyntaxKind::Identifier).unwrap(),
|
&prop_decl.DeclaredIdentifier().child_token(SyntaxKind::Identifier).unwrap(),
|
||||||
|
@ -435,7 +440,7 @@ impl Element {
|
||||||
}
|
}
|
||||||
|
|
||||||
r.property_declarations.insert(
|
r.property_declarations.insert(
|
||||||
prop_name.clone(),
|
prop_name.to_string(),
|
||||||
PropertyDeclaration {
|
PropertyDeclaration {
|
||||||
property_type: prop_type,
|
property_type: prop_type,
|
||||||
type_node: Some(type_node.into()),
|
type_node: Some(type_node.into()),
|
||||||
|
@ -445,7 +450,7 @@ impl Element {
|
||||||
|
|
||||||
if let Some(csn) = prop_decl.BindingExpression() {
|
if let Some(csn) = prop_decl.BindingExpression() {
|
||||||
if r.bindings
|
if r.bindings
|
||||||
.insert(prop_name.clone(), ExpressionSpanned::new_uncompiled(csn.into()))
|
.insert(prop_name.to_string(), ExpressionSpanned::new_uncompiled(csn.into()))
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
diag.push_error(
|
diag.push_error(
|
||||||
|
@ -456,7 +461,7 @@ impl Element {
|
||||||
}
|
}
|
||||||
if let Some(csn) = prop_decl.TwoWayBinding() {
|
if let Some(csn) = prop_decl.TwoWayBinding() {
|
||||||
if r.bindings
|
if r.bindings
|
||||||
.insert(prop_name, ExpressionSpanned::new_uncompiled(csn.into()))
|
.insert(prop_name.into(), ExpressionSpanned::new_uncompiled(csn.into()))
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
diag.push_error(
|
diag.push_error(
|
||||||
|
@ -504,18 +509,19 @@ impl Element {
|
||||||
}
|
}
|
||||||
|
|
||||||
for con_node in node.CallbackConnection() {
|
for con_node in node.CallbackConnection() {
|
||||||
let name = match identifier_text(&con_node) {
|
let unresolved_name = match identifier_text(&con_node) {
|
||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
let prop_type = r.lookup_property(&name);
|
let PropertyLookupResult { resolved_name, property_type } =
|
||||||
if let Type::Callback { args, .. } = prop_type {
|
r.lookup_property(&unresolved_name);
|
||||||
|
if let Type::Callback { args, .. } = property_type {
|
||||||
let num_arg = con_node.DeclaredIdentifier().count();
|
let num_arg = con_node.DeclaredIdentifier().count();
|
||||||
if num_arg > args.len() {
|
if num_arg > args.len() {
|
||||||
diag.push_error(
|
diag.push_error(
|
||||||
format!(
|
format!(
|
||||||
"'{}' only has {} arguments, but {} were provided",
|
"'{}' only has {} arguments, but {} were provided",
|
||||||
name,
|
unresolved_name,
|
||||||
args.len(),
|
args.len(),
|
||||||
num_arg
|
num_arg
|
||||||
),
|
),
|
||||||
|
@ -523,7 +529,10 @@ impl Element {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if r.bindings
|
if r.bindings
|
||||||
.insert(name, ExpressionSpanned::new_uncompiled(con_node.clone().into()))
|
.insert(
|
||||||
|
resolved_name.into_owned(),
|
||||||
|
ExpressionSpanned::new_uncompiled(con_node.clone().into()),
|
||||||
|
)
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
diag.push_error(
|
diag.push_error(
|
||||||
|
@ -533,7 +542,7 @@ impl Element {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
diag.push_error(
|
diag.push_error(
|
||||||
format!("'{}' is not a callback{}", name, name_for_looup_errors),
|
format!("'{}' is not a callback{}", unresolved_name, name_for_looup_errors),
|
||||||
&con_node.child_token(SyntaxKind::Identifier).unwrap(),
|
&con_node.child_token(SyntaxKind::Identifier).unwrap(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -548,17 +557,21 @@ impl Element {
|
||||||
};
|
};
|
||||||
for prop_name_token in anim.QualifiedName() {
|
for prop_name_token in anim.QualifiedName() {
|
||||||
match QualifiedTypeName::from_node(prop_name_token.clone()).members.as_slice() {
|
match QualifiedTypeName::from_node(prop_name_token.clone()).members.as_slice() {
|
||||||
[prop_name] => {
|
[unresolved_prop_name] => {
|
||||||
let prop_type = r.lookup_property(&prop_name);
|
let PropertyLookupResult { resolved_name, property_type } =
|
||||||
|
r.lookup_property(&unresolved_prop_name);
|
||||||
if let Some(anim_element) = animation_element_from_node(
|
if let Some(anim_element) = animation_element_from_node(
|
||||||
&anim,
|
&anim,
|
||||||
&prop_name_token,
|
&prop_name_token,
|
||||||
prop_type,
|
property_type,
|
||||||
diag,
|
diag,
|
||||||
tr,
|
tr,
|
||||||
) {
|
) {
|
||||||
if r.property_animations
|
if r.property_animations
|
||||||
.insert(prop_name.clone(), PropertyAnimation::Static(anim_element))
|
.insert(
|
||||||
|
resolved_name.to_string(),
|
||||||
|
PropertyAnimation::Static(anim_element),
|
||||||
|
)
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
diag.push_error("Duplicated animation".into(), &prop_name_token)
|
diag.push_error("Duplicated animation".into(), &prop_name_token)
|
||||||
|
@ -750,13 +763,14 @@ impl Element {
|
||||||
e
|
e
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the type of a property in this element or its base
|
/// Return the type of a property in this element or its base, along with the final name, in case
|
||||||
pub fn lookup_property(&self, name: &str) -> Type {
|
/// the provided name points towards a property alias. Type::Invalid is returned if the property does
|
||||||
self.property_declarations
|
/// not exist.
|
||||||
.get(name)
|
pub fn lookup_property<'a>(&self, name: &'a str) -> PropertyLookupResult<'a> {
|
||||||
.cloned()
|
self.property_declarations.get(name).cloned().map(|decl| decl.property_type).map_or_else(
|
||||||
.map(|decl| decl.property_type)
|
|| self.base_type.lookup_property(name),
|
||||||
.unwrap_or_else(|| self.base_type.lookup_property(name))
|
|property_type| PropertyLookupResult { resolved_name: name.into(), property_type },
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the Span of this element in the AST for error reporting
|
/// Return the Span of this element in the AST for error reporting
|
||||||
|
@ -773,26 +787,31 @@ impl Element {
|
||||||
diag: &mut FileDiagnostics,
|
diag: &mut FileDiagnostics,
|
||||||
) {
|
) {
|
||||||
for (name_token, b) in bindings {
|
for (name_token, b) in bindings {
|
||||||
let name = crate::parser::normalize_identifier(name_token.text());
|
let unresolved_name = crate::parser::normalize_identifier(name_token.text());
|
||||||
let prop_type = self.lookup_property(&name);
|
let PropertyLookupResult { resolved_name, property_type } =
|
||||||
if !prop_type.is_property_type() {
|
self.lookup_property(&unresolved_name);
|
||||||
|
if !property_type.is_property_type() {
|
||||||
diag.push_error(
|
diag.push_error(
|
||||||
match prop_type {
|
match property_type {
|
||||||
Type::Invalid => {
|
Type::Invalid => {
|
||||||
format!("Unknown property {}{}", name, name_for_lookup_error)
|
format!("Unknown property {}{}", unresolved_name, name_for_lookup_error)
|
||||||
}
|
}
|
||||||
Type::Callback { .. } => {
|
Type::Callback { .. } => {
|
||||||
format!("'{}' is a callback. Use `=>` to connect", name)
|
format!("'{}' is a callback. Use `=>` to connect", unresolved_name)
|
||||||
}
|
}
|
||||||
_ => format!(
|
_ => format!(
|
||||||
"Cannot assign to {}{} because it does not have a valid property type.",
|
"Cannot assign to {}{} because it does not have a valid property type.",
|
||||||
name, name_for_lookup_error
|
unresolved_name, name_for_lookup_error
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
&name_token,
|
&name_token,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if self.bindings.insert(name, ExpressionSpanned::new_uncompiled(b)).is_some() {
|
if self
|
||||||
|
.bindings
|
||||||
|
.insert(resolved_name.to_string(), ExpressionSpanned::new_uncompiled(b))
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
diag.push_error("Duplicated property binding".into(), &name_token);
|
diag.push_error("Duplicated property binding".into(), &name_token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -917,25 +936,34 @@ fn lookup_property_from_qualified_name(
|
||||||
) -> (NamedReference, Type) {
|
) -> (NamedReference, Type) {
|
||||||
let qualname = QualifiedTypeName::from_node(node.clone());
|
let qualname = QualifiedTypeName::from_node(node.clone());
|
||||||
match qualname.members.as_slice() {
|
match qualname.members.as_slice() {
|
||||||
[prop_name] => {
|
[unresolved_prop_name] => {
|
||||||
let ty = r.borrow().lookup_property(prop_name.as_ref());
|
let PropertyLookupResult { resolved_name, property_type } =
|
||||||
if !ty.is_property_type() {
|
r.borrow().lookup_property(unresolved_prop_name.as_ref());
|
||||||
|
if !property_type.is_property_type() {
|
||||||
diag.push_error(format!("'{}' is not a valid property", qualname), &node);
|
diag.push_error(format!("'{}' is not a valid property", qualname), &node);
|
||||||
}
|
}
|
||||||
(NamedReference { element: Rc::downgrade(&r), name: prop_name.clone() }, ty)
|
(
|
||||||
|
NamedReference { element: Rc::downgrade(&r), name: resolved_name.to_string() },
|
||||||
|
property_type,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
[elem_id, prop_name] => {
|
[elem_id, unresolved_prop_name] => {
|
||||||
let (element, ty) = if let Some(element) = find_element_by_id(&r, elem_id.as_ref()) {
|
let (element, name, ty) =
|
||||||
let ty = element.borrow().lookup_property(prop_name.as_ref());
|
if let Some(element) = find_element_by_id(&r, elem_id.as_ref()) {
|
||||||
if !ty.is_property_type() {
|
let PropertyLookupResult { resolved_name, property_type } =
|
||||||
diag.push_error(format!("'{}' not found in '{}'", prop_name, elem_id), &node);
|
element.borrow().lookup_property(unresolved_prop_name.as_ref());
|
||||||
|
if !property_type.is_property_type() {
|
||||||
|
diag.push_error(
|
||||||
|
format!("'{}' not found in '{}'", unresolved_prop_name, elem_id),
|
||||||
|
&node,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
(Rc::downgrade(&element), ty)
|
(Rc::downgrade(&element), resolved_name, property_type)
|
||||||
} else {
|
} else {
|
||||||
diag.push_error(format!("'{}' is not a valid element id", elem_id), &node);
|
diag.push_error(format!("'{}' is not a valid element id", elem_id), &node);
|
||||||
(Weak::new(), Type::Invalid)
|
(Weak::new(), Cow::Borrowed(unresolved_prop_name.as_ref()), Type::Invalid)
|
||||||
};
|
};
|
||||||
(NamedReference { element, name: prop_name.clone() }, ty)
|
(NamedReference { element, name: name.to_string() }, ty)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
diag.push_error(format!("'{}' is not a valid property", qualname), &node);
|
diag.push_error(format!("'{}' is not a valid property", qualname), &node);
|
||||||
|
@ -1049,7 +1077,7 @@ pub fn visit_element_expressions(
|
||||||
) {
|
) {
|
||||||
let mut bindings = std::mem::take(&mut elem.borrow_mut().bindings);
|
let mut bindings = std::mem::take(&mut elem.borrow_mut().bindings);
|
||||||
for (name, expr) in &mut bindings {
|
for (name, expr) in &mut bindings {
|
||||||
vis(expr, Some(name.as_str()), &|| elem.borrow().lookup_property(name));
|
vis(expr, Some(name.as_str()), &|| elem.borrow().lookup_property(name).property_type);
|
||||||
}
|
}
|
||||||
elem.borrow_mut().bindings = bindings;
|
elem.borrow_mut().bindings = bindings;
|
||||||
}
|
}
|
||||||
|
@ -1068,7 +1096,12 @@ pub fn visit_element_expressions(
|
||||||
}
|
}
|
||||||
for (ne, e) in &mut s.property_changes {
|
for (ne, e) in &mut s.property_changes {
|
||||||
vis(e, Some(ne.name.as_ref()), &|| {
|
vis(e, Some(ne.name.as_ref()), &|| {
|
||||||
ne.element.upgrade().unwrap().borrow().lookup_property(ne.name.as_ref())
|
ne.element
|
||||||
|
.upgrade()
|
||||||
|
.unwrap()
|
||||||
|
.borrow()
|
||||||
|
.lookup_property(ne.name.as_ref())
|
||||||
|
.property_type
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,13 @@ LICENSE END */
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::expression_tree::{BuiltinFunction, Expression, NamedReference};
|
|
||||||
use crate::langtype::DefaultSizeBinding;
|
use crate::langtype::DefaultSizeBinding;
|
||||||
use crate::langtype::Type;
|
use crate::langtype::Type;
|
||||||
use crate::object_tree::{Component, ElementRc};
|
use crate::object_tree::{Component, ElementRc};
|
||||||
|
use crate::{
|
||||||
|
expression_tree::{BuiltinFunction, Expression, NamedReference},
|
||||||
|
langtype::PropertyLookupResult,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn default_geometry(root_component: &Rc<Component>) {
|
pub fn default_geometry(root_component: &Rc<Component>) {
|
||||||
crate::object_tree::recurse_elem_including_sub_components(
|
crate::object_tree::recurse_elem_including_sub_components(
|
||||||
|
@ -44,11 +47,14 @@ pub fn default_geometry(root_component: &Rc<Component>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_default_100(elem: &ElementRc, parent_element: &ElementRc, property: &str) {
|
fn make_default_100(elem: &ElementRc, parent_element: &ElementRc, property: &str) {
|
||||||
if parent_element.borrow().lookup_property(property) != Type::Length {
|
let PropertyLookupResult { resolved_name, property_type } =
|
||||||
|
parent_element.borrow().lookup_property(property);
|
||||||
|
if property_type != Type::Length {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
elem.borrow_mut().bindings.entry(property.into()).or_insert_with(|| {
|
elem.borrow_mut().bindings.entry(resolved_name.to_string()).or_insert_with(|| {
|
||||||
Expression::PropertyReference(NamedReference::new(parent_element, property)).into()
|
Expression::PropertyReference(NamedReference::new(parent_element, resolved_name.as_ref()))
|
||||||
|
.into()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -149,7 +149,9 @@ fn lower_transitions_in_element(
|
||||||
/// Returns a suitable unique name for the "state" property
|
/// Returns a suitable unique name for the "state" property
|
||||||
fn compute_state_property_name(root_element: &ElementRc) -> String {
|
fn compute_state_property_name(root_element: &ElementRc) -> String {
|
||||||
let mut property_name = "state".to_owned();
|
let mut property_name = "state".to_owned();
|
||||||
while root_element.borrow().lookup_property(property_name.as_ref()) != Type::Invalid {
|
while root_element.borrow().lookup_property(property_name.as_ref()).property_type
|
||||||
|
!= Type::Invalid
|
||||||
|
{
|
||||||
property_name += "_";
|
property_name += "_";
|
||||||
}
|
}
|
||||||
property_name
|
property_name
|
||||||
|
@ -168,5 +170,5 @@ fn expression_for_property(element: &ElementRc, name: &str) -> Expression {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Expression::default_value_for_type(&element.borrow().lookup_property(name))
|
Expression::default_value_for_type(&element.borrow().lookup_property(name).property_type)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@ LICENSE END */
|
||||||
//!
|
//!
|
||||||
//! Most of the code for the resolving actualy lies in the expression_tree module
|
//! Most of the code for the resolving actualy lies in the expression_tree module
|
||||||
|
|
||||||
use crate::diagnostics::{BuildDiagnostics, SpannedWithSourceFile};
|
|
||||||
use crate::expression_tree::*;
|
use crate::expression_tree::*;
|
||||||
use crate::langtype::Type;
|
use crate::langtype::Type;
|
||||||
use crate::object_tree::*;
|
use crate::object_tree::*;
|
||||||
|
@ -22,6 +21,10 @@ use crate::parser::{
|
||||||
identifier_text, syntax_nodes, NodeOrTokenWithSourceFile, SyntaxKind, SyntaxNodeWithSourceFile,
|
identifier_text, syntax_nodes, NodeOrTokenWithSourceFile, SyntaxKind, SyntaxNodeWithSourceFile,
|
||||||
};
|
};
|
||||||
use crate::typeregister::TypeRegister;
|
use crate::typeregister::TypeRegister;
|
||||||
|
use crate::{
|
||||||
|
diagnostics::{BuildDiagnostics, SpannedWithSourceFile},
|
||||||
|
langtype::PropertyLookupResult,
|
||||||
|
};
|
||||||
use std::{collections::HashMap, rc::Rc};
|
use std::{collections::HashMap, rc::Rc};
|
||||||
|
|
||||||
/// This represeresent a scope for the Component, where Component is the repeated component, but
|
/// This represeresent a scope for the Component, where Component is the repeated component, but
|
||||||
|
@ -235,8 +238,9 @@ fn attempt_percent_conversion(
|
||||||
|
|
||||||
let mut parent = ctx.component_scope.last().and_then(find_parent_element);
|
let mut parent = ctx.component_scope.last().and_then(find_parent_element);
|
||||||
while let Some(p) = parent {
|
while let Some(p) = parent {
|
||||||
let ty = p.borrow().lookup_property(property_name);
|
let PropertyLookupResult { resolved_name, property_type } =
|
||||||
if ty == Type::Length {
|
p.borrow().lookup_property(property_name);
|
||||||
|
if property_type == Type::Length {
|
||||||
return Expression::BinaryExpression {
|
return Expression::BinaryExpression {
|
||||||
lhs: Box::new(Expression::BinaryExpression {
|
lhs: Box::new(Expression::BinaryExpression {
|
||||||
lhs: Box::new(e),
|
lhs: Box::new(e),
|
||||||
|
@ -245,7 +249,7 @@ fn attempt_percent_conversion(
|
||||||
}),
|
}),
|
||||||
rhs: Box::new(Expression::PropertyReference(NamedReference {
|
rhs: Box::new(Expression::PropertyReference(NamedReference {
|
||||||
element: Rc::downgrade(&p),
|
element: Rc::downgrade(&p),
|
||||||
name: property_name.to_string(),
|
name: resolved_name.to_string(),
|
||||||
})),
|
})),
|
||||||
op: '*',
|
op: '*',
|
||||||
};
|
};
|
||||||
|
@ -577,22 +581,23 @@ impl Expression {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let property = elem.borrow().lookup_property(&first_str);
|
let PropertyLookupResult { resolved_name, property_type } =
|
||||||
if property.is_property_type() {
|
elem.borrow().lookup_property(&first_str);
|
||||||
|
if property_type.is_property_type() {
|
||||||
let prop = Self::PropertyReference(NamedReference {
|
let prop = Self::PropertyReference(NamedReference {
|
||||||
element: Rc::downgrade(&elem),
|
element: Rc::downgrade(&elem),
|
||||||
name: first_str,
|
name: resolved_name.to_string(),
|
||||||
});
|
});
|
||||||
return maybe_lookup_object(prop, it, ctx);
|
return maybe_lookup_object(prop, it, ctx);
|
||||||
} else if matches!(property, Type::Callback{..}) {
|
} else if matches!(property_type, Type::Callback{..}) {
|
||||||
if let Some(x) = it.next() {
|
if let Some(x) = it.next() {
|
||||||
ctx.diag.push_error("Cannot access fields of callback".into(), &x)
|
ctx.diag.push_error("Cannot access fields of callback".into(), &x)
|
||||||
}
|
}
|
||||||
return Self::CallbackReference(NamedReference {
|
return Self::CallbackReference(NamedReference {
|
||||||
element: Rc::downgrade(&elem),
|
element: Rc::downgrade(&elem),
|
||||||
name: first_str,
|
name: resolved_name.to_string(),
|
||||||
});
|
});
|
||||||
} else if property.is_object_type() {
|
} else if property_type.is_object_type() {
|
||||||
todo!("Continue looking up");
|
todo!("Continue looking up");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -681,8 +686,9 @@ impl Expression {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let property = elem.borrow().lookup_property(&first_str);
|
let PropertyLookupResult { resolved_name: _, property_type } =
|
||||||
if property.is_property_type() {
|
elem.borrow().lookup_property(&first_str);
|
||||||
|
if property_type.is_property_type() {
|
||||||
report_minus_error(ctx);
|
report_minus_error(ctx);
|
||||||
return Expression::Invalid;
|
return Expression::Invalid;
|
||||||
}
|
}
|
||||||
|
@ -1128,23 +1134,24 @@ fn continue_lookup_within_element(
|
||||||
};
|
};
|
||||||
let prop_name = crate::parser::normalize_identifier(second.text());
|
let prop_name = crate::parser::normalize_identifier(second.text());
|
||||||
|
|
||||||
let p = elem.borrow().lookup_property(&prop_name);
|
let PropertyLookupResult { resolved_name, property_type } =
|
||||||
if p.is_property_type() {
|
elem.borrow().lookup_property(&prop_name);
|
||||||
|
if property_type.is_property_type() {
|
||||||
let prop = Expression::PropertyReference(NamedReference {
|
let prop = Expression::PropertyReference(NamedReference {
|
||||||
element: Rc::downgrade(elem),
|
element: Rc::downgrade(elem),
|
||||||
name: prop_name,
|
name: resolved_name.to_string(),
|
||||||
});
|
});
|
||||||
maybe_lookup_object(prop, it, ctx)
|
maybe_lookup_object(prop, it, ctx)
|
||||||
} else if matches!(p, Type::Callback{..}) {
|
} else if matches!(property_type, Type::Callback{..}) {
|
||||||
if let Some(x) = it.next() {
|
if let Some(x) = it.next() {
|
||||||
ctx.diag.push_error("Cannot access fields of callback".into(), &x)
|
ctx.diag.push_error("Cannot access fields of callback".into(), &x)
|
||||||
}
|
}
|
||||||
Expression::CallbackReference(NamedReference {
|
Expression::CallbackReference(NamedReference {
|
||||||
element: Rc::downgrade(elem),
|
element: Rc::downgrade(elem),
|
||||||
name: prop_name,
|
name: resolved_name.to_string(),
|
||||||
})
|
})
|
||||||
} else if matches!(p, Type::Function{..}) {
|
} else if matches!(property_type, Type::Function{..}) {
|
||||||
let member = elem.borrow().base_type.lookup_member_function(&prop_name);
|
let member = elem.borrow().base_type.lookup_member_function(&resolved_name);
|
||||||
Expression::MemberFunction {
|
Expression::MemberFunction {
|
||||||
base: Box::new(Expression::ElementReference(Rc::downgrade(elem))),
|
base: Box::new(Expression::ElementReference(Rc::downgrade(elem))),
|
||||||
base_node: node.into(),
|
base_node: node.into(),
|
||||||
|
@ -1169,7 +1176,9 @@ fn continue_lookup_within_element(
|
||||||
};
|
};
|
||||||
if let Some(minus_pos) = second.text().find('-') {
|
if let Some(minus_pos) = second.text().find('-') {
|
||||||
// Attempt to recover if the user wanted to write "-"
|
// Attempt to recover if the user wanted to write "-"
|
||||||
if elem.borrow().lookup_property(&second.text()[0..minus_pos]) != Type::Invalid {
|
if elem.borrow().lookup_property(&second.text()[0..minus_pos]).property_type
|
||||||
|
!= Type::Invalid
|
||||||
|
{
|
||||||
err(" Use space before the '-' if you meant a substraction.");
|
err(" Use space before the '-' if you meant a substraction.");
|
||||||
return Expression::Invalid;
|
return Expression::Invalid;
|
||||||
}
|
}
|
||||||
|
@ -1213,15 +1222,16 @@ fn maybe_lookup_object(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::Component(c) => {
|
Type::Component(c) => {
|
||||||
let prop_ty = c.root_element.borrow().lookup_property(next_str.as_str());
|
let PropertyLookupResult { resolved_name, property_type } =
|
||||||
if prop_ty != Type::Invalid {
|
c.root_element.borrow().lookup_property(next_str.as_str());
|
||||||
|
if property_type != Type::Invalid {
|
||||||
base = Expression::ObjectAccess {
|
base = Expression::ObjectAccess {
|
||||||
base: Box::new(std::mem::replace(&mut base, Expression::Invalid)),
|
base: Box::new(std::mem::replace(&mut base, Expression::Invalid)),
|
||||||
name: next.to_string(),
|
name: resolved_name.to_string(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return error_or_try_minus(ctx, next, |x| {
|
return error_or_try_minus(ctx, next, |x| {
|
||||||
c.root_element.borrow().lookup_property(x) != Type::Invalid
|
c.root_element.borrow().lookup_property(x).property_type != Type::Invalid
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ TestCase := Rectangle {
|
||||||
animate * { }
|
animate * { }
|
||||||
}
|
}
|
||||||
in checked: {
|
in checked: {
|
||||||
// ^error{The property 'color' cannot have transition because it already has an animation}
|
// ^error{The property 'background' cannot have transition because it already has an animation}
|
||||||
animate color { }
|
animate color { }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -157,7 +157,7 @@ impl ItemWeak {
|
||||||
#[pin]
|
#[pin]
|
||||||
/// The implementation of the `Rectangle` element
|
/// The implementation of the `Rectangle` element
|
||||||
pub struct Rectangle {
|
pub struct Rectangle {
|
||||||
pub color: Property<Color>,
|
pub background: Property<Color>,
|
||||||
pub x: Property<f32>,
|
pub x: Property<f32>,
|
||||||
pub y: Property<f32>,
|
pub y: Property<f32>,
|
||||||
pub width: Property<f32>,
|
pub width: Property<f32>,
|
||||||
|
@ -218,7 +218,7 @@ ItemVTable_static! {
|
||||||
#[pin]
|
#[pin]
|
||||||
/// The implementation of the `BorderRectangle` element
|
/// The implementation of the `BorderRectangle` element
|
||||||
pub struct BorderRectangle {
|
pub struct BorderRectangle {
|
||||||
pub color: Property<Color>,
|
pub background: Property<Color>,
|
||||||
pub x: Property<f32>,
|
pub x: Property<f32>,
|
||||||
pub y: Property<f32>,
|
pub y: Property<f32>,
|
||||||
pub width: Property<f32>,
|
pub width: Property<f32>,
|
||||||
|
|
|
@ -14,10 +14,10 @@ use core::ptr::NonNull;
|
||||||
use dynamic_type::{Instance, InstanceBox};
|
use dynamic_type::{Instance, InstanceBox};
|
||||||
use expression_tree::NamedReference;
|
use expression_tree::NamedReference;
|
||||||
use object_tree::{Element, ElementRc};
|
use object_tree::{Element, ElementRc};
|
||||||
use sixtyfps_compilerlib::expression_tree::Expression;
|
|
||||||
use sixtyfps_compilerlib::langtype::Type;
|
use sixtyfps_compilerlib::langtype::Type;
|
||||||
use sixtyfps_compilerlib::layout::{Layout, LayoutConstraints, LayoutItem, PathLayout};
|
use sixtyfps_compilerlib::layout::{Layout, LayoutConstraints, LayoutItem, PathLayout};
|
||||||
use sixtyfps_compilerlib::*;
|
use sixtyfps_compilerlib::*;
|
||||||
|
use sixtyfps_compilerlib::{expression_tree::Expression, langtype::PropertyLookupResult};
|
||||||
use sixtyfps_corelib::component::{Component, ComponentRefPin, ComponentVTable};
|
use sixtyfps_corelib::component::{Component, ComponentRefPin, ComponentVTable};
|
||||||
use sixtyfps_corelib::graphics::{Rect, Resource};
|
use sixtyfps_corelib::graphics::{Rect, Resource};
|
||||||
use sixtyfps_corelib::item_tree::{
|
use sixtyfps_corelib::item_tree::{
|
||||||
|
@ -168,8 +168,10 @@ impl RepeatedComponent for ErasedComponentBox {
|
||||||
|
|
||||||
let root_item = &s.component_type.original.root_element.clone();
|
let root_item = &s.component_type.original.root_element.clone();
|
||||||
let get_prop = |name: &str| {
|
let get_prop = |name: &str| {
|
||||||
if root_item.borrow().lookup_property(name) == Type::Length {
|
let PropertyLookupResult { resolved_name, property_type } =
|
||||||
let nr = NamedReference::new(root_item, name);
|
root_item.borrow().lookup_property(name);
|
||||||
|
if property_type == Type::Length {
|
||||||
|
let nr = NamedReference::new(root_item, resolved_name.as_ref());
|
||||||
let p = get_property_ptr(&nr, s.borrow_instance());
|
let p = get_property_ptr(&nr, s.borrow_instance());
|
||||||
// Safety: assuming get_property_ptr returned a valid pointer,
|
// Safety: assuming get_property_ptr returned a valid pointer,
|
||||||
// we know that `Type::Length` is a property of type `f32`
|
// we know that `Type::Length` is a property of type `f32`
|
||||||
|
@ -820,9 +822,10 @@ pub fn instantiate<'id>(
|
||||||
unsafe {
|
unsafe {
|
||||||
let item = item_within_component.item_from_component(instance_ref.as_ptr());
|
let item = item_within_component.item_from_component(instance_ref.as_ptr());
|
||||||
let elem = item_within_component.elem.borrow();
|
let elem = item_within_component.elem.borrow();
|
||||||
for (prop, expr) in &elem.bindings {
|
for (unresolved_prop_name, expr) in &elem.bindings {
|
||||||
let ty = elem.lookup_property(prop.as_str());
|
let PropertyLookupResult { resolved_name, property_type } =
|
||||||
if let Type::Callback { .. } = ty {
|
elem.lookup_property(unresolved_prop_name.as_str());
|
||||||
|
if let Type::Callback { .. } = property_type {
|
||||||
let expr = expr.clone();
|
let expr = expr.clone();
|
||||||
let component_type = component_type.clone();
|
let component_type = component_type.clone();
|
||||||
let instance = component_box.instance.as_ptr();
|
let instance = component_box.instance.as_ptr();
|
||||||
|
@ -830,7 +833,8 @@ pub fn instantiate<'id>(
|
||||||
NonNull::from(&component_type.ct).cast(),
|
NonNull::from(&component_type.ct).cast(),
|
||||||
instance.cast(),
|
instance.cast(),
|
||||||
));
|
));
|
||||||
if let Some(callback) = item_within_component.rtti.callbacks.get(prop.as_str())
|
if let Some(callback) =
|
||||||
|
item_within_component.rtti.callbacks.get(resolved_name.as_ref())
|
||||||
{
|
{
|
||||||
callback.set_handler(
|
callback.set_handler(
|
||||||
item,
|
item,
|
||||||
|
@ -845,7 +849,7 @@ pub fn instantiate<'id>(
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
} else if let Some(callback_offset) =
|
} else if let Some(callback_offset) =
|
||||||
component_type.custom_callbacks.get(prop.as_str())
|
component_type.custom_callbacks.get(resolved_name.as_ref())
|
||||||
{
|
{
|
||||||
let callback = callback_offset.apply(instance_ref.as_ref());
|
let callback = callback_offset.apply(instance_ref.as_ref());
|
||||||
callback.set_handler(move |args| {
|
callback.set_handler(move |args| {
|
||||||
|
@ -857,13 +861,14 @@ pub fn instantiate<'id>(
|
||||||
eval::eval_expression(&expr, &mut local_context)
|
eval::eval_expression(&expr, &mut local_context)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
panic!("unkown callback {}", prop)
|
panic!("unkown callback {}", unresolved_prop_name)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let Some(prop_rtti) =
|
if let Some(prop_rtti) =
|
||||||
item_within_component.rtti.properties.get(prop.as_str())
|
item_within_component.rtti.properties.get(resolved_name.as_ref())
|
||||||
{
|
{
|
||||||
let maybe_animation = animation_for_property(instance_ref, &elem, prop);
|
let maybe_animation =
|
||||||
|
animation_for_property(instance_ref, &elem, resolved_name.as_ref());
|
||||||
let mut e = Some(&expr.expression);
|
let mut e = Some(&expr.expression);
|
||||||
while let Some(Expression::TwoWayBinding(nr, next)) = &e {
|
while let Some(Expression::TwoWayBinding(nr, next)) = &e {
|
||||||
// Safety: The compiler must have ensured that the properties exist and are of the same type
|
// Safety: The compiler must have ensured that the properties exist and are of the same type
|
||||||
|
@ -908,14 +913,14 @@ pub fn instantiate<'id>(
|
||||||
}
|
}
|
||||||
} else if let Some(PropertiesWithinComponent {
|
} else if let Some(PropertiesWithinComponent {
|
||||||
offset, prop: prop_info, ..
|
offset, prop: prop_info, ..
|
||||||
}) = component_type.custom_properties.get(prop.as_str())
|
}) = component_type.custom_properties.get(resolved_name.as_ref())
|
||||||
{
|
{
|
||||||
let c = Pin::new_unchecked(vtable::VRef::from_raw(
|
let c = Pin::new_unchecked(vtable::VRef::from_raw(
|
||||||
NonNull::from(&component_type.ct).cast(),
|
NonNull::from(&component_type.ct).cast(),
|
||||||
component_box.instance.as_ptr().cast(),
|
component_box.instance.as_ptr().cast(),
|
||||||
));
|
));
|
||||||
|
|
||||||
let is_state_info = match ty {
|
let is_state_info = match property_type {
|
||||||
Type::Object { name: Some(name), .. }
|
Type::Object { name: Some(name), .. }
|
||||||
if name.ends_with("::StateInfo") =>
|
if name.ends_with("::StateInfo") =>
|
||||||
{
|
{
|
||||||
|
@ -946,7 +951,7 @@ pub fn instantiate<'id>(
|
||||||
let maybe_animation = animation_for_property(
|
let maybe_animation = animation_for_property(
|
||||||
instance_ref,
|
instance_ref,
|
||||||
&component_type.original.root_element.borrow(),
|
&component_type.original.root_element.borrow(),
|
||||||
prop,
|
resolved_name.as_ref(),
|
||||||
);
|
);
|
||||||
let item = Pin::new_unchecked(&*instance_ref.as_ptr().add(*offset));
|
let item = Pin::new_unchecked(&*instance_ref.as_ptr().add(*offset));
|
||||||
|
|
||||||
|
@ -983,7 +988,7 @@ pub fn instantiate<'id>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("unkown property {}", prop);
|
panic!("unkown property {}", unresolved_prop_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -667,7 +667,7 @@ impl ItemRenderer for GLItemRenderer {
|
||||||
}
|
}
|
||||||
// TODO: cache path in item to avoid re-tesselation
|
// TODO: cache path in item to avoid re-tesselation
|
||||||
let mut path = rect_to_path(geometry);
|
let mut path = rect_to_path(geometry);
|
||||||
let paint = femtovg::Paint::color(rect.color().into());
|
let paint = femtovg::Paint::color(rect.background().into());
|
||||||
self.shared_data.canvas.borrow_mut().save_with(|canvas| {
|
self.shared_data.canvas.borrow_mut().save_with(|canvas| {
|
||||||
canvas.translate(pos.x, pos.y);
|
canvas.translate(pos.x, pos.y);
|
||||||
canvas.fill_path(&mut path, paint)
|
canvas.fill_path(&mut path, paint)
|
||||||
|
@ -705,7 +705,7 @@ impl ItemRenderer for GLItemRenderer {
|
||||||
path.rounded_rect(x, y, width, height, border_radius);
|
path.rounded_rect(x, y, width, height, border_radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
let fill_paint = femtovg::Paint::color(rect.color().into());
|
let fill_paint = femtovg::Paint::color(rect.background().into());
|
||||||
|
|
||||||
let mut border_paint = femtovg::Paint::color(rect.border_color().into());
|
let mut border_paint = femtovg::Paint::color(rect.border_color().into());
|
||||||
border_paint.set_line_width(border_width);
|
border_paint.set_line_width(border_width);
|
||||||
|
|
|
@ -226,7 +226,7 @@ struct QtItemRenderer<'a> {
|
||||||
impl ItemRenderer for QtItemRenderer<'_> {
|
impl ItemRenderer for QtItemRenderer<'_> {
|
||||||
fn draw_rectangle(&mut self, pos: Point, rect: Pin<&items::Rectangle>) {
|
fn draw_rectangle(&mut self, pos: Point, rect: Pin<&items::Rectangle>) {
|
||||||
let pos = qttypes::QPoint { x: pos.x as _, y: pos.y as _ };
|
let pos = qttypes::QPoint { x: pos.x as _, y: pos.y as _ };
|
||||||
let color: u32 = rect.color().as_argb_encoded();
|
let color: u32 = rect.background().as_argb_encoded();
|
||||||
let rect: qttypes::QRectF = get_geometry!(pos, items::Rectangle, rect);
|
let rect: qttypes::QRectF = get_geometry!(pos, items::Rectangle, rect);
|
||||||
let painter: &mut QPainter = &mut *self.painter;
|
let painter: &mut QPainter = &mut *self.painter;
|
||||||
cpp! { unsafe [painter as "QPainter*", color as "QRgb", rect as "QRectF"] {
|
cpp! { unsafe [painter as "QPainter*", color as "QRgb", rect as "QRectF"] {
|
||||||
|
@ -237,7 +237,7 @@ impl ItemRenderer for QtItemRenderer<'_> {
|
||||||
fn draw_border_rectangle(&mut self, pos: Point, rect: std::pin::Pin<&items::BorderRectangle>) {
|
fn draw_border_rectangle(&mut self, pos: Point, rect: std::pin::Pin<&items::BorderRectangle>) {
|
||||||
self.draw_rectangle_impl(
|
self.draw_rectangle_impl(
|
||||||
get_geometry!(pos, items::BorderRectangle, rect),
|
get_geometry!(pos, items::BorderRectangle, rect),
|
||||||
rect.color(),
|
rect.background(),
|
||||||
rect.border_color(),
|
rect.border_color(),
|
||||||
rect.border_width(),
|
rect.border_width(),
|
||||||
rect.border_radius(),
|
rect.border_radius(),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue