mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-04 10:50:00 +00:00
New syntax: allow to create component without base
This commit is contained in:
parent
d7e366864b
commit
f055afd2de
14 changed files with 187 additions and 77 deletions
|
@ -23,13 +23,19 @@
|
|||
|
||||
import { _ } from ""; // just to silence many errors in the LSP
|
||||
|
||||
Rectangle := _ {
|
||||
property <brush> background;
|
||||
property <brush> color <=> background;
|
||||
Empty := _ {
|
||||
property <length> x;
|
||||
property <length> y;
|
||||
property <length> width;
|
||||
property <length> height;
|
||||
//-default_size_binding:expands_to_parent_geometry
|
||||
//-is_internal
|
||||
|
||||
}
|
||||
|
||||
Rectangle := Empty {
|
||||
property <brush> background;
|
||||
property <brush> color <=> background;
|
||||
}
|
||||
|
||||
BorderRectangle := Rectangle {
|
||||
|
@ -41,12 +47,8 @@ BorderRectangle := Rectangle {
|
|||
|
||||
export { BorderRectangle as Rectangle }
|
||||
|
||||
ImageItem := _ {
|
||||
ImageItem := Empty {
|
||||
property <image> source;
|
||||
property <length> x;
|
||||
property <length> y;
|
||||
property <length> width;
|
||||
property <length> height;
|
||||
property <ImageFit> image-fit;
|
||||
property <ImageRendering> image-rendering;
|
||||
}
|
||||
|
@ -57,25 +59,20 @@ export ClippedImage := ImageItem {
|
|||
property <int> source-clip-width;
|
||||
property <int> source-clip-height;
|
||||
property <brush> colorize;
|
||||
property <ImageRendering> image-rendering;
|
||||
//-default_size_binding:implicit_size
|
||||
}
|
||||
|
||||
export { ClippedImage as Image }
|
||||
|
||||
export Rotate := _ {
|
||||
property <length> x;
|
||||
property <length> y;
|
||||
export Rotate := Empty {
|
||||
property <angle> rotation-angle;
|
||||
property <length> rotation-origin-x;
|
||||
property <length> rotation-origin-y;
|
||||
property <length> width;
|
||||
property <length> height;
|
||||
//-default_size_binding:expands_to_parent_geometry
|
||||
//-is_internal
|
||||
}
|
||||
|
||||
export Text := _ {
|
||||
export Text := Empty {
|
||||
property <string> text;
|
||||
property <string> font-family;
|
||||
property <length> font-size;
|
||||
|
@ -86,10 +83,6 @@ export Text := _ {
|
|||
property <TextOverflow> overflow;
|
||||
property <TextWrap> wrap;
|
||||
property <length> letter-spacing;
|
||||
property <length> x;
|
||||
property <length> y;
|
||||
property <length> width;
|
||||
property <length> height;
|
||||
//-default_size_binding:implicit_size
|
||||
}
|
||||
|
||||
|
@ -146,11 +139,7 @@ export FocusScope := _ {
|
|||
//-accepts_focus
|
||||
}
|
||||
|
||||
export Flickable := _ {
|
||||
property <length> x;
|
||||
property <length> y;
|
||||
property <length> width;
|
||||
property <length> height;
|
||||
export Flickable := Empty {
|
||||
// These properties are actually going to be forwarded to the viewport by the
|
||||
// code generator
|
||||
property <length> viewport-height;
|
||||
|
@ -176,11 +165,7 @@ WindowItem := _ {
|
|||
|
||||
export Window := WindowItem {}
|
||||
|
||||
export BoxShadow := _ {
|
||||
property <length> x;
|
||||
property <length> y;
|
||||
property <length> width;
|
||||
property <length> height;
|
||||
export BoxShadow := Empty {
|
||||
property <length> border_radius;
|
||||
property <length> offset_x;
|
||||
property <length> offset_y;
|
||||
|
@ -250,11 +235,7 @@ export Opacity := _ {
|
|||
//-is_internal
|
||||
}
|
||||
|
||||
export Layer := _ {
|
||||
property <length> x;
|
||||
property <length> y;
|
||||
property <length> width;
|
||||
property <length> height;
|
||||
export Layer := Empty {
|
||||
property <bool> cache-rendering-hint;
|
||||
//-default_size_binding:expands_to_parent_geometry
|
||||
//-is_internal
|
||||
|
|
|
@ -209,6 +209,8 @@ pub fn load_builtins(register: &mut TypeRegister) {
|
|||
register.property_animation_type =
|
||||
ElementType::Builtin(natives.remove("PropertyAnimation").unwrap());
|
||||
|
||||
register.empty_type = ElementType::Builtin(natives.remove("Empty").unwrap());
|
||||
|
||||
if !diag.is_empty() {
|
||||
let vec = diag.to_string_vec();
|
||||
#[cfg(feature = "display-diagnostics")]
|
||||
|
|
|
@ -254,7 +254,11 @@ impl Component {
|
|||
root_element: Element::from_node(
|
||||
node.Element(),
|
||||
"root".into(),
|
||||
ElementType::Error,
|
||||
if node.child_text(SyntaxKind::Identifier).map_or(false, |t| t == "global") {
|
||||
ElementType::Global
|
||||
} else {
|
||||
ElementType::Error
|
||||
},
|
||||
&mut child_insertion_point,
|
||||
diag,
|
||||
tr,
|
||||
|
@ -681,13 +685,7 @@ impl Element {
|
|||
ElementType::Error
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if parent_type != ElementType::Error {
|
||||
// This should normally never happen because the parser does not allow for this
|
||||
assert!(diag.has_error());
|
||||
return ElementRc::default();
|
||||
}
|
||||
|
||||
} else if parent_type == ElementType::Global {
|
||||
// This must be a global component it can only have properties and callback
|
||||
let mut error_on = |node: &dyn Spanned, what: &str| {
|
||||
diag.push_error(format!("A global component cannot have {}", what), node);
|
||||
|
@ -700,7 +698,14 @@ impl Element {
|
|||
node.PropertyAnimation().for_each(|n| error_on(&n, "animations"));
|
||||
node.States().for_each(|n| error_on(&n, "states"));
|
||||
node.Transitions().for_each(|n| error_on(&n, "transitions"));
|
||||
|
||||
ElementType::Global
|
||||
} else if parent_type != ElementType::Error {
|
||||
// This should normally never happen because the parser does not allow for this
|
||||
assert!(diag.has_error());
|
||||
return ElementRc::default();
|
||||
} else {
|
||||
tr.empty_type()
|
||||
};
|
||||
let mut r = Element { id, base_type, node: Some(node.clone()), ..Default::default() };
|
||||
|
||||
|
@ -1158,10 +1163,11 @@ impl Element {
|
|||
match lookup_result.property_type {
|
||||
Type::Invalid => {
|
||||
if self.base_type != ElementType::Error {
|
||||
diag.push_error(format!(
|
||||
"Unknown property {} in {}",
|
||||
unresolved_name, self.base_type
|
||||
),
|
||||
diag.push_error(if self.base_type.to_string() == "Empty" {
|
||||
format!( "Unknown property {unresolved_name}")
|
||||
} else {
|
||||
format!( "Unknown property {unresolved_name} in {}", self.base_type)
|
||||
},
|
||||
&name_token);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,12 +81,17 @@ pub fn parse_component(p: &mut impl Parser) -> bool {
|
|||
return false;
|
||||
}
|
||||
} else {
|
||||
if p.peek().as_str() != "inherits" {
|
||||
p.error("Expected keyword 'inherits'");
|
||||
if p.peek().as_str() == "inherits" {
|
||||
p.consume();
|
||||
} else if p.peek().kind() == SyntaxKind::LBrace {
|
||||
let mut p = p.start_node(SyntaxKind::Element);
|
||||
p.consume();
|
||||
parse_element_content(&mut *p);
|
||||
return p.expect(SyntaxKind::RBrace);
|
||||
} else {
|
||||
p.error("Expected '{' or keyword 'inherits'");
|
||||
drop(p.start_node(SyntaxKind::Element));
|
||||
return false;
|
||||
} else {
|
||||
p.consume();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,9 +23,9 @@ pub fn is_flickable_element(element: &ElementRc) -> bool {
|
|||
}
|
||||
|
||||
pub fn handle_flickable(root_component: &Rc<Component>, tr: &TypeRegister) {
|
||||
let mut native_rect = tr.lookup_element("Rectangle").unwrap().as_builtin().native_class.clone();
|
||||
while let Some(p) = native_rect.parent.clone() {
|
||||
native_rect = p;
|
||||
let mut native_empty = tr.empty_type().as_builtin().native_class.clone();
|
||||
while let Some(p) = native_empty.parent.clone() {
|
||||
native_empty = p;
|
||||
}
|
||||
|
||||
crate::object_tree::recurse_elem_including_sub_components(
|
||||
|
@ -37,17 +37,17 @@ pub fn handle_flickable(root_component: &Rc<Component>, tr: &TypeRegister) {
|
|||
}
|
||||
|
||||
fixup_geometry(elem);
|
||||
create_viewport_element(elem, &native_rect);
|
||||
create_viewport_element(elem, &native_empty);
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn create_viewport_element(flickable_elem: &ElementRc, native_rect: &Rc<NativeClass>) {
|
||||
fn create_viewport_element(flickable_elem: &ElementRc, native_empty: &Rc<NativeClass>) {
|
||||
let mut flickable = flickable_elem.borrow_mut();
|
||||
let flickable = &mut *flickable;
|
||||
let viewport = Rc::new(RefCell::new(Element {
|
||||
id: format!("{}-viewport", flickable.id),
|
||||
base_type: ElementType::Native(native_rect.clone()),
|
||||
base_type: ElementType::Native(native_empty.clone()),
|
||||
children: std::mem::take(&mut flickable.children),
|
||||
enclosing_component: flickable.enclosing_component.clone(),
|
||||
is_flickable_viewport: true,
|
||||
|
|
|
@ -90,7 +90,7 @@ fn should_materialize(
|
|||
if property_declarations.contains_key(prop) {
|
||||
return None;
|
||||
}
|
||||
let has_declared_property = match &base_type {
|
||||
let has_declared_property = match base_type {
|
||||
ElementType::Component(c) => has_declared_property(&c.root_element.borrow(), prop),
|
||||
ElementType::Builtin(b) => b.properties.contains_key(prop),
|
||||
ElementType::Native(n) => {
|
||||
|
|
|
@ -48,6 +48,9 @@ fn can_optimize(elem: &ElementRc) -> bool {
|
|||
|
||||
let base_type = match &e.base_type {
|
||||
ElementType::Builtin(base_type) if base_type.name == "Rectangle" => base_type,
|
||||
ElementType::Builtin(base_type) if base_type.native_class.class_name == "Empty" => {
|
||||
base_type
|
||||
}
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
|
|
|
@ -128,11 +128,11 @@ fn select_minimal_class() {
|
|||
["x".to_owned(), "width".to_owned()].iter()
|
||||
)
|
||||
.class_name,
|
||||
"Rectangle",
|
||||
"Empty",
|
||||
);
|
||||
assert_eq!(
|
||||
select_minimal_class_based_on_property_usage(&rect.native_class, [].iter()).class_name,
|
||||
"Rectangle",
|
||||
"Empty",
|
||||
);
|
||||
assert_eq!(
|
||||
select_minimal_class_based_on_property_usage(
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
||||
|
||||
|
||||
component Foo {
|
||||
background: 0;
|
||||
// ^error{Unknown property background$}
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
component Bar {
|
||||
Foo { }
|
||||
Foo {
|
||||
background: 0;
|
||||
// ^error{Unknown property background in Foo}
|
||||
height: self.width;
|
||||
}
|
||||
}
|
|
@ -191,6 +191,7 @@ pub struct TypeRegister {
|
|||
elements: HashMap<String, ElementType>,
|
||||
supported_property_animation_types: HashSet<String>,
|
||||
pub(crate) property_animation_type: ElementType,
|
||||
pub(crate) empty_type: ElementType,
|
||||
/// Map from a context restricted type to the list of contexts (parent type) it is allowed in. This is
|
||||
/// used to construct helpful error messages, such as "Row can only be within a GridLayout element".
|
||||
context_restricted_types: HashMap<String, HashSet<String>>,
|
||||
|
@ -368,4 +369,11 @@ impl TypeRegister {
|
|||
}
|
||||
all
|
||||
}
|
||||
|
||||
pub fn empty_type(&self) -> ElementType {
|
||||
match self.parent_registry.as_ref() {
|
||||
Some(parent) => parent.borrow().empty_type(),
|
||||
None => self.empty_type.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue