mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-03 15:14:35 +00:00
input output property: fix semantic with two ways bindings
This commit is contained in:
parent
15d9a2665b
commit
6ab6ae63d4
10 changed files with 477 additions and 23 deletions
|
@ -1130,7 +1130,26 @@ impl Expression {
|
||||||
nr.mark_as_set();
|
nr.mark_as_set();
|
||||||
let lookup = nr.element().borrow().lookup_property(nr.name());
|
let lookup = nr.element().borrow().lookup_property(nr.name());
|
||||||
if lookup.is_valid_for_assignment() {
|
if lookup.is_valid_for_assignment() {
|
||||||
true
|
if !nr
|
||||||
|
.element()
|
||||||
|
.borrow()
|
||||||
|
.property_analysis
|
||||||
|
.borrow()
|
||||||
|
.get(nr.name())
|
||||||
|
.map_or(false, |d| d.is_linked_to_read_only)
|
||||||
|
{
|
||||||
|
true
|
||||||
|
} else if is_legacy_component {
|
||||||
|
diag.push_warning("Modifying a property that is linked to a read-only property is deprecated".into(), node);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
diag.push_error(
|
||||||
|
"Cannot modify a property that is linked to a read-only property"
|
||||||
|
.into(),
|
||||||
|
node,
|
||||||
|
);
|
||||||
|
false
|
||||||
|
}
|
||||||
} else if is_legacy_component
|
} else if is_legacy_component
|
||||||
&& lookup.property_visibility == PropertyVisibility::Output
|
&& lookup.property_visibility == PropertyVisibility::Output
|
||||||
{
|
{
|
||||||
|
|
|
@ -346,7 +346,7 @@ pub struct BuiltinPropertyInfo {
|
||||||
|
|
||||||
impl BuiltinPropertyInfo {
|
impl BuiltinPropertyInfo {
|
||||||
pub fn new(ty: Type) -> Self {
|
pub fn new(ty: Type) -> Self {
|
||||||
Self { ty, default_value: None, property_visibility: PropertyVisibility::Private }
|
Self { ty, default_value: None, property_visibility: PropertyVisibility::InOut }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_native_output(&self) -> bool {
|
pub fn is_native_output(&self) -> bool {
|
||||||
|
|
|
@ -86,6 +86,8 @@ pub fn load_builtins(register: &mut TypeRegister) {
|
||||||
register,
|
register,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
info.property_visibility = PropertyVisibility::Private;
|
||||||
|
|
||||||
for token in p.children_with_tokens() {
|
for token in p.children_with_tokens() {
|
||||||
if token.kind() != SyntaxKind::Identifier {
|
if token.kind() != SyntaxKind::Identifier {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -614,6 +614,9 @@ pub struct PropertyAnalysis {
|
||||||
|
|
||||||
/// true if this property is read from another component
|
/// true if this property is read from another component
|
||||||
pub is_read_externally: bool,
|
pub is_read_externally: bool,
|
||||||
|
|
||||||
|
/// True if the property is linked to another property that is read only. That property becomes read-only
|
||||||
|
pub is_linked_to_read_only: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PropertyAnalysis {
|
impl PropertyAnalysis {
|
||||||
|
@ -1233,7 +1236,7 @@ impl Element {
|
||||||
&& lookup_result.property_visibility == PropertyVisibility::Output
|
&& lookup_result.property_visibility == PropertyVisibility::Output
|
||||||
{
|
{
|
||||||
diag.push_warning(
|
diag.push_warning(
|
||||||
format!("Assigning to out property '{unresolved_name}' is deprecated"),
|
format!("Assigning to output property '{unresolved_name}' is deprecated"),
|
||||||
&name_token,
|
&name_token,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -30,7 +30,6 @@ fn resolve_expression(
|
||||||
scope: &ComponentScope,
|
scope: &ComponentScope,
|
||||||
type_register: &TypeRegister,
|
type_register: &TypeRegister,
|
||||||
type_loader: &crate::typeloader::TypeLoader,
|
type_loader: &crate::typeloader::TypeLoader,
|
||||||
two_ways: &mut Vec<(String, NamedReference)>,
|
|
||||||
diag: &mut BuildDiagnostics,
|
diag: &mut BuildDiagnostics,
|
||||||
) {
|
) {
|
||||||
if let Expression::Uncompiled(node) = expr {
|
if let Expression::Uncompiled(node) = expr {
|
||||||
|
@ -59,14 +58,7 @@ fn resolve_expression(
|
||||||
Expression::from_binding_expression_node(node.clone(), &mut lookup_ctx)
|
Expression::from_binding_expression_node(node.clone(), &mut lookup_ctx)
|
||||||
}
|
}
|
||||||
SyntaxKind::TwoWayBinding => {
|
SyntaxKind::TwoWayBinding => {
|
||||||
if lookup_ctx.property_type == Type::Invalid {
|
assert!(diag.has_error(), "Two way binding should have been resolved already (property: {property_name:?})");
|
||||||
// An attempt to resolve this already failed when trying to resolve the property type
|
|
||||||
assert!(diag.has_error());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if let Some(nr) = resolve_two_way_binding(node.clone().into(), &mut lookup_ctx) {
|
|
||||||
two_ways.push((property_name.unwrap().into(), nr));
|
|
||||||
}
|
|
||||||
Expression::Invalid
|
Expression::Invalid
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -83,6 +75,8 @@ pub fn resolve_expressions(
|
||||||
type_loader: &crate::typeloader::TypeLoader,
|
type_loader: &crate::typeloader::TypeLoader,
|
||||||
diag: &mut BuildDiagnostics,
|
diag: &mut BuildDiagnostics,
|
||||||
) {
|
) {
|
||||||
|
resolve_two_way_bindings(doc, &doc.local_registry, diag);
|
||||||
|
|
||||||
for component in doc.inner_components.iter() {
|
for component in doc.inner_components.iter() {
|
||||||
let scope = ComponentScope(vec![]);
|
let scope = ComponentScope(vec![]);
|
||||||
|
|
||||||
|
@ -90,7 +84,6 @@ pub fn resolve_expressions(
|
||||||
let mut new_scope = scope.clone();
|
let mut new_scope = scope.clone();
|
||||||
let mut is_repeated = elem.borrow().repeated.is_some();
|
let mut is_repeated = elem.borrow().repeated.is_some();
|
||||||
new_scope.0.push(elem.clone());
|
new_scope.0.push(elem.clone());
|
||||||
let mut two_ways = vec![];
|
|
||||||
visit_element_expressions(elem, |expr, property_name, property_type| {
|
visit_element_expressions(elem, |expr, property_name, property_type| {
|
||||||
if is_repeated {
|
if is_repeated {
|
||||||
// The first expression is always the model and it needs to be resolved with the parent scope
|
// The first expression is always the model and it needs to be resolved with the parent scope
|
||||||
|
@ -102,7 +95,6 @@ pub fn resolve_expressions(
|
||||||
&scope,
|
&scope,
|
||||||
&doc.local_registry,
|
&doc.local_registry,
|
||||||
type_loader,
|
type_loader,
|
||||||
&mut two_ways,
|
|
||||||
diag,
|
diag,
|
||||||
);
|
);
|
||||||
is_repeated = false;
|
is_repeated = false;
|
||||||
|
@ -114,14 +106,10 @@ pub fn resolve_expressions(
|
||||||
&new_scope,
|
&new_scope,
|
||||||
&doc.local_registry,
|
&doc.local_registry,
|
||||||
type_loader,
|
type_loader,
|
||||||
&mut two_ways,
|
|
||||||
diag,
|
diag,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
for (prop, nr) in two_ways {
|
|
||||||
elem.borrow().bindings.get(&prop).unwrap().borrow_mut().two_way_bindings.push(nr);
|
|
||||||
}
|
|
||||||
new_scope
|
new_scope
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1139,6 +1127,123 @@ fn maybe_lookup_object(
|
||||||
base
|
base
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Go through all the two way binding and resolve them first
|
||||||
|
fn resolve_two_way_bindings(
|
||||||
|
doc: &Document,
|
||||||
|
type_register: &TypeRegister,
|
||||||
|
diag: &mut BuildDiagnostics,
|
||||||
|
) {
|
||||||
|
for component in doc.inner_components.iter() {
|
||||||
|
let scope = ComponentScope(vec![]);
|
||||||
|
|
||||||
|
recurse_elem(&component.root_element, &scope, &mut |elem, scope| {
|
||||||
|
let mut new_scope = scope.clone();
|
||||||
|
new_scope.0.push(elem.clone());
|
||||||
|
for (prop_name, binding) in &elem.borrow().bindings {
|
||||||
|
let mut binding = binding.borrow_mut();
|
||||||
|
if let Expression::Uncompiled(node) = binding.expression.clone() {
|
||||||
|
if let Some(n) = syntax_nodes::TwoWayBinding::new(node.clone()) {
|
||||||
|
let lhs_lookup = elem.borrow().lookup_property(prop_name);
|
||||||
|
if lhs_lookup.property_type == Type::Invalid {
|
||||||
|
// An attempt to resolve this already failed when trying to resolve the property type
|
||||||
|
assert!(diag.has_error());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut lookup_ctx = LookupCtx {
|
||||||
|
property_name: Some(prop_name.as_str()),
|
||||||
|
property_type: lhs_lookup.property_type.clone(),
|
||||||
|
component_scope: &new_scope.0,
|
||||||
|
diag,
|
||||||
|
arguments: vec![],
|
||||||
|
type_register,
|
||||||
|
type_loader: None,
|
||||||
|
current_token: Some(node.clone().into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
binding.expression = Expression::Invalid;
|
||||||
|
|
||||||
|
if let Some(nr) = resolve_two_way_binding(n, &mut lookup_ctx) {
|
||||||
|
binding.two_way_bindings.push(nr.clone());
|
||||||
|
|
||||||
|
// Check the compatibility.
|
||||||
|
let rhs_lookup = nr.element().borrow().lookup_property(nr.name());
|
||||||
|
|
||||||
|
if !rhs_lookup.is_valid_for_assignment() {
|
||||||
|
match (
|
||||||
|
lhs_lookup.property_visibility,
|
||||||
|
rhs_lookup.property_visibility,
|
||||||
|
) {
|
||||||
|
(PropertyVisibility::Input, PropertyVisibility::Input)
|
||||||
|
if !lhs_lookup.is_local_to_component =>
|
||||||
|
{
|
||||||
|
assert!(rhs_lookup.is_local_to_component);
|
||||||
|
marked_linked_read_only(elem, prop_name);
|
||||||
|
}
|
||||||
|
(
|
||||||
|
PropertyVisibility::Output | PropertyVisibility::Private,
|
||||||
|
PropertyVisibility::Output | PropertyVisibility::Input,
|
||||||
|
) => {
|
||||||
|
assert!(lhs_lookup.is_local_to_component);
|
||||||
|
marked_linked_read_only(elem, prop_name);
|
||||||
|
}
|
||||||
|
(PropertyVisibility::Input, PropertyVisibility::Output)
|
||||||
|
if !lhs_lookup.is_local_to_component =>
|
||||||
|
{
|
||||||
|
assert!(!rhs_lookup.is_local_to_component);
|
||||||
|
marked_linked_read_only(elem, prop_name);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if lookup_ctx.is_legacy_component() {
|
||||||
|
diag.push_warning(
|
||||||
|
format!(
|
||||||
|
"Link to a {} property is deprecated",
|
||||||
|
rhs_lookup.property_visibility
|
||||||
|
),
|
||||||
|
&node,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
diag.push_error(
|
||||||
|
format!(
|
||||||
|
"Cannot link to a {} property",
|
||||||
|
rhs_lookup.property_visibility
|
||||||
|
),
|
||||||
|
&node,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if !lhs_lookup.is_valid_for_assignment() {
|
||||||
|
if rhs_lookup.is_local_to_component
|
||||||
|
&& rhs_lookup.property_visibility == PropertyVisibility::InOut
|
||||||
|
{
|
||||||
|
if lookup_ctx.is_legacy_component() {
|
||||||
|
debug_assert!(!diag.is_empty()); // warning should already be reported
|
||||||
|
} else {
|
||||||
|
diag.push_error("Cannot link input property".into(), &node);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This is allowed, but then the rhs must also become read only.
|
||||||
|
marked_linked_read_only(&nr.element(), nr.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new_scope
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn marked_linked_read_only(elem: &ElementRc, prop_name: &str) {
|
||||||
|
elem.borrow()
|
||||||
|
.property_analysis
|
||||||
|
.borrow_mut()
|
||||||
|
.entry(prop_name.to_string())
|
||||||
|
.or_default()
|
||||||
|
.is_linked_to_read_only = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn resolve_two_way_binding(
|
pub fn resolve_two_way_binding(
|
||||||
node: syntax_nodes::TwoWayBinding,
|
node: syntax_nodes::TwoWayBinding,
|
||||||
ctx: &mut LookupCtx,
|
ctx: &mut LookupCtx,
|
||||||
|
|
|
@ -45,7 +45,7 @@ OldCompo := Rectangle {
|
||||||
// ^warning{Self assignment on an output property is deprecated}
|
// ^warning{Self assignment on an output property is deprecated}
|
||||||
}
|
}
|
||||||
has-hover: true;
|
has-hover: true;
|
||||||
// ^warning{Assigning to out property 'has-hover' is deprecated}
|
// ^warning{Assigning to output property 'has-hover' is deprecated}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,325 @@
|
||||||
|
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
||||||
|
|
||||||
|
component Button {
|
||||||
|
in property<bool> enabled : true;
|
||||||
|
out property <bool> pressed;
|
||||||
|
in-out property <bool> checked;
|
||||||
|
callback clicked();
|
||||||
|
}
|
||||||
|
|
||||||
|
component C1 {
|
||||||
|
out property <bool> out;
|
||||||
|
in property <bool> in;
|
||||||
|
in-out property <bool> inout;
|
||||||
|
property <bool> priv;
|
||||||
|
|
||||||
|
// pressed is "output" in Button
|
||||||
|
out <=> b.pressed; // ok (but then there should be no other assignment?)
|
||||||
|
in <=> b.pressed; // Error
|
||||||
|
// ^error{Cannot link to a output property}
|
||||||
|
inout <=> b.pressed;
|
||||||
|
// ^error{Cannot link to a output property}
|
||||||
|
priv <=> b.pressed; // makes assignment forbidden
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
b:= Button {
|
||||||
|
clicked => {
|
||||||
|
in = !in;
|
||||||
|
// ^error{Assignment on a input property}
|
||||||
|
out = !out;
|
||||||
|
// ^error{Cannot modify a property that is linked to a read-only property}
|
||||||
|
inout = !inout;
|
||||||
|
priv = !priv;
|
||||||
|
// ^error{Cannot modify a property that is linked to a read-only property}
|
||||||
|
|
||||||
|
self.enabled = !self.enabled;
|
||||||
|
self.checked = !self.checked;
|
||||||
|
self.pressed = !self.pressed;
|
||||||
|
// ^error{Assignment on a output property}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
component C2 {
|
||||||
|
out property <bool> out;
|
||||||
|
in property <bool> in;
|
||||||
|
in-out property <bool> inout;
|
||||||
|
property <bool> priv;
|
||||||
|
|
||||||
|
// enabled is "input" in Button
|
||||||
|
out <=> b.enabled;
|
||||||
|
in <=> b.enabled;
|
||||||
|
inout <=> b.enabled;
|
||||||
|
priv <=> b.enabled;
|
||||||
|
|
||||||
|
b:= Button {
|
||||||
|
clicked => {
|
||||||
|
in = !in;
|
||||||
|
// ^error{Assignment on a input property}
|
||||||
|
out = !out;
|
||||||
|
inout = !inout;
|
||||||
|
priv = !priv;
|
||||||
|
|
||||||
|
|
||||||
|
self.enabled = !self.enabled;
|
||||||
|
// ^error{Cannot modify a property that is linked to a read-only property}
|
||||||
|
self.checked = !self.checked;
|
||||||
|
self.pressed = !self.pressed;
|
||||||
|
// ^error{Assignment on a output property}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component C3 {
|
||||||
|
out property <bool> out;
|
||||||
|
in property <bool> in;
|
||||||
|
in-out property <bool> inout;
|
||||||
|
property <bool> priv;
|
||||||
|
|
||||||
|
// checked is "input/output" in Button
|
||||||
|
out <=> b.checked;
|
||||||
|
in <=> b.checked;
|
||||||
|
inout <=> b.checked;
|
||||||
|
priv <=> b.checked;
|
||||||
|
|
||||||
|
b:= Button {
|
||||||
|
clicked => {
|
||||||
|
in = !in;
|
||||||
|
// ^error{Assignment on a input property}
|
||||||
|
out = !out;
|
||||||
|
inout = !inout;
|
||||||
|
priv = !priv;
|
||||||
|
|
||||||
|
self.enabled = !self.enabled;
|
||||||
|
self.checked = !self.checked;
|
||||||
|
// ^error{Cannot modify a property that is linked to a read-only property}
|
||||||
|
self.pressed = !self.pressed;
|
||||||
|
// ^error{Assignment on a output property}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
component C5 {
|
||||||
|
out property <bool> out;
|
||||||
|
in property <bool> in;
|
||||||
|
in-out property <bool> inout;
|
||||||
|
property <bool> priv;
|
||||||
|
|
||||||
|
Button { enabled <=> out; }
|
||||||
|
Button {
|
||||||
|
enabled <=> in;
|
||||||
|
clicked => { self.enabled = !self.enabled; }
|
||||||
|
// ^error{Cannot modify a property that is linked to a read-only property}
|
||||||
|
}
|
||||||
|
Button { enabled <=> inout; }
|
||||||
|
Button { enabled <=> priv; }
|
||||||
|
}
|
||||||
|
|
||||||
|
component C6 {
|
||||||
|
out property <bool> out;
|
||||||
|
in property <bool> in;
|
||||||
|
in-out property <bool> inout;
|
||||||
|
property <bool> priv;
|
||||||
|
|
||||||
|
Button {
|
||||||
|
checked <=> out;
|
||||||
|
clicked => { out = !out; self.checked = !self.checked; }
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
checked <=> in;
|
||||||
|
// ^error{Cannot link to a input property}
|
||||||
|
clicked => { self.checked = !self.checked; }
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
checked <=> inout;
|
||||||
|
clicked => { inout = !inout; self.checked = !self.checked; }
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
checked <=> priv;
|
||||||
|
clicked => { priv = !priv; self.checked = !self.checked; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component C7 {
|
||||||
|
b1 := Button {
|
||||||
|
clicked => {
|
||||||
|
self.enabled = !self.enabled;
|
||||||
|
self.checked = !self.checked;
|
||||||
|
self.pressed = !self.pressed;
|
||||||
|
// ^error{Assignment on a output property}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
enabled <=> b1.pressed;
|
||||||
|
clicked => { self.enabled = !self.enabled; }
|
||||||
|
// ^error{Cannot modify a property that is linked to a read-only property}
|
||||||
|
}
|
||||||
|
b2 := Button {
|
||||||
|
clicked => {
|
||||||
|
self.enabled = !self.enabled;
|
||||||
|
self.checked = !self.checked;
|
||||||
|
self.pressed = !self.pressed;
|
||||||
|
// ^error{Assignment on a output property}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button { checked <=> b2.pressed; }
|
||||||
|
// ^error{Cannot link to a output property}
|
||||||
|
|
||||||
|
b3 := Button {
|
||||||
|
clicked => {
|
||||||
|
self.enabled = !self.enabled;
|
||||||
|
self.checked = !self.checked;
|
||||||
|
self.pressed = !self.pressed;
|
||||||
|
// ^error{Assignment on a output property}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
checked <=> b3.checked;
|
||||||
|
enabled <=> b3.checked;
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
checked <=> b3.enabled;
|
||||||
|
enabled <=> b3.enabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component C8 {
|
||||||
|
out property <bool> out1;
|
||||||
|
out property <bool> out2;
|
||||||
|
out property <bool> out3;
|
||||||
|
out property <bool> out4;
|
||||||
|
|
||||||
|
out property <bool> out <=> out1;
|
||||||
|
in property <bool> in <=> out2;
|
||||||
|
in-out property <bool> inout <=> out3;
|
||||||
|
property <bool> priv <=> out4;
|
||||||
|
|
||||||
|
Button {
|
||||||
|
clicked => {
|
||||||
|
out1 = !out1;
|
||||||
|
out2 = !out2;
|
||||||
|
// ^error{Cannot modify a property that is linked to a read-only property}
|
||||||
|
out3 = !out3;
|
||||||
|
out4 = !out4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component C9 {
|
||||||
|
in property <bool> in1;
|
||||||
|
in property <bool> in2;
|
||||||
|
in property <bool> in3;
|
||||||
|
in property <bool> in4;
|
||||||
|
|
||||||
|
out property <bool> out <=> in1;
|
||||||
|
in property <bool> in <=> in2;
|
||||||
|
// ^error{Cannot link to a input property}
|
||||||
|
in-out property <bool> inout <=> in3;
|
||||||
|
// ^error{Cannot link to a input property}
|
||||||
|
property <bool> priv <=> in4;
|
||||||
|
|
||||||
|
Button {
|
||||||
|
clicked => {
|
||||||
|
out = !out;
|
||||||
|
// ^error{Cannot modify a property that is linked to a read-only property}
|
||||||
|
in = !in;
|
||||||
|
// ^error{Assignment on a input property}
|
||||||
|
inout = !inout;
|
||||||
|
priv = !priv;
|
||||||
|
// ^error{Cannot modify a property that is linked to a read-only property}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
component C10 {
|
||||||
|
in-out property <bool> inout1;
|
||||||
|
in-out property <bool> inout2;
|
||||||
|
in-out property <bool> inout3;
|
||||||
|
in-out property <bool> inout4;
|
||||||
|
|
||||||
|
out property <bool> out <=> inout1;
|
||||||
|
in property <bool> in <=> inout2;
|
||||||
|
// ^error{Cannot link input property}
|
||||||
|
in-out property <bool> inout <=> inout3;
|
||||||
|
property <bool> priv <=> inout4;
|
||||||
|
|
||||||
|
Button {
|
||||||
|
clicked => {
|
||||||
|
inout1 = !inout1;
|
||||||
|
inout2 = !inout2;
|
||||||
|
inout3 = !inout3;
|
||||||
|
inout4 = !inout4;
|
||||||
|
out = !out;
|
||||||
|
in = !in;
|
||||||
|
// ^error{Assignment on a input property}
|
||||||
|
inout = !inout;
|
||||||
|
priv = !priv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component C11 {
|
||||||
|
property <bool> priv1;
|
||||||
|
property <bool> priv2;
|
||||||
|
property <bool> priv3;
|
||||||
|
property <bool> priv4;
|
||||||
|
|
||||||
|
out property <bool> out <=> priv1;
|
||||||
|
in property <bool> in <=> priv2;
|
||||||
|
in-out property <bool> inout <=> priv3;
|
||||||
|
property <bool> priv <=> priv4;
|
||||||
|
|
||||||
|
Button {
|
||||||
|
clicked => {
|
||||||
|
priv1 = !priv1;
|
||||||
|
priv2 = !priv2;
|
||||||
|
// ^error{Cannot modify a property that is linked to a read-only property}
|
||||||
|
priv3 = !priv3;
|
||||||
|
priv4 = !priv4;
|
||||||
|
out = !out;
|
||||||
|
in = !in;
|
||||||
|
// ^error{Assignment on a input property}
|
||||||
|
inout = !inout;
|
||||||
|
priv = !priv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Legacy1 := Rectangle {
|
||||||
|
b1:= Button {}
|
||||||
|
in property in1 <=> b1.pressed;
|
||||||
|
// ^warning{Link to a output property is deprecated}
|
||||||
|
out property out1 <=> b1.pressed;
|
||||||
|
in-out property inout1 <=> b1.pressed;
|
||||||
|
// ^warning{Link to a output property is deprecated}
|
||||||
|
|
||||||
|
|
||||||
|
property <bool> p1;
|
||||||
|
Button {
|
||||||
|
pressed <=> p1;
|
||||||
|
// ^warning{Assigning to output property 'pressed' is deprecated}
|
||||||
|
clicked => {
|
||||||
|
p1 = !p1;
|
||||||
|
out1 = !out1;
|
||||||
|
// ^warning{Modifying a property that is linked to a read-only property is deprecated}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
enabled <=> self.pressed;
|
||||||
|
clicked => {
|
||||||
|
self.enabled = !self.enabled;
|
||||||
|
// ^warning{Modifying a property that is linked to a read-only property is deprecated}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ export LineEditInner := Rectangle {
|
||||||
property text <=> input.text;
|
property text <=> input.text;
|
||||||
property placeholder-color <=> placeholder.color;
|
property placeholder-color <=> placeholder.color;
|
||||||
property enabled <=> input.enabled;
|
property enabled <=> input.enabled;
|
||||||
property has-focus <=> input.has-focus;
|
property <bool> has-focus: input.has-focus;
|
||||||
property input-type <=> input.input-type;
|
property input-type <=> input.input-type;
|
||||||
property horizontal-alignment <=> input.horizontal-alignment;
|
property horizontal-alignment <=> input.horizontal-alignment;
|
||||||
property read-only <=> input.read-only;
|
property read-only <=> input.read-only;
|
||||||
|
@ -47,7 +47,7 @@ export LineEditInner := Rectangle {
|
||||||
export TextEdit := ScrollView {
|
export TextEdit := ScrollView {
|
||||||
property <length> font-size <=> input.font-size;
|
property <length> font-size <=> input.font-size;
|
||||||
property <string> text <=> input.text;
|
property <string> text <=> input.text;
|
||||||
has-focus <=> input.has-focus;
|
has-focus: input.has-focus;
|
||||||
enabled <=> input.enabled;
|
enabled <=> input.enabled;
|
||||||
property <TextWrap> wrap <=> input.wrap;
|
property <TextWrap> wrap <=> input.wrap;
|
||||||
property horizontal-alignment <=> input.horizontal-alignment;
|
property horizontal-alignment <=> input.horizontal-alignment;
|
||||||
|
|
|
@ -83,7 +83,7 @@ export global StyleMetrics := {
|
||||||
export Button := Rectangle {
|
export Button := Rectangle {
|
||||||
callback clicked;
|
callback clicked;
|
||||||
property<string> text <=> text.text;
|
property<string> text <=> text.text;
|
||||||
property<bool> has-focus <=> fs.has-focus;
|
property<bool> has-focus: fs.has-focus;
|
||||||
property<bool> pressed: self.enabled && touch.pressed;
|
property<bool> pressed: self.enabled && touch.pressed;
|
||||||
property<bool> enabled <=> touch.enabled;
|
property<bool> enabled <=> touch.enabled;
|
||||||
property<bool> checkable;
|
property<bool> checkable;
|
||||||
|
|
|
@ -218,7 +218,7 @@ export Slider := Rectangle {
|
||||||
property<float> maximum: 100;
|
property<float> maximum: 100;
|
||||||
property<float> minimum: 0;
|
property<float> minimum: 0;
|
||||||
property<float> value;
|
property<float> value;
|
||||||
property<bool> has-focus <=> fs.has-focus;
|
property<bool> has-focus: fs.has-focus;
|
||||||
property<bool> enabled <=> touch.enabled;
|
property<bool> enabled <=> touch.enabled;
|
||||||
callback changed(float);
|
callback changed(float);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue