mirror of
https://github.com/slint-ui/slint.git
synced 2025-09-30 22:01:13 +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 := _ {
|
||||
property <color> color;
|
||||
property <color> background;
|
||||
property <color> color <=> background;
|
||||
property <length> x;
|
||||
property <length> y;
|
||||
property <length> width;
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 { }
|
||||
}
|
||||
]
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue