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:
Simon Hausmann 2021-02-02 09:07:01 +01:00
parent c479fd132d
commit 1f091cb1c0
16 changed files with 250 additions and 131 deletions

View file

@ -19,7 +19,8 @@ LICENSE END */
*/
Rectangle := _ {
property <color> color;
property <color> background;
property <color> color <=> background;
property <length> x;
property <length> y;
property <length> width;

View file

@ -420,13 +420,13 @@ impl Expression {
Expression::NumberLiteral(_, unit) => unit.ty(),
Expression::BoolLiteral(_) => Type::Bool,
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 }) => {
element.upgrade().unwrap().borrow().lookup_property(name)
element.upgrade().unwrap().borrow().lookup_property(name).property_type
}
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::MemberFunction { member, .. } => member.ty(),
@ -456,7 +456,7 @@ impl Expression {
Type::Object { fields, .. } => {
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,
},
Expression::Cast { to, .. } => to.clone(),

View file

@ -337,7 +337,7 @@ fn handle_property_binding(
let item = elem.borrow();
let component = item.enclosing_component.upgrade().unwrap();
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 {
let callback_accessor_prefix = if item.property_declarations.contains_key(prop_name) {
String::new()
@ -2059,14 +2059,14 @@ impl<'a> LayoutTreeItem<'a> {
let path_layout_item_data =
|elem: &ElementRc, elem_cpp: &str, component_cpp: &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)
} else {
"nullptr".to_owned()
}
};
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(
&elem,
n,

View file

@ -146,7 +146,7 @@ fn handle_property_binding(
init: &mut Vec<TokenStream>,
) {
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{..}) {
let tokens_for_expression = compile_expression(binding_expression, &component);
init.push(quote!(
@ -1774,7 +1774,7 @@ impl<'a> LayoutTreeItem<'a> {
let path_layout_item_data =
|elem: &ElementRc, elem_rs: TokenStream, component_rust: TokenStream| {
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);
quote! {Some(& #elem_rs.#n)}
} else {
@ -1782,7 +1782,7 @@ impl<'a> LayoutTreeItem<'a> {
}
};
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(
&elem,
n,

View file

@ -7,8 +7,10 @@
This file is also available under commercial licensing terms.
Please contact info@sixtyfps.io for more information.
LICENSE END */
use std::borrow::Cow;
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::object_tree::Component;
@ -193,18 +195,39 @@ impl Type {
!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 {
Type::Component(c) => c.root_element.borrow().lookup_property(name),
Type::Builtin(b) => b.properties.get(name).cloned().unwrap_or_else(|| {
if b.is_non_item_type {
Type::Invalid
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 {
Type::Invalid
} else {
crate::typeregister::reserved_property(resolved_name.as_ref())
}
});
PropertyLookupResult { resolved_name, property_type }
}
Type::Native(n) => {
let resolved_name = if let Some(alias_name) = n.lookup_alias(name.as_ref()) {
Cow::Owned(alias_name.to_string())
} else {
crate::typeregister::reserved_property(name)
}
}),
Type::Native(n) => n.lookup_property(name).unwrap_or_default(),
_ => Type::Invalid,
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 vtable_symbol: String,
pub properties: HashMap<String, Type>,
pub deprecated_aliases: HashMap<String, String>,
pub cpp_type: 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>) {
let mut distance = 0;
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);
}
pub struct PropertyLookupResult<'a> {
pub resolved_name: std::borrow::Cow<'a, str>,
pub property_type: Type,
}
#[derive(Debug, Clone)]
pub struct Enumeration {
pub name: String,

View file

@ -9,9 +9,9 @@
LICENSE END */
//! Datastructures used to represent layouts in the compiler
use crate::diagnostics::BuildDiagnostics;
use crate::langtype::Type;
use crate::object_tree::{ElementRc, PropertyDeclaration};
use crate::{diagnostics::BuildDiagnostics, langtype::PropertyLookupResult};
use crate::{
expression_tree::{Expression, NamedReference, Path},
object_tree::Component,
@ -69,9 +69,11 @@ pub struct LayoutItem {
impl LayoutItem {
pub fn rect(&self) -> Cow<LayoutRect> {
if let Some(e) = &self.element {
let p = |name: &str| {
if e.borrow().lookup_property(name) == Type::Length {
Some(NamedReference::new(e, name))
let p = |unresolved_name: &str| {
let PropertyLookupResult { resolved_name, property_type } =
e.borrow().lookup_property(unresolved_name);
if property_type == Type::Length {
Some(NamedReference::new(e, resolved_name.as_ref()))
} else {
None
}

View file

@ -81,11 +81,15 @@ pub fn load_builtins(register: &mut TypeRegister) {
let mut n = NativeClass::new_with_properties(
&id,
e.PropertyDeclaration()
.map(|p| {
(
identifier_text(&p.DeclaredIdentifier()).unwrap(),
object_tree::type_from_node(p.Type(), *diag.borrow_mut(), register),
)
.flat_map(|p| {
if p.TwoWayBinding().is_some() {
None // aliases are handled further down
} else {
Some((
identifier_text(&p.DeclaredIdentifier()).unwrap(),
object_tree::type_from_node(p.Type(), *diag.borrow_mut(), register),
))
}
})
.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.rust_type_constructor =
parse_annotation("rust_type_constructor", &e.node).map(|x| x.unwrap());

View file

@ -14,12 +14,13 @@ LICENSE END */
use crate::diagnostics::{FileDiagnostics, Spanned, SpannedWithSourceFile};
use crate::expression_tree::{self, Unit};
use crate::expression_tree::{Expression, ExpressionSpanned, NamedReference};
use crate::langtype::PropertyLookupResult;
use crate::langtype::{NativeClass, Type};
use crate::parser::{identifier_text, syntax_nodes, SyntaxKind, SyntaxNodeWithSourceFile};
use crate::typeregister::TypeRegister;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::{Rc, Weak};
use std::{borrow::Cow, cell::RefCell};
/// The full document (a complete file)
#[derive(Default, Debug)]
@ -418,9 +419,13 @@ impl Element {
for prop_decl in node.PropertyDeclaration() {
let type_node = prop_decl.Type();
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(
format!("Cannot override property '{}'", prop_name),
&prop_decl.DeclaredIdentifier().child_token(SyntaxKind::Identifier).unwrap(),
@ -435,7 +440,7 @@ impl Element {
}
r.property_declarations.insert(
prop_name.clone(),
prop_name.to_string(),
PropertyDeclaration {
property_type: prop_type,
type_node: Some(type_node.into()),
@ -445,7 +450,7 @@ impl Element {
if let Some(csn) = prop_decl.BindingExpression() {
if r.bindings
.insert(prop_name.clone(), ExpressionSpanned::new_uncompiled(csn.into()))
.insert(prop_name.to_string(), ExpressionSpanned::new_uncompiled(csn.into()))
.is_some()
{
diag.push_error(
@ -456,7 +461,7 @@ impl Element {
}
if let Some(csn) = prop_decl.TwoWayBinding() {
if r.bindings
.insert(prop_name, ExpressionSpanned::new_uncompiled(csn.into()))
.insert(prop_name.into(), ExpressionSpanned::new_uncompiled(csn.into()))
.is_some()
{
diag.push_error(
@ -504,18 +509,19 @@ impl Element {
}
for con_node in node.CallbackConnection() {
let name = match identifier_text(&con_node) {
let unresolved_name = match identifier_text(&con_node) {
Some(x) => x,
None => continue,
};
let prop_type = r.lookup_property(&name);
if let Type::Callback { args, .. } = prop_type {
let PropertyLookupResult { resolved_name, property_type } =
r.lookup_property(&unresolved_name);
if let Type::Callback { args, .. } = property_type {
let num_arg = con_node.DeclaredIdentifier().count();
if num_arg > args.len() {
diag.push_error(
format!(
"'{}' only has {} arguments, but {} were provided",
name,
unresolved_name,
args.len(),
num_arg
),
@ -523,7 +529,10 @@ impl Element {
);
}
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()
{
diag.push_error(
@ -533,7 +542,7 @@ impl Element {
}
} else {
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(),
);
}
@ -548,17 +557,21 @@ impl Element {
};
for prop_name_token in anim.QualifiedName() {
match QualifiedTypeName::from_node(prop_name_token.clone()).members.as_slice() {
[prop_name] => {
let prop_type = r.lookup_property(&prop_name);
[unresolved_prop_name] => {
let PropertyLookupResult { resolved_name, property_type } =
r.lookup_property(&unresolved_prop_name);
if let Some(anim_element) = animation_element_from_node(
&anim,
&prop_name_token,
prop_type,
property_type,
diag,
tr,
) {
if r.property_animations
.insert(prop_name.clone(), PropertyAnimation::Static(anim_element))
.insert(
resolved_name.to_string(),
PropertyAnimation::Static(anim_element),
)
.is_some()
{
diag.push_error("Duplicated animation".into(), &prop_name_token)
@ -750,13 +763,14 @@ impl Element {
e
}
/// Return the type of a property in this element or its base
pub fn lookup_property(&self, name: &str) -> Type {
self.property_declarations
.get(name)
.cloned()
.map(|decl| decl.property_type)
.unwrap_or_else(|| self.base_type.lookup_property(name))
/// Return the type of a property in this element or its base, along with the final name, in case
/// the provided name points towards a property alias. Type::Invalid is returned if the property does
/// not exist.
pub fn lookup_property<'a>(&self, name: &'a str) -> PropertyLookupResult<'a> {
self.property_declarations.get(name).cloned().map(|decl| decl.property_type).map_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
@ -773,26 +787,31 @@ impl Element {
diag: &mut FileDiagnostics,
) {
for (name_token, b) in bindings {
let name = crate::parser::normalize_identifier(name_token.text());
let prop_type = self.lookup_property(&name);
if !prop_type.is_property_type() {
let unresolved_name = crate::parser::normalize_identifier(name_token.text());
let PropertyLookupResult { resolved_name, property_type } =
self.lookup_property(&unresolved_name);
if !property_type.is_property_type() {
diag.push_error(
match prop_type {
match property_type {
Type::Invalid => {
format!("Unknown property {}{}", name, name_for_lookup_error)
format!("Unknown property {}{}", unresolved_name, name_for_lookup_error)
}
Type::Callback { .. } => {
format!("'{}' is a callback. Use `=>` to connect", name)
format!("'{}' is a callback. Use `=>` to connect", unresolved_name)
}
_ => format!(
"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,
);
}
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);
}
}
@ -917,25 +936,34 @@ fn lookup_property_from_qualified_name(
) -> (NamedReference, Type) {
let qualname = QualifiedTypeName::from_node(node.clone());
match qualname.members.as_slice() {
[prop_name] => {
let ty = r.borrow().lookup_property(prop_name.as_ref());
if !ty.is_property_type() {
[unresolved_prop_name] => {
let PropertyLookupResult { resolved_name, 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);
}
(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] => {
let (element, ty) = if let Some(element) = find_element_by_id(&r, elem_id.as_ref()) {
let ty = element.borrow().lookup_property(prop_name.as_ref());
if !ty.is_property_type() {
diag.push_error(format!("'{}' not found in '{}'", prop_name, elem_id), &node);
}
(Rc::downgrade(&element), ty)
} else {
diag.push_error(format!("'{}' is not a valid element id", elem_id), &node);
(Weak::new(), Type::Invalid)
};
(NamedReference { element, name: prop_name.clone() }, ty)
[elem_id, unresolved_prop_name] => {
let (element, name, ty) =
if let Some(element) = find_element_by_id(&r, elem_id.as_ref()) {
let PropertyLookupResult { resolved_name, property_type } =
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), resolved_name, property_type)
} else {
diag.push_error(format!("'{}' is not a valid element id", elem_id), &node);
(Weak::new(), Cow::Borrowed(unresolved_prop_name.as_ref()), Type::Invalid)
};
(NamedReference { element, name: name.to_string() }, ty)
}
_ => {
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);
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;
}
@ -1068,7 +1096,12 @@ pub fn visit_element_expressions(
}
for (ne, e) in &mut s.property_changes {
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
});
}
}

View file

@ -12,10 +12,13 @@ LICENSE END */
use std::rc::Rc;
use crate::expression_tree::{BuiltinFunction, Expression, NamedReference};
use crate::langtype::DefaultSizeBinding;
use crate::langtype::Type;
use crate::object_tree::{Component, ElementRc};
use crate::{
expression_tree::{BuiltinFunction, Expression, NamedReference},
langtype::PropertyLookupResult,
};
pub fn default_geometry(root_component: &Rc<Component>) {
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) {
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;
}
elem.borrow_mut().bindings.entry(property.into()).or_insert_with(|| {
Expression::PropertyReference(NamedReference::new(parent_element, property)).into()
elem.borrow_mut().bindings.entry(resolved_name.to_string()).or_insert_with(|| {
Expression::PropertyReference(NamedReference::new(parent_element, resolved_name.as_ref()))
.into()
});
}

View file

@ -149,7 +149,9 @@ fn lower_transitions_in_element(
/// Returns a suitable unique name for the "state" property
fn compute_state_property_name(root_element: &ElementRc) -> String {
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
@ -168,5 +170,5 @@ fn expression_for_property(element: &ElementRc, name: &str) -> Expression {
None
};
}
Expression::default_value_for_type(&element.borrow().lookup_property(name))
Expression::default_value_for_type(&element.borrow().lookup_property(name).property_type)
}

View file

@ -14,7 +14,6 @@ LICENSE END */
//!
//! 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::langtype::Type;
use crate::object_tree::*;
@ -22,6 +21,10 @@ use crate::parser::{
identifier_text, syntax_nodes, NodeOrTokenWithSourceFile, SyntaxKind, SyntaxNodeWithSourceFile,
};
use crate::typeregister::TypeRegister;
use crate::{
diagnostics::{BuildDiagnostics, SpannedWithSourceFile},
langtype::PropertyLookupResult,
};
use std::{collections::HashMap, rc::Rc};
/// 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);
while let Some(p) = parent {
let ty = p.borrow().lookup_property(property_name);
if ty == Type::Length {
let PropertyLookupResult { resolved_name, property_type } =
p.borrow().lookup_property(property_name);
if property_type == Type::Length {
return Expression::BinaryExpression {
lhs: Box::new(Expression::BinaryExpression {
lhs: Box::new(e),
@ -245,7 +249,7 @@ fn attempt_percent_conversion(
}),
rhs: Box::new(Expression::PropertyReference(NamedReference {
element: Rc::downgrade(&p),
name: property_name.to_string(),
name: resolved_name.to_string(),
})),
op: '*',
};
@ -577,22 +581,23 @@ impl Expression {
}
}
let property = elem.borrow().lookup_property(&first_str);
if property.is_property_type() {
let PropertyLookupResult { resolved_name, property_type } =
elem.borrow().lookup_property(&first_str);
if property_type.is_property_type() {
let prop = Self::PropertyReference(NamedReference {
element: Rc::downgrade(&elem),
name: first_str,
name: resolved_name.to_string(),
});
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() {
ctx.diag.push_error("Cannot access fields of callback".into(), &x)
}
return Self::CallbackReference(NamedReference {
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");
}
}
@ -681,8 +686,9 @@ impl Expression {
}
}
let property = elem.borrow().lookup_property(&first_str);
if property.is_property_type() {
let PropertyLookupResult { resolved_name: _, property_type } =
elem.borrow().lookup_property(&first_str);
if property_type.is_property_type() {
report_minus_error(ctx);
return Expression::Invalid;
}
@ -1128,23 +1134,24 @@ fn continue_lookup_within_element(
};
let prop_name = crate::parser::normalize_identifier(second.text());
let p = elem.borrow().lookup_property(&prop_name);
if p.is_property_type() {
let PropertyLookupResult { resolved_name, property_type } =
elem.borrow().lookup_property(&prop_name);
if property_type.is_property_type() {
let prop = Expression::PropertyReference(NamedReference {
element: Rc::downgrade(elem),
name: prop_name,
name: resolved_name.to_string(),
});
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() {
ctx.diag.push_error("Cannot access fields of callback".into(), &x)
}
Expression::CallbackReference(NamedReference {
element: Rc::downgrade(elem),
name: prop_name,
name: resolved_name.to_string(),
})
} else if matches!(p, Type::Function{..}) {
let member = elem.borrow().base_type.lookup_member_function(&prop_name);
} else if matches!(property_type, Type::Function{..}) {
let member = elem.borrow().base_type.lookup_member_function(&resolved_name);
Expression::MemberFunction {
base: Box::new(Expression::ElementReference(Rc::downgrade(elem))),
base_node: node.into(),
@ -1169,7 +1176,9 @@ fn continue_lookup_within_element(
};
if let Some(minus_pos) = second.text().find('-') {
// 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.");
return Expression::Invalid;
}
@ -1213,15 +1222,16 @@ fn maybe_lookup_object(
}
}
Type::Component(c) => {
let prop_ty = c.root_element.borrow().lookup_property(next_str.as_str());
if prop_ty != Type::Invalid {
let PropertyLookupResult { resolved_name, property_type } =
c.root_element.borrow().lookup_property(next_str.as_str());
if property_type != Type::Invalid {
base = Expression::ObjectAccess {
base: Box::new(std::mem::replace(&mut base, Expression::Invalid)),
name: next.to_string(),
name: resolved_name.to_string(),
}
} else {
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
});
}
}

View file

@ -24,7 +24,7 @@ TestCase := Rectangle {
animate * { }
}
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 { }
}
]

View file

@ -157,7 +157,7 @@ impl ItemWeak {
#[pin]
/// The implementation of the `Rectangle` element
pub struct Rectangle {
pub color: Property<Color>,
pub background: Property<Color>,
pub x: Property<f32>,
pub y: Property<f32>,
pub width: Property<f32>,
@ -218,7 +218,7 @@ ItemVTable_static! {
#[pin]
/// The implementation of the `BorderRectangle` element
pub struct BorderRectangle {
pub color: Property<Color>,
pub background: Property<Color>,
pub x: Property<f32>,
pub y: Property<f32>,
pub width: Property<f32>,

View file

@ -14,10 +14,10 @@ use core::ptr::NonNull;
use dynamic_type::{Instance, InstanceBox};
use expression_tree::NamedReference;
use object_tree::{Element, ElementRc};
use sixtyfps_compilerlib::expression_tree::Expression;
use sixtyfps_compilerlib::langtype::Type;
use sixtyfps_compilerlib::layout::{Layout, LayoutConstraints, LayoutItem, PathLayout};
use sixtyfps_compilerlib::*;
use sixtyfps_compilerlib::{expression_tree::Expression, langtype::PropertyLookupResult};
use sixtyfps_corelib::component::{Component, ComponentRefPin, ComponentVTable};
use sixtyfps_corelib::graphics::{Rect, Resource};
use sixtyfps_corelib::item_tree::{
@ -168,8 +168,10 @@ impl RepeatedComponent for ErasedComponentBox {
let root_item = &s.component_type.original.root_element.clone();
let get_prop = |name: &str| {
if root_item.borrow().lookup_property(name) == Type::Length {
let nr = NamedReference::new(root_item, name);
let PropertyLookupResult { resolved_name, property_type } =
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());
// Safety: assuming get_property_ptr returned a valid pointer,
// we know that `Type::Length` is a property of type `f32`
@ -820,9 +822,10 @@ pub fn instantiate<'id>(
unsafe {
let item = item_within_component.item_from_component(instance_ref.as_ptr());
let elem = item_within_component.elem.borrow();
for (prop, expr) in &elem.bindings {
let ty = elem.lookup_property(prop.as_str());
if let Type::Callback { .. } = ty {
for (unresolved_prop_name, expr) in &elem.bindings {
let PropertyLookupResult { resolved_name, property_type } =
elem.lookup_property(unresolved_prop_name.as_str());
if let Type::Callback { .. } = property_type {
let expr = expr.clone();
let component_type = component_type.clone();
let instance = component_box.instance.as_ptr();
@ -830,7 +833,8 @@ pub fn instantiate<'id>(
NonNull::from(&component_type.ct).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(
item,
@ -845,7 +849,7 @@ pub fn instantiate<'id>(
}),
)
} 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());
callback.set_handler(move |args| {
@ -857,13 +861,14 @@ pub fn instantiate<'id>(
eval::eval_expression(&expr, &mut local_context)
})
} else {
panic!("unkown callback {}", prop)
panic!("unkown callback {}", unresolved_prop_name)
}
} else {
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);
while let Some(Expression::TwoWayBinding(nr, next)) = &e {
// 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 {
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(
NonNull::from(&component_type.ct).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), .. }
if name.ends_with("::StateInfo") =>
{
@ -946,7 +951,7 @@ pub fn instantiate<'id>(
let maybe_animation = animation_for_property(
instance_ref,
&component_type.original.root_element.borrow(),
prop,
resolved_name.as_ref(),
);
let item = Pin::new_unchecked(&*instance_ref.as_ptr().add(*offset));
@ -983,7 +988,7 @@ pub fn instantiate<'id>(
}
}
} else {
panic!("unkown property {}", prop);
panic!("unkown property {}", unresolved_prop_name);
}
}
}

View file

@ -667,7 +667,7 @@ impl ItemRenderer for GLItemRenderer {
}
// TODO: cache path in item to avoid re-tesselation
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| {
canvas.translate(pos.x, pos.y);
canvas.fill_path(&mut path, paint)
@ -705,7 +705,7 @@ impl ItemRenderer for GLItemRenderer {
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());
border_paint.set_line_width(border_width);

View file

@ -226,7 +226,7 @@ struct QtItemRenderer<'a> {
impl ItemRenderer for QtItemRenderer<'_> {
fn draw_rectangle(&mut self, pos: Point, rect: Pin<&items::Rectangle>) {
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 painter: &mut QPainter = &mut *self.painter;
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>) {
self.draw_rectangle_impl(
get_geometry!(pos, items::BorderRectangle, rect),
rect.color(),
rect.background(),
rect.border_color(),
rect.border_width(),
rect.border_radius(),