mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 06:11:16 +00:00
More work on LLR
generate the actual tree and support a bunch more of expressions
This commit is contained in:
parent
53c3e6a279
commit
d395e92f3f
6 changed files with 907 additions and 155 deletions
|
@ -14,7 +14,7 @@ use std::rc::{Rc, Weak};
|
|||
// FIXME remove the pub
|
||||
pub use crate::namedreference::NamedReference;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
/// A function built into the run-time
|
||||
pub enum BuiltinFunction {
|
||||
GetWindowScaleFactor,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
// Copyright © SixtyFPS GmbH <info@sixtyfps.io>
|
||||
// SPDX-License-Identifier: (GPL-3.0-only OR LicenseRef-SixtyFPS-commercial)
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::langtype::Type;
|
||||
|
||||
use super::PropertyReference;
|
||||
use crate::expression_tree::{BuiltinFunction, OperatorClass};
|
||||
use crate::langtype::Type;
|
||||
use itertools::Either;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Expression {
|
||||
|
@ -64,17 +64,32 @@ pub enum Expression {
|
|||
CodeBlock(Vec<Expression>),
|
||||
|
||||
/// A function call
|
||||
FunctionCall {
|
||||
function: Box<Expression>,
|
||||
BuiltinFunctionCall {
|
||||
function: BuiltinFunction,
|
||||
arguments: Vec<Expression>,
|
||||
},
|
||||
CallBackCall {
|
||||
callback: PropertyReference,
|
||||
arguments: Vec<Expression>,
|
||||
},
|
||||
|
||||
/// A SelfAssignment or an Assignment. When op is '=' this is a signal assignment.
|
||||
SelfAssignment {
|
||||
lhs: Box<Expression>,
|
||||
rhs: Box<Expression>,
|
||||
/// '+', '-', '/', '*', or '='
|
||||
op: char,
|
||||
/// A BuiltinFunctionCall, but the function is not yet in the `BuiltinFunction` enum
|
||||
/// TODO: merge in BuiltinFunctionCall
|
||||
ExtraBuiltinFunctionCall {
|
||||
function: String,
|
||||
arguments: Vec<Expression>,
|
||||
},
|
||||
|
||||
/// An assignment of a value to a property
|
||||
PropertyAssignment {
|
||||
property: PropertyReference,
|
||||
value: Box<Expression>,
|
||||
},
|
||||
/// an assignment of a value to the model data
|
||||
ModelDataAssignment {
|
||||
// how deep in the parent hierarchy we go
|
||||
level: usize,
|
||||
value: Box<Expression>,
|
||||
},
|
||||
|
||||
BinaryExpression {
|
||||
|
@ -109,9 +124,7 @@ pub enum Expression {
|
|||
values: HashMap<String, Expression>,
|
||||
},
|
||||
|
||||
PathElements {
|
||||
elements: crate::expression_tree::PathEvents,
|
||||
},
|
||||
PathEvents(crate::expression_tree::PathEvents),
|
||||
|
||||
EasingCurve(crate::expression_tree::EasingCurve),
|
||||
|
||||
|
@ -132,55 +145,15 @@ pub enum Expression {
|
|||
/// So this looks like `layout_cache_prop[layout_cache_prop[index] + repeater_index]`
|
||||
repeater_index: Option<Box<Expression>>,
|
||||
},
|
||||
//-/ Compute the LayoutInfo for the given layout.
|
||||
//TODO
|
||||
//ComputeLayoutInfo(Layout),
|
||||
//SolveLayout(Layout),
|
||||
}
|
||||
|
||||
/*
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct LayoutConstraints {
|
||||
pub min: Option<PropertyReference>,
|
||||
pub max: Option<PropertyReference>,
|
||||
pub preferred: Option<PropertyReference>,
|
||||
pub stretch: Option<PropertyReference>,
|
||||
pub fixed: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LayoutItem {
|
||||
pos: Option<PropertyReference>,
|
||||
size: Option<PropertyReference>,
|
||||
}
|
||||
|
||||
pub struct LayoutGeometry {}
|
||||
|
||||
/// An element in a GridLayout
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GridLayoutElement {
|
||||
pub col: u16,
|
||||
pub row: u16,
|
||||
pub colspan: u16,
|
||||
pub rowspan: u16,
|
||||
pub item_horiz: LayoutItem,
|
||||
pub item_vert: LayoutItem,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Layout {
|
||||
Grid {
|
||||
/// All the elements will be layout within that element.
|
||||
elems: Vec<GridLayoutElement>,
|
||||
|
||||
geometry: LayoutGeometry,
|
||||
|
||||
/// When this GridLyout is actually the layout of a Dialog, then the cells start with all the buttons,
|
||||
/// and this variable contains their roles. The string is actually one of the values from the sixtyfps_corelib::layout::DialogButtonRole
|
||||
dialog_button_roles: Option<Vec<String>>,
|
||||
/// Generate the array of BoxLayoutCellData form elements
|
||||
BoxLayoutCellDataArray {
|
||||
/// Either an expression of type BoxLayoutCellData, or an index to the repeater
|
||||
elements: Vec<Either<Expression, usize>>,
|
||||
/// The name for the local variable that stores the repeater indices
|
||||
/// In other word, this expression has side effect and change that
|
||||
repeater_indices: Option<String>,
|
||||
},
|
||||
}
|
||||
*/
|
||||
|
||||
impl Expression {
|
||||
pub fn default_value_for_type(ty: &Type) -> Option<Self> {
|
||||
|
@ -213,7 +186,7 @@ impl Expression {
|
|||
},
|
||||
Type::Bool => Expression::BoolLiteral(false),
|
||||
Type::Model => return None,
|
||||
Type::PathElements => Expression::PathElements { elements: Default::default() },
|
||||
Type::PathElements => Expression::PathEvents(Default::default()),
|
||||
Type::Array(element_ty) => {
|
||||
Expression::Array { element_ty: (**element_ty).clone(), values: vec![] }
|
||||
}
|
||||
|
@ -234,4 +207,51 @@ impl Expression {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn ty(&self) -> Type {
|
||||
match self {
|
||||
Self::StringLiteral(_) => Type::String,
|
||||
Self::NumberLiteral(_) => Type::Float32,
|
||||
Self::BoolLiteral(_) => Type::Bool,
|
||||
Self::PropertyReference(_) => todo!(),
|
||||
Self::FunctionParameterReference { .. } => todo!(),
|
||||
Self::StoreLocalVariable { .. } => Type::Void,
|
||||
Self::ReadLocalVariable { ty, .. } => ty.clone(),
|
||||
Self::StructFieldAccess { base, name } => match base.ty() {
|
||||
Type::Struct { fields, .. } => fields[name].clone(),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Self::Cast { to, .. } => to.clone(),
|
||||
Self::CodeBlock(sub) => sub.last().map_or(Type::Void, |e| e.ty()),
|
||||
Self::BuiltinFunctionCall { function, .. } => match function.ty() {
|
||||
Type::Function { return_type, .. } => *return_type,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Self::CallBackCall { .. } => todo!(),
|
||||
Self::ExtraBuiltinFunctionCall { .. } => todo!(),
|
||||
Self::PropertyAssignment { .. } => Type::Void,
|
||||
Self::ModelDataAssignment { .. } => Type::Void,
|
||||
Self::BinaryExpression { lhs, rhs: _, op } => {
|
||||
if crate::expression_tree::operator_class(*op) != OperatorClass::ArithmeticOp {
|
||||
Type::Bool
|
||||
} else {
|
||||
lhs.ty()
|
||||
}
|
||||
}
|
||||
Self::UnaryOp { sub, .. } => sub.ty(),
|
||||
Self::ImageReference { .. } => Type::Image,
|
||||
Self::Condition { true_expr, .. } => true_expr.ty(),
|
||||
Self::Array { element_ty, .. } => Type::Array(element_ty.clone().into()),
|
||||
Self::Struct { ty, .. } => ty.clone(),
|
||||
Self::PathEvents { .. } => todo!(),
|
||||
Self::EasingCurve(_) => Type::Easing,
|
||||
Self::LinearGradient { .. } => Type::Brush,
|
||||
Self::EnumerationValue(e) => Type::Enumeration(e.enumeration.clone()),
|
||||
Self::ReturnStatement(_) => Type::Invalid,
|
||||
Self::LayoutCacheAccess { .. } => crate::layout::layout_info_type(),
|
||||
Self::BoxLayoutCellDataArray { .. } => {
|
||||
Type::Array(Box::new(crate::layout::layout_info_type()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,31 +1,34 @@
|
|||
// Copyright © SixtyFPS GmbH <info@sixtyfps.io>
|
||||
// SPDX-License-Identifier: (GPL-3.0-only OR LicenseRef-SixtyFPS-commercial)
|
||||
|
||||
use std::collections::HashMap;
|
||||
use super::Expression;
|
||||
use crate::langtype::{NativeClass, Type};
|
||||
use std::collections::BTreeMap;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::langtype::Type;
|
||||
|
||||
use super::Expression;
|
||||
|
||||
// Index in the `SubComponent::properties`
|
||||
pub type PropertyIndex = usize;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Animation {
|
||||
/// The expression is a Struct with the animation fields
|
||||
Static(Expression),
|
||||
Transition(Expression),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BindingExpression {
|
||||
pub expression: Expression,
|
||||
pub animation: Option<Animation>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GlobalComponent {
|
||||
pub name: String,
|
||||
pub properties: Vec<Property>,
|
||||
pub init_values: Vec<Option<Expression>>,
|
||||
pub const_properties: Vec<bool>,
|
||||
}
|
||||
|
||||
/// a Reference to a property, in the context of a SubComponent
|
||||
|
@ -41,12 +44,14 @@ pub enum PropertyReference {
|
|||
Global { global_index: usize, property_index: usize },
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Property {
|
||||
pub name: String,
|
||||
pub ty: Type,
|
||||
//pub binding: Option<BindingExpression>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RepeatedElement {
|
||||
pub model: Expression,
|
||||
/// Within the sub_tree's root component
|
||||
|
@ -56,41 +61,52 @@ pub struct RepeatedElement {
|
|||
pub sub_tree: ItemTree,
|
||||
}
|
||||
|
||||
pub struct ItemType {
|
||||
// cpp_name: String,
|
||||
// rust_name: String,
|
||||
// cpp_init_function: String,
|
||||
// mouse_function: String,
|
||||
// extra_data_type: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Item {
|
||||
pub ty: Rc<ItemType>,
|
||||
pub ty: Rc<NativeClass>,
|
||||
pub name: String,
|
||||
/// When this is true, this item does not need to be created because it is
|
||||
/// already in the flickable.
|
||||
/// The Item::name is the same as the flickable, and ty is Rectangle
|
||||
pub is_flickable_viewport: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TreeNode {
|
||||
pub sub_component_path: Vec<usize>,
|
||||
pub item_index: usize,
|
||||
pub repeated: bool,
|
||||
pub children: Vec<TreeNode>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SubComponent {
|
||||
pub name: String,
|
||||
pub properties: Vec<Property>,
|
||||
pub items: Vec<Item>,
|
||||
pub repeated: Vec<RepeatedElement>,
|
||||
pub popup_windows: Vec<ItemTree>,
|
||||
pub sub_components: Vec<SubComponentInstance>,
|
||||
pub property_init: Vec<(PropertyReference, BindingExpression)>,
|
||||
pub two_way_bindings: Vec<(PropertyReference, PropertyReference)>,
|
||||
pub const_properties: Vec<PropertyReference>,
|
||||
}
|
||||
|
||||
pub struct SubComponentInstance {
|
||||
pub ty: Rc<SubComponent>,
|
||||
pub name: String,
|
||||
//pub property_values: Vec<(PropertyReference, BindingExpression)>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for SubComponentInstance {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.ty.name)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ItemTree {
|
||||
pub root: SubComponentInstance,
|
||||
pub root: SubComponent,
|
||||
pub tree: TreeNode,
|
||||
/// This tree has a parent. e.g: it is a Repeater or a PopupMenu whose property can access
|
||||
/// the parent ItemTree.
|
||||
|
@ -98,8 +114,10 @@ pub struct ItemTree {
|
|||
pub parent_context: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PublicComponent {
|
||||
pub public_properties: BTreeMap<String, (Type, PropertyReference)>,
|
||||
pub item_tree: ItemTree,
|
||||
pub sub_components: HashMap<String, Rc<SubComponent>>,
|
||||
pub sub_components: BTreeMap<String, Rc<SubComponent>>,
|
||||
pub globals: Vec<GlobalComponent>,
|
||||
}
|
||||
|
|
|
@ -2,13 +2,17 @@
|
|||
// SPDX-License-Identifier: (GPL-3.0-only OR LicenseRef-SixtyFPS-commercial)
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::num::NonZeroUsize;
|
||||
use std::rc::{Rc, Weak};
|
||||
|
||||
use super::lower_to_item_tree::{LoweredSubComponentMapping, LoweringState};
|
||||
use itertools::Either;
|
||||
|
||||
use super::lower_to_item_tree::{LoweredElement, LoweredSubComponentMapping, LoweringState};
|
||||
use super::{Animation, PropertyReference};
|
||||
use crate::expression_tree::Expression as tree_Expression;
|
||||
use crate::langtype::Type;
|
||||
use crate::expression_tree::{BuiltinFunction, Expression as tree_Expression};
|
||||
use crate::langtype::{EnumerationValue, Type};
|
||||
use crate::layout::Orientation;
|
||||
use crate::llr::Expression as llr_Expression;
|
||||
use crate::namedreference::NamedReference;
|
||||
use crate::object_tree::{Element, ElementRc, PropertyAnimation};
|
||||
|
@ -21,11 +25,7 @@ pub struct ExpressionContext<'a> {
|
|||
}
|
||||
|
||||
impl ExpressionContext<'_> {
|
||||
pub fn map_property_reference(
|
||||
&self,
|
||||
from: &NamedReference,
|
||||
state: &LoweringState,
|
||||
) -> Option<PropertyReference> {
|
||||
pub fn map_property_reference(&self, from: &NamedReference) -> Option<PropertyReference> {
|
||||
let element = from.element();
|
||||
let enclosing = &element.borrow().enclosing_component.upgrade().unwrap();
|
||||
if !enclosing.is_global() {
|
||||
|
@ -36,13 +36,15 @@ impl ExpressionContext<'_> {
|
|||
level += 1;
|
||||
}
|
||||
if let Some(level) = NonZeroUsize::new(level) {
|
||||
PropertyReference::InParent {
|
||||
return Some(PropertyReference::InParent {
|
||||
level,
|
||||
parent_reference: Box::new(map.mapping.map_property_reference(from, state)?),
|
||||
};
|
||||
parent_reference: Box::new(
|
||||
map.mapping.map_property_reference(from, self.state)?,
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
self.mapping.map_property_reference(from, state)
|
||||
self.mapping.map_property_reference(from, self.state)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,20 +54,34 @@ pub fn lower_expression(
|
|||
) -> Option<llr_Expression> {
|
||||
match expression {
|
||||
tree_Expression::Invalid => None,
|
||||
tree_Expression::Uncompiled(_) => None,
|
||||
tree_Expression::Uncompiled(_) => panic!(),
|
||||
tree_Expression::StringLiteral(s) => Some(llr_Expression::StringLiteral(s.clone())),
|
||||
tree_Expression::NumberLiteral(n, _) => Some(llr_Expression::NumberLiteral(*n)),
|
||||
tree_Expression::NumberLiteral(n, unit) => {
|
||||
Some(llr_Expression::NumberLiteral(unit.normalize(*n)))
|
||||
}
|
||||
tree_Expression::BoolLiteral(b) => Some(llr_Expression::BoolLiteral(*b)),
|
||||
tree_Expression::CallbackReference(nr) => Some(llr_Expression::PropertyReference(
|
||||
ctx.mapping.map_property_reference(nr, ctx.state)?,
|
||||
)),
|
||||
tree_Expression::PropertyReference(nr) => Some(llr_Expression::PropertyReference(
|
||||
ctx.mapping.map_property_reference(nr, ctx.state)?,
|
||||
)),
|
||||
tree_Expression::BuiltinFunctionReference(_, _) => todo!(),
|
||||
tree_Expression::MemberFunction { .. } => None,
|
||||
tree_Expression::BuiltinMacroReference(_, _) => None,
|
||||
tree_Expression::ElementReference(_) => todo!(),
|
||||
tree_Expression::CallbackReference(nr) => {
|
||||
Some(llr_Expression::PropertyReference(ctx.map_property_reference(nr)?))
|
||||
}
|
||||
tree_Expression::PropertyReference(nr) => {
|
||||
Some(llr_Expression::PropertyReference(ctx.map_property_reference(nr)?))
|
||||
}
|
||||
tree_Expression::BuiltinFunctionReference(_, _) => panic!(),
|
||||
tree_Expression::MemberFunction { .. } => panic!(),
|
||||
tree_Expression::BuiltinMacroReference(_, _) => panic!(),
|
||||
tree_Expression::ElementReference(e) => {
|
||||
// We map an element reference to a reference to the property "" inside that native item
|
||||
Some(llr_Expression::PropertyReference(
|
||||
ctx.mapping
|
||||
.map_property_reference(
|
||||
&NamedReference::new(&e.upgrade().unwrap(), ""),
|
||||
ctx.state,
|
||||
)
|
||||
.expect(
|
||||
"this should be a reference to a native item and it should always exist",
|
||||
),
|
||||
))
|
||||
}
|
||||
tree_Expression::RepeaterIndexReference { element } => {
|
||||
repeater_special_property(element, ctx.component, 1)
|
||||
}
|
||||
|
@ -97,20 +113,26 @@ pub fn lower_expression(
|
|||
tree_Expression::CodeBlock(expr) => Some(llr_Expression::CodeBlock(
|
||||
expr.iter().map(|e| lower_expression(e, ctx)).collect::<Option<_>>()?,
|
||||
)),
|
||||
tree_Expression::FunctionCall { function, arguments, .. } => {
|
||||
Some(llr_Expression::FunctionCall {
|
||||
function: Box::new(lower_expression(function, ctx)?),
|
||||
arguments: arguments
|
||||
.iter()
|
||||
.map(|e| lower_expression(e, ctx))
|
||||
.collect::<Option<_>>()?,
|
||||
tree_Expression::FunctionCall { function, arguments, .. } => match &**function {
|
||||
tree_Expression::BuiltinFunctionReference(BuiltinFunction::ShowPopupWindow, _) => {
|
||||
lower_show_popup(arguments, ctx)
|
||||
}
|
||||
tree_Expression::BuiltinFunctionReference(f, _) => {
|
||||
let arguments =
|
||||
arguments.iter().map(|e| lower_expression(e, ctx)).collect::<Option<_>>()?;
|
||||
Some(llr_Expression::BuiltinFunctionCall { function: *f, arguments })
|
||||
}
|
||||
tree_Expression::CallbackReference(nr) => {
|
||||
let arguments =
|
||||
arguments.iter().map(|e| lower_expression(e, ctx)).collect::<Option<_>>()?;
|
||||
Some(llr_Expression::CallBackCall {
|
||||
callback: ctx.map_property_reference(nr)?,
|
||||
arguments,
|
||||
})
|
||||
}
|
||||
tree_Expression::SelfAssignment { lhs, rhs, op } => Some(llr_Expression::SelfAssignment {
|
||||
lhs: Box::new(lower_expression(lhs, ctx)?),
|
||||
rhs: Box::new(lower_expression(rhs, ctx)?),
|
||||
op: *op,
|
||||
}),
|
||||
_ => panic!("not calling a function"),
|
||||
},
|
||||
tree_Expression::SelfAssignment { lhs, rhs, op } => lower_assignment(lhs, rhs, *op, ctx),
|
||||
tree_Expression::BinaryExpression { lhs, rhs, op } => {
|
||||
Some(llr_Expression::BinaryExpression {
|
||||
lhs: Box::new(lower_expression(lhs, ctx)?),
|
||||
|
@ -142,10 +164,7 @@ pub fn lower_expression(
|
|||
.map(|(s, e)| Some((s.clone(), lower_expression(e, ctx)?)))
|
||||
.collect::<Option<_>>()?,
|
||||
}),
|
||||
tree_Expression::PathElements { elements } => match elements {
|
||||
crate::expression_tree::Path::Elements(_) => todo!(),
|
||||
crate::expression_tree::Path::Events(_) => todo!(),
|
||||
},
|
||||
tree_Expression::PathElements { elements } => compile_path(elements, ctx),
|
||||
tree_Expression::EasingCurve(x) => Some(llr_Expression::EasingCurve(x.clone())),
|
||||
tree_Expression::LinearGradient { angle, stops } => Some(llr_Expression::LinearGradient {
|
||||
angle: Box::new(lower_expression(angle, ctx)?),
|
||||
|
@ -170,8 +189,98 @@ pub fn lower_expression(
|
|||
.map(Box::new),
|
||||
})
|
||||
}
|
||||
tree_Expression::ComputeLayoutInfo(_, _) => todo!(),
|
||||
tree_Expression::SolveLayout(_, _) => todo!(),
|
||||
tree_Expression::ComputeLayoutInfo(l, o) => compute_layout_info(l, *o, ctx),
|
||||
tree_Expression::SolveLayout(l, o) => solve_layout(l, *o, ctx),
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_assignment(
|
||||
lhs: &tree_Expression,
|
||||
rhs: &tree_Expression,
|
||||
op: char,
|
||||
ctx: &ExpressionContext,
|
||||
) -> Option<llr_Expression> {
|
||||
match lhs {
|
||||
tree_Expression::PropertyReference(nr) => {
|
||||
let rhs = lower_expression(rhs, ctx)?;
|
||||
let property = ctx.map_property_reference(nr)?;
|
||||
let value = if op == '=' {
|
||||
rhs
|
||||
} else {
|
||||
llr_Expression::BinaryExpression {
|
||||
lhs: llr_Expression::PropertyReference(property.clone()).into(),
|
||||
rhs: rhs.into(),
|
||||
op,
|
||||
}
|
||||
}
|
||||
.into();
|
||||
Some(llr_Expression::PropertyAssignment { property, value })
|
||||
}
|
||||
tree_Expression::StructFieldAccess { base, name } => {
|
||||
let ty = base.ty();
|
||||
|
||||
static COUNT: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
|
||||
let unique_name = format!(
|
||||
"struct_assignment{}",
|
||||
COUNT.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
|
||||
);
|
||||
let s = tree_Expression::StoreLocalVariable {
|
||||
name: unique_name.clone(),
|
||||
value: base.clone(),
|
||||
};
|
||||
let lower_base =
|
||||
tree_Expression::ReadLocalVariable { name: unique_name, ty: ty.clone() };
|
||||
let mut values = HashMap::new();
|
||||
match &ty {
|
||||
Type::Struct { fields, .. } => {
|
||||
for (field, _) in fields {
|
||||
let e = if field != name {
|
||||
tree_Expression::StructFieldAccess {
|
||||
base: lower_base.clone().into(),
|
||||
name: field.clone(),
|
||||
}
|
||||
} else if op == '=' {
|
||||
rhs.clone()
|
||||
} else {
|
||||
tree_Expression::BinaryExpression {
|
||||
lhs: tree_Expression::StructFieldAccess {
|
||||
base: lower_base.clone().into(),
|
||||
name: field.clone(),
|
||||
}
|
||||
.into(),
|
||||
rhs: Box::new(rhs.clone()),
|
||||
op,
|
||||
}
|
||||
};
|
||||
values.insert(field.clone(), e);
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
let new_value =
|
||||
tree_Expression::CodeBlock(vec![s, tree_Expression::Struct { ty, values }]);
|
||||
lower_assignment(base, &new_value, '=', ctx)
|
||||
}
|
||||
tree_Expression::RepeaterModelReference { element } => {
|
||||
let rhs = lower_expression(rhs, ctx)?;
|
||||
let prop = repeater_special_property(element, ctx.component, 0)?;
|
||||
|
||||
let level = match &prop {
|
||||
llr_Expression::PropertyReference(PropertyReference::InParent {
|
||||
level, ..
|
||||
}) => (*level).into(),
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
let value = Box::new(if op == '=' {
|
||||
rhs
|
||||
} else {
|
||||
llr_Expression::BinaryExpression { lhs: prop.into(), rhs: rhs.into(), op }
|
||||
});
|
||||
|
||||
Some(llr_Expression::ModelDataAssignment { level, value })
|
||||
}
|
||||
_ => panic!("not a rvalue"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,6 +310,39 @@ fn repeater_special_property(
|
|||
Some(llr_Expression::PropertyReference(r))
|
||||
}
|
||||
|
||||
fn lower_show_popup(args: &[tree_Expression], ctx: &ExpressionContext) -> Option<llr_Expression> {
|
||||
if let [tree_Expression::ElementReference(e)] = args {
|
||||
let popup_window = e.upgrade().unwrap();
|
||||
let pop_comp = popup_window.borrow().enclosing_component.upgrade().unwrap();
|
||||
let parent_component = pop_comp
|
||||
.parent_element
|
||||
.upgrade()
|
||||
.unwrap()
|
||||
.borrow()
|
||||
.enclosing_component
|
||||
.upgrade()
|
||||
.unwrap();
|
||||
let popup_list = parent_component.popup_windows.borrow();
|
||||
let (popup_index, popup) = popup_list
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, p)| Rc::ptr_eq(&p.component, &pop_comp))
|
||||
.unwrap();
|
||||
let x = llr_Expression::PropertyReference(ctx.map_property_reference(&popup.x)?);
|
||||
let y = llr_Expression::PropertyReference(ctx.map_property_reference(&popup.y)?);
|
||||
let item_ref = lower_expression(
|
||||
&tree_Expression::ElementReference(Rc::downgrade(&popup.parent_element)),
|
||||
ctx,
|
||||
)?;
|
||||
Some(llr_Expression::BuiltinFunctionCall {
|
||||
function: BuiltinFunction::ShowPopupWindow,
|
||||
arguments: vec![llr_Expression::NumberLiteral(popup_index as _), x, y, item_ref],
|
||||
})
|
||||
} else {
|
||||
panic!("invalid arguments to ShowPopupWindow");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lower_animation(a: &PropertyAnimation, ctx: &ExpressionContext<'_>) -> Option<Animation> {
|
||||
fn lower_animation_element(
|
||||
a: &ElementRc,
|
||||
|
@ -256,3 +398,458 @@ pub fn lower_animation(a: &PropertyAnimation, ctx: &ExpressionContext<'_>) -> Op
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_layout_info(
|
||||
l: &crate::layout::Layout,
|
||||
o: Orientation,
|
||||
ctx: &ExpressionContext,
|
||||
) -> Option<llr_Expression> {
|
||||
match l {
|
||||
crate::layout::Layout::GridLayout(layout) => {
|
||||
let (padding, spacing) = generate_layout_padding_and_spacing(&layout.geometry, o, ctx)?;
|
||||
let cells = grid_layout_cell_data(layout, o, ctx)?;
|
||||
Some(llr_Expression::ExtraBuiltinFunctionCall {
|
||||
function: "grid_layout_info".into(),
|
||||
arguments: vec![cells, spacing, padding],
|
||||
})
|
||||
}
|
||||
crate::layout::Layout::BoxLayout(layout) => {
|
||||
let (padding, spacing) = generate_layout_padding_and_spacing(&layout.geometry, o, ctx)?;
|
||||
let (cells, alignment) = box_layout_data(layout, o, ctx, None)?;
|
||||
if o == layout.orientation {
|
||||
Some(llr_Expression::ExtraBuiltinFunctionCall {
|
||||
function: "box_layout_info".into(),
|
||||
arguments: vec![cells, spacing, padding, alignment],
|
||||
})
|
||||
} else {
|
||||
Some(llr_Expression::ExtraBuiltinFunctionCall {
|
||||
function: "box_layout_info_ortho".into(),
|
||||
arguments: vec![cells, padding],
|
||||
})
|
||||
}
|
||||
}
|
||||
crate::layout::Layout::PathLayout(_) => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn solve_layout(
|
||||
l: &crate::layout::Layout,
|
||||
o: Orientation,
|
||||
ctx: &ExpressionContext,
|
||||
) -> Option<llr_Expression> {
|
||||
match l {
|
||||
crate::layout::Layout::GridLayout(layout) => {
|
||||
let (padding, spacing) = generate_layout_padding_and_spacing(&layout.geometry, o, ctx)?;
|
||||
let cells = grid_layout_cell_data(layout, o, ctx)?;
|
||||
let size = layout_geometry_size(&layout.geometry.rect, o, ctx)?;
|
||||
if let (Some(button_roles), Orientation::Horizontal) = (&layout.dialog_button_roles, o)
|
||||
{
|
||||
let cells_ty = cells.ty();
|
||||
let e = crate::typeregister::DIALOG_BUTTON_ROLE_ENUM.with(|e| e.clone());
|
||||
let roles = button_roles
|
||||
.iter()
|
||||
.map(|r| {
|
||||
llr_Expression::EnumerationValue(EnumerationValue {
|
||||
value: e.values.iter().position(|x| x == r).unwrap() as _,
|
||||
enumeration: e.clone(),
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
Some(llr_Expression::CodeBlock(vec![
|
||||
llr_Expression::StoreLocalVariable {
|
||||
name: "cells".into(),
|
||||
value: Box::new(cells),
|
||||
},
|
||||
llr_Expression::ExtraBuiltinFunctionCall {
|
||||
function: "reorder_dialog_button_layout".into(),
|
||||
arguments: vec![
|
||||
llr_Expression::ReadLocalVariable {
|
||||
name: "cells".into(),
|
||||
ty: cells_ty.clone(),
|
||||
},
|
||||
llr_Expression::Array {
|
||||
element_ty: Type::Enumeration(e),
|
||||
values: roles,
|
||||
},
|
||||
],
|
||||
},
|
||||
llr_Expression::ExtraBuiltinFunctionCall {
|
||||
function: "solve_grid_layout".into(),
|
||||
arguments: vec![make_struct(
|
||||
"GridLayoutData".into(),
|
||||
[
|
||||
("size", Type::Float32, size),
|
||||
("spacing", Type::Float32, spacing),
|
||||
("padding", padding.ty(), padding),
|
||||
(
|
||||
"cells",
|
||||
cells_ty.clone(),
|
||||
llr_Expression::ReadLocalVariable {
|
||||
name: "cells".into(),
|
||||
ty: cells_ty,
|
||||
},
|
||||
),
|
||||
],
|
||||
)],
|
||||
},
|
||||
]))
|
||||
} else {
|
||||
Some(llr_Expression::ExtraBuiltinFunctionCall {
|
||||
function: "solve_grid_layout".into(),
|
||||
arguments: vec![make_struct(
|
||||
"GridLayoutData".into(),
|
||||
[
|
||||
("size", Type::Float32, size),
|
||||
("spacing", Type::Float32, spacing),
|
||||
("padding", padding.ty(), padding),
|
||||
("cells", cells.ty(), cells),
|
||||
],
|
||||
)],
|
||||
})
|
||||
}
|
||||
}
|
||||
crate::layout::Layout::BoxLayout(layout) => {
|
||||
let (padding, spacing) = generate_layout_padding_and_spacing(&layout.geometry, o, ctx)?;
|
||||
let mut repeated_indices = String::new();
|
||||
let (cells, alignment) = box_layout_data(layout, o, ctx, Some(&mut repeated_indices))?;
|
||||
let size = layout_geometry_size(&layout.geometry.rect, o, ctx)?;
|
||||
let data = make_struct(
|
||||
"BoxLayoutData".into(),
|
||||
[
|
||||
("size", Type::Float32, size),
|
||||
("spacing", Type::Float32, spacing),
|
||||
("padding", padding.ty(), padding),
|
||||
(
|
||||
"alignment",
|
||||
crate::typeregister::LAYOUT_ALIGNMENT_ENUM
|
||||
.with(|e| Type::Enumeration(e.clone())),
|
||||
alignment,
|
||||
),
|
||||
("cells", cells.ty(), cells),
|
||||
],
|
||||
);
|
||||
if repeated_indices.is_empty() {
|
||||
Some(llr_Expression::ExtraBuiltinFunctionCall {
|
||||
function: "solve_grid_layout".into(),
|
||||
arguments: vec![
|
||||
data,
|
||||
llr_Expression::Array { element_ty: Type::Int32, values: vec![] },
|
||||
],
|
||||
})
|
||||
} else {
|
||||
Some(llr_Expression::CodeBlock(vec![
|
||||
llr_Expression::StoreLocalVariable {
|
||||
name: repeated_indices.clone(),
|
||||
value: llr_Expression::Array { element_ty: Type::Int32, values: vec![] }
|
||||
.into(),
|
||||
},
|
||||
llr_Expression::ExtraBuiltinFunctionCall {
|
||||
function: "solve_grid_layout".into(),
|
||||
arguments: vec![
|
||||
data,
|
||||
llr_Expression::ReadLocalVariable {
|
||||
name: repeated_indices,
|
||||
ty: Type::Array(Type::Int32.into()),
|
||||
},
|
||||
],
|
||||
},
|
||||
]))
|
||||
}
|
||||
}
|
||||
crate::layout::Layout::PathLayout(layout) => {
|
||||
let width = layout_geometry_size(&layout.rect, Orientation::Horizontal, ctx)?;
|
||||
let height = layout_geometry_size(&layout.rect, Orientation::Vertical, ctx)?;
|
||||
let elements = compile_path(&layout.path, ctx)?;
|
||||
let offset = if let Some(expr) = &layout.offset_reference {
|
||||
llr_Expression::PropertyReference(ctx.map_property_reference(expr)?)
|
||||
} else {
|
||||
llr_Expression::NumberLiteral(0.)
|
||||
};
|
||||
|
||||
let count = layout.elements.len(); // FIXME! repeater
|
||||
Some(llr_Expression::ExtraBuiltinFunctionCall {
|
||||
function: "solve_path_layout".into(),
|
||||
arguments: vec![make_struct(
|
||||
"PathLayoutData".into(),
|
||||
[
|
||||
("width", Type::Float32, width),
|
||||
("height", Type::Float32, height),
|
||||
("x", Type::Float32, llr_Expression::NumberLiteral(0.)),
|
||||
("y", Type::Float32, llr_Expression::NumberLiteral(0.)),
|
||||
("elements", elements.ty(), elements),
|
||||
("offset", Type::Int32, offset),
|
||||
("item_count", Type::Int32, llr_Expression::NumberLiteral(count as _)),
|
||||
],
|
||||
)],
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn box_layout_data(
|
||||
layout: &crate::layout::BoxLayout,
|
||||
orientation: Orientation,
|
||||
ctx: &ExpressionContext,
|
||||
repeater_indices: Option<&mut String>,
|
||||
) -> Option<(llr_Expression, llr_Expression)> {
|
||||
let alignment = if let Some(expr) = &layout.geometry.alignment {
|
||||
llr_Expression::PropertyReference(ctx.map_property_reference(expr)?)
|
||||
} else {
|
||||
let e = crate::typeregister::LAYOUT_ALIGNMENT_ENUM.with(|e| e.clone());
|
||||
llr_Expression::EnumerationValue(EnumerationValue {
|
||||
value: e.default_value,
|
||||
enumeration: e,
|
||||
})
|
||||
};
|
||||
|
||||
let repeater_count =
|
||||
layout.elems.iter().filter(|i| i.element.borrow().repeated.is_some()).count();
|
||||
|
||||
let element_ty = Type::Struct {
|
||||
fields: IntoIterator::into_iter([(
|
||||
"constraint".to_string(),
|
||||
crate::layout::layout_info_type(),
|
||||
)])
|
||||
.collect(),
|
||||
name: Some("BoxLayoutCellData".into()),
|
||||
node: None,
|
||||
};
|
||||
|
||||
if repeater_count == 0 {
|
||||
let cells = llr_Expression::Array {
|
||||
values: layout
|
||||
.elems
|
||||
.iter()
|
||||
.map(|li| {
|
||||
let layout_info =
|
||||
get_layout_info(&li.element, ctx, &li.constraints, orientation).unwrap();
|
||||
make_struct(
|
||||
"BoxLayoutCellData".into(),
|
||||
[("constraint", crate::layout::layout_info_type(), layout_info)],
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
element_ty,
|
||||
};
|
||||
Some((cells, alignment))
|
||||
} else {
|
||||
let mut elements = vec![];
|
||||
for item in &layout.elems {
|
||||
if item.element.borrow().repeated.is_some() {
|
||||
let repeater_index =
|
||||
match ctx.mapping.element_mapping.get(&item.element.clone().into()).unwrap() {
|
||||
LoweredElement::Repeated { repeated_index } => *repeated_index,
|
||||
_ => panic!(),
|
||||
};
|
||||
elements.push(Either::Right(repeater_index))
|
||||
} else {
|
||||
let layout_info =
|
||||
get_layout_info(&item.element, ctx, &item.constraints, orientation).unwrap();
|
||||
elements.push(Either::Left(make_struct(
|
||||
"BoxLayoutCellData".into(),
|
||||
[("constraint", crate::layout::layout_info_type(), layout_info)],
|
||||
)));
|
||||
}
|
||||
}
|
||||
Some((
|
||||
llr_Expression::BoxLayoutCellDataArray {
|
||||
elements,
|
||||
repeater_indices: repeater_indices.map(|ri| {
|
||||
*ri = "repeater_indices".into();
|
||||
(*ri).clone()
|
||||
}),
|
||||
},
|
||||
alignment,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn grid_layout_cell_data(
|
||||
layout: &crate::layout::GridLayout,
|
||||
orientation: Orientation,
|
||||
ctx: &ExpressionContext,
|
||||
) -> Option<llr_Expression> {
|
||||
Some(llr_Expression::Array {
|
||||
element_ty: Type::Struct {
|
||||
fields: IntoIterator::into_iter([
|
||||
("col_or_row".to_string(), Type::Int32),
|
||||
("span".to_string(), Type::Int32),
|
||||
("constraint".to_string(), crate::layout::layout_info_type()),
|
||||
])
|
||||
.collect(),
|
||||
name: Some("GridLayoutCellData".into()),
|
||||
node: None,
|
||||
},
|
||||
values: layout
|
||||
.elems
|
||||
.iter()
|
||||
.map(|c| {
|
||||
let (col_or_row, span) = c.col_or_row_and_span(orientation);
|
||||
let layout_info =
|
||||
get_layout_info(&c.item.element, ctx, &c.item.constraints, orientation)
|
||||
.unwrap();
|
||||
|
||||
make_struct(
|
||||
"BoxLayoutCellData".into(),
|
||||
[
|
||||
("constraint", crate::layout::layout_info_type(), layout_info),
|
||||
("col_or_row", Type::Int32, llr_Expression::NumberLiteral(col_or_row as _)),
|
||||
("span", Type::Int32, llr_Expression::NumberLiteral(span as _)),
|
||||
],
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
|
||||
fn generate_layout_padding_and_spacing(
|
||||
layout_geometry: &crate::layout::LayoutGeometry,
|
||||
orientation: Orientation,
|
||||
ctx: &ExpressionContext,
|
||||
) -> Option<(llr_Expression, llr_Expression)> {
|
||||
let padding_prop = |expr| {
|
||||
Some(if let Some(expr) = expr {
|
||||
llr_Expression::PropertyReference(ctx.map_property_reference(expr)?)
|
||||
} else {
|
||||
llr_Expression::NumberLiteral(0.)
|
||||
})
|
||||
};
|
||||
let spacing = padding_prop(layout_geometry.spacing.as_ref())?;
|
||||
let (begin, end) = layout_geometry.padding.begin_end(orientation);
|
||||
|
||||
let padding = make_struct(
|
||||
"Padding".into(),
|
||||
[
|
||||
("begin", Type::Float32, padding_prop(begin)?),
|
||||
("end", Type::Float32, padding_prop(end)?),
|
||||
],
|
||||
);
|
||||
|
||||
Some((padding, spacing))
|
||||
}
|
||||
|
||||
fn layout_geometry_size(
|
||||
rect: &crate::layout::LayoutRect,
|
||||
orientation: Orientation,
|
||||
ctx: &ExpressionContext,
|
||||
) -> Option<llr_Expression> {
|
||||
match rect.size_reference(orientation) {
|
||||
Some(nr) => Some(llr_Expression::PropertyReference(ctx.map_property_reference(nr)?)),
|
||||
None => Some(llr_Expression::NumberLiteral(0.)),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_layout_info(
|
||||
elem: &ElementRc,
|
||||
ctx: &ExpressionContext,
|
||||
constraints: &crate::layout::LayoutConstraints,
|
||||
orientation: Orientation,
|
||||
) -> Option<llr_Expression> {
|
||||
let layout_info = if let Some(layout_info_prop) = &elem.borrow().layout_info_prop(orientation) {
|
||||
llr_Expression::PropertyReference(ctx.map_property_reference(layout_info_prop)?)
|
||||
} else {
|
||||
lower_expression(&crate::layout::implicit_layout_info_call(elem, orientation), ctx)?
|
||||
};
|
||||
|
||||
if constraints.has_explicit_restrictions() {
|
||||
llr_Expression::StoreLocalVariable {
|
||||
name: "layout_info".into(),
|
||||
value: layout_info.into(),
|
||||
};
|
||||
let ty = crate::layout::layout_info_type();
|
||||
let fields = match &ty {
|
||||
Type::Struct { fields, .. } => fields,
|
||||
_ => panic!(),
|
||||
};
|
||||
let mut values = fields
|
||||
.keys()
|
||||
.map(|p| {
|
||||
(
|
||||
p.clone(),
|
||||
llr_Expression::StructFieldAccess {
|
||||
base: llr_Expression::ReadLocalVariable {
|
||||
name: "layout_info".into(),
|
||||
ty: ty.clone(),
|
||||
}
|
||||
.into(),
|
||||
name: p.clone(),
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
for (nr, s) in constraints.for_each_restrictions(orientation) {
|
||||
values.insert(
|
||||
s.into(),
|
||||
llr_Expression::PropertyReference(ctx.map_property_reference(nr)?),
|
||||
);
|
||||
}
|
||||
Some(llr_Expression::Struct { ty, values })
|
||||
} else {
|
||||
Some(layout_info)
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_path(
|
||||
path: &crate::expression_tree::Path,
|
||||
ctx: &ExpressionContext,
|
||||
) -> Option<llr_Expression> {
|
||||
match path {
|
||||
crate::expression_tree::Path::Elements(elements) => {
|
||||
let converted_elements = elements
|
||||
.iter()
|
||||
.map(|element| {
|
||||
let ty = Type::Struct {
|
||||
fields: element
|
||||
.element_type
|
||||
.properties
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), v.ty.clone()))
|
||||
.collect(),
|
||||
name: element.element_type.native_class.cpp_type.clone(),
|
||||
node: None,
|
||||
};
|
||||
|
||||
llr_Expression::Struct {
|
||||
ty,
|
||||
values: element
|
||||
.bindings
|
||||
.iter()
|
||||
.map(|(property, expr)| {
|
||||
(
|
||||
property.clone(),
|
||||
lower_expression(&expr.borrow().expression, ctx).unwrap(),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
Some(llr_Expression::Cast {
|
||||
from: llr_Expression::Array {
|
||||
element_ty: Type::PathElements,
|
||||
values: converted_elements,
|
||||
}
|
||||
.into(),
|
||||
to: Type::PathElements,
|
||||
})
|
||||
}
|
||||
crate::expression_tree::Path::Events(events) => {
|
||||
Some(llr_Expression::PathEvents(events.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn make_struct(
|
||||
name: String,
|
||||
it: impl IntoIterator<Item = (&'static str, Type, llr_Expression)>,
|
||||
) -> llr_Expression {
|
||||
let mut fields = BTreeMap::<String, Type>::new();
|
||||
let mut values = HashMap::<String, llr_Expression>::new();
|
||||
for (name, ty, expr) in it {
|
||||
fields.insert(name.to_string(), ty);
|
||||
values.insert(name.to_string(), expr);
|
||||
}
|
||||
|
||||
llr_Expression::Struct { ty: Type::Struct { fields, name: Some(name), node: None }, values }
|
||||
}
|
||||
|
|
|
@ -26,9 +26,23 @@ pub fn lower_to_item_tree(component: &Rc<Component>) -> PublicComponent {
|
|||
}
|
||||
|
||||
let sc = lower_sub_component(component, &state, None);
|
||||
let public_properties = component
|
||||
.root_element
|
||||
.borrow()
|
||||
.property_declarations
|
||||
.iter()
|
||||
.filter(|(_, c)| c.expose_in_public_api)
|
||||
.map(|(p, c)| {
|
||||
let property_reference = sc
|
||||
.mapping
|
||||
.map_property_reference(&NamedReference::new(&component.root_element, p), &state)
|
||||
.unwrap();
|
||||
(p.clone(), (c.property_type.clone(), property_reference))
|
||||
})
|
||||
.collect();
|
||||
let item_tree = ItemTree {
|
||||
root: SubComponentInstance { ty: sc.sub_component.clone() },
|
||||
tree: make_tree(&state, component),
|
||||
tree: make_tree(&state, &component.root_element, &sc, &[]),
|
||||
root: Rc::try_unwrap(sc.sub_component).unwrap(),
|
||||
parent_context: None,
|
||||
};
|
||||
PublicComponent {
|
||||
|
@ -39,6 +53,7 @@ pub fn lower_to_item_tree(component: &Rc<Component>) -> PublicComponent {
|
|||
.into_iter()
|
||||
.map(|(c, sc)| (c.id.clone(), sc.sub_component))
|
||||
.collect(),
|
||||
public_properties,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,13 +66,14 @@ pub struct LoweringState {
|
|||
#[derive(Debug, Clone)]
|
||||
pub enum LoweredElement {
|
||||
SubComponent { sub_component_index: usize },
|
||||
NativeItem { item_index: usize }, //property_mapping: HashMap<String, (Vec<usize>, PropertyIndex)>,
|
||||
NativeItem { item_index: usize },
|
||||
Repeated { repeated_index: usize },
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct LoweredSubComponentMapping {
|
||||
element_mapping: HashMap<ByAddress<ElementRc>, LoweredElement>,
|
||||
property_mapping: HashMap<NamedReference, PropertyReference>,
|
||||
pub element_mapping: HashMap<ByAddress<ElementRc>, LoweredElement>,
|
||||
pub property_mapping: HashMap<NamedReference, PropertyReference>,
|
||||
}
|
||||
|
||||
impl LoweredSubComponentMapping {
|
||||
|
@ -72,11 +88,20 @@ impl LoweredSubComponentMapping {
|
|||
if let Some(x) = state.global_properties.get(&from) {
|
||||
return Some(x.clone());
|
||||
}
|
||||
match self.element_mapping.get(&from.element().into())? {
|
||||
let element = from.element();
|
||||
if let Some(alias) = element
|
||||
.borrow()
|
||||
.property_declarations
|
||||
.get(from.name())
|
||||
.and_then(|x| x.is_alias.as_ref())
|
||||
{
|
||||
return state.map_property_reference(alias);
|
||||
}
|
||||
match self.element_mapping.get(&element.clone().into())? {
|
||||
LoweredElement::SubComponent { sub_component_index } => {
|
||||
if let Type::Component(base) = &from.element().borrow().base_type {
|
||||
if let Type::Component(base) = &element.borrow().base_type {
|
||||
return Some(property_reference_within_sub_component(
|
||||
state.map_property_reference(NamedReference::new(
|
||||
state.map_property_reference(&NamedReference::new(
|
||||
&base.root_element,
|
||||
from.name(),
|
||||
))?,
|
||||
|
@ -92,6 +117,7 @@ impl LoweredSubComponentMapping {
|
|||
prop_name: from.name().into(),
|
||||
});
|
||||
}
|
||||
LoweredElement::Repeated { .. } => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +128,7 @@ pub struct LoweredSubComponent {
|
|||
}
|
||||
|
||||
impl LoweringState {
|
||||
pub fn map_property_reference(&self, from: NamedReference) -> Option<PropertyReference> {
|
||||
pub fn map_property_reference(&self, from: &NamedReference) -> Option<PropertyReference> {
|
||||
if let Some(x) = self.global_properties.get(&from) {
|
||||
return Some(x.clone());
|
||||
}
|
||||
|
@ -112,7 +138,7 @@ impl LoweringState {
|
|||
.sub_components
|
||||
.get(&element.borrow().enclosing_component.upgrade().unwrap().into())?;
|
||||
|
||||
enclosing.mapping.map_property_reference(&from, self)
|
||||
enclosing.mapping.map_property_reference(from, self)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,9 +186,11 @@ fn lower_sub_component(
|
|||
properties: Default::default(),
|
||||
items: Default::default(),
|
||||
repeated: Default::default(),
|
||||
popup_windows: Default::default(),
|
||||
sub_components: Default::default(),
|
||||
property_init: Default::default(),
|
||||
two_way_bindings: Default::default(),
|
||||
const_properties: Default::default(),
|
||||
};
|
||||
let mut mapping = LoweredSubComponentMapping::default();
|
||||
let mut property_bindings = vec![];
|
||||
|
@ -201,6 +229,10 @@ fn lower_sub_component(
|
|||
}
|
||||
}
|
||||
if elem.repeated.is_some() {
|
||||
mapping.element_mapping.insert(
|
||||
element.clone().into(),
|
||||
LoweredElement::Repeated { repeated_index: repeated.len() },
|
||||
);
|
||||
repeated.push(element.clone());
|
||||
return;
|
||||
}
|
||||
|
@ -218,14 +250,16 @@ fn lower_sub_component(
|
|||
continue;
|
||||
}
|
||||
let prop_ref = state
|
||||
.map_property_reference(NamedReference::new(&comp.root_element, p))
|
||||
.map_property_reference(&NamedReference::new(&comp.root_element, p))
|
||||
.map(|x| property_reference_within_sub_component(x, sub_component_index));
|
||||
property_bindings.push((prop_ref.unwrap(), b.borrow().clone()));
|
||||
}
|
||||
sub_component.sub_components.push(SubComponentInstance { ty });
|
||||
sub_component
|
||||
.sub_components
|
||||
.push(SubComponentInstance { ty, name: elem.id.clone() });
|
||||
}
|
||||
|
||||
Type::Native(_) => {
|
||||
Type::Native(n) => {
|
||||
let item_index = sub_component.items.len();
|
||||
mapping
|
||||
.element_mapping
|
||||
|
@ -243,6 +277,11 @@ fn lower_sub_component(
|
|||
b.borrow().clone(),
|
||||
));
|
||||
}
|
||||
sub_component.items.push(Item {
|
||||
ty: n.clone(),
|
||||
name: elem.id.clone(),
|
||||
is_flickable_viewport: elem.is_flickable_viewport,
|
||||
})
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
@ -266,9 +305,21 @@ fn lower_sub_component(
|
|||
.push((prop.clone(), BindingExpression { expression, animation }))
|
||||
}
|
||||
}
|
||||
for elem in repeated {
|
||||
sub_component.repeated.push(lower_repeated_component(&elem, &ctx))
|
||||
sub_component.repeated =
|
||||
repeated.into_iter().map(|elem| lower_repeated_component(&elem, &ctx)).collect();
|
||||
sub_component.popup_windows = component
|
||||
.popup_windows
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|popup| lower_popup_component(&popup.component, &ctx))
|
||||
.collect();
|
||||
|
||||
crate::generator::for_each_const_properties(component, |elem, n| {
|
||||
if let Some(x) = ctx.map_property_reference(&NamedReference::new(elem, n)) {
|
||||
sub_component.const_properties.push(x);
|
||||
}
|
||||
});
|
||||
|
||||
LoweredSubComponent { sub_component: Rc::new(sub_component), mapping }
|
||||
}
|
||||
|
||||
|
@ -277,12 +328,12 @@ fn lower_repeated_component(elem: &ElementRc, ctx: &ExpressionContext) -> Repeat
|
|||
let component = e.base_type.as_component().clone();
|
||||
let repeated = e.repeated.as_ref().unwrap();
|
||||
|
||||
let sc = ctx.state.sub_component(&component);
|
||||
let sc = lower_sub_component(&component, &ctx.state, Some(ctx));
|
||||
RepeatedElement {
|
||||
model: super::lower_expression::lower_expression(&repeated.model, ctx).unwrap(),
|
||||
sub_tree: ItemTree {
|
||||
root: SubComponentInstance { ty: sc.sub_component.clone() },
|
||||
tree: make_tree(ctx.state, &component),
|
||||
tree: make_tree(ctx.state, &component.root_element, &sc, &[]),
|
||||
root: Rc::try_unwrap(sc.sub_component).unwrap(),
|
||||
parent_context: Some(e.enclosing_component.upgrade().unwrap().id.clone()),
|
||||
},
|
||||
index_prop: 1,
|
||||
|
@ -290,6 +341,26 @@ fn lower_repeated_component(elem: &ElementRc, ctx: &ExpressionContext) -> Repeat
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_popup_component(component: &Rc<Component>, ctx: &ExpressionContext) -> ItemTree {
|
||||
let sc = lower_sub_component(component, &ctx.state, Some(ctx));
|
||||
ItemTree {
|
||||
tree: make_tree(ctx.state, &component.root_element, &sc, &[]),
|
||||
root: Rc::try_unwrap(sc.sub_component).unwrap(),
|
||||
parent_context: Some(
|
||||
component
|
||||
.parent_element
|
||||
.upgrade()
|
||||
.unwrap()
|
||||
.borrow()
|
||||
.enclosing_component
|
||||
.upgrade()
|
||||
.unwrap()
|
||||
.id
|
||||
.clone(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_global(
|
||||
global: &Rc<Component>,
|
||||
global_index: usize,
|
||||
|
@ -297,6 +368,7 @@ fn lower_global(
|
|||
) -> GlobalComponent {
|
||||
let mut mapping = LoweredSubComponentMapping::default();
|
||||
let mut properties = vec![];
|
||||
let mut const_properties = vec![];
|
||||
|
||||
for (p, x) in &global.root_element.borrow().property_declarations {
|
||||
let property_index = properties.len();
|
||||
|
@ -307,6 +379,7 @@ fn lower_global(
|
|||
);
|
||||
|
||||
properties.push(Property { name: p.clone(), ty: x.property_type.clone() });
|
||||
const_properties.push(nr.is_constant());
|
||||
state
|
||||
.global_properties
|
||||
.insert(nr.clone(), PropertyReference::Global { global_index, property_index });
|
||||
|
@ -330,9 +403,45 @@ fn lower_global(
|
|||
}
|
||||
}
|
||||
|
||||
GlobalComponent { name: global.id.clone(), properties, init_values }
|
||||
GlobalComponent { name: global.id.clone(), properties, init_values, const_properties }
|
||||
}
|
||||
|
||||
fn make_tree(state: &LoweringState, component: &Rc<Component>) -> TreeNode {
|
||||
todo!()
|
||||
fn make_tree(
|
||||
state: &LoweringState,
|
||||
element: &ElementRc,
|
||||
component: &LoweredSubComponent,
|
||||
sub_component_path: &[usize],
|
||||
) -> TreeNode {
|
||||
let e = element.borrow();
|
||||
let children = e.children.iter().map(|c| make_tree(state, c, component, sub_component_path));
|
||||
match component.mapping.element_mapping.get(&ByAddress(element.clone())).unwrap() {
|
||||
LoweredElement::SubComponent { sub_component_index } => {
|
||||
let sub_component = e.sub_component().unwrap();
|
||||
let new_sub_component_path = sub_component_path
|
||||
.iter()
|
||||
.copied()
|
||||
.chain(std::iter::once(*sub_component_index))
|
||||
.collect::<Vec<_>>();
|
||||
let mut tree_node = make_tree(
|
||||
state,
|
||||
&sub_component.root_element,
|
||||
state.sub_component(sub_component),
|
||||
&new_sub_component_path,
|
||||
);
|
||||
tree_node.children.extend(children);
|
||||
tree_node
|
||||
}
|
||||
LoweredElement::NativeItem { item_index } => TreeNode {
|
||||
sub_component_path: sub_component_path.into(),
|
||||
item_index: *item_index,
|
||||
children: children.collect(),
|
||||
repeated: false,
|
||||
},
|
||||
LoweredElement::Repeated { repeated_index } => TreeNode {
|
||||
sub_component_path: sub_component_path.into(),
|
||||
item_index: *repeated_index,
|
||||
children: vec![],
|
||||
repeated: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,8 +38,8 @@ const RESERVED_LAYOUT_PROPERTIES: &[(&str, Type)] = &[
|
|||
];
|
||||
|
||||
thread_local! {
|
||||
pub static DIALOG_BUTTON_ROLE_ENUM: Type =
|
||||
Type::Enumeration(Rc::new(Enumeration {
|
||||
pub static DIALOG_BUTTON_ROLE_ENUM: Rc<Enumeration> =
|
||||
Rc::new(Enumeration {
|
||||
name: "DialogButtonRole".into(),
|
||||
values: IntoIterator::into_iter([
|
||||
"none".to_owned(),
|
||||
|
@ -52,7 +52,16 @@ thread_local! {
|
|||
])
|
||||
.collect(),
|
||||
default_value: 0,
|
||||
}));
|
||||
});
|
||||
|
||||
pub static LAYOUT_ALIGNMENT_ENUM: Rc<Enumeration> =
|
||||
Rc::new(Enumeration {
|
||||
name: "LayoutAlignment".into(),
|
||||
values: IntoIterator::into_iter(
|
||||
["stretch", "center", "start", "end", "space-between", "space-around"]
|
||||
).map(String::from).collect(),
|
||||
default_value: 0,
|
||||
});
|
||||
}
|
||||
|
||||
const RESERVED_OTHER_PROPERTIES: &[(&str, Type)] = &[
|
||||
|
@ -79,7 +88,7 @@ pub fn reserved_properties() -> impl Iterator<Item = (&'static str, Type)> {
|
|||
.chain(IntoIterator::into_iter([
|
||||
("forward-focus", Type::ElementReference),
|
||||
("focus", BuiltinFunction::SetFocusItem.ty()),
|
||||
("dialog-button-role", DIALOG_BUTTON_ROLE_ENUM.with(|e| e.clone())),
|
||||
("dialog-button-role", Type::Enumeration(DIALOG_BUTTON_ROLE_ENUM.with(|e| e.clone()))),
|
||||
]))
|
||||
}
|
||||
|
||||
|
@ -179,10 +188,6 @@ impl TypeRegister {
|
|||
declare_enum("TextVerticalAlignment", &["top", "center", "bottom"]);
|
||||
declare_enum("TextWrap", &["no-wrap", "word-wrap"]);
|
||||
declare_enum("TextOverflow", &["clip", "elide"]);
|
||||
declare_enum(
|
||||
"LayoutAlignment",
|
||||
&["stretch", "center", "start", "end", "space-between", "space-around"],
|
||||
);
|
||||
declare_enum("ImageFit", &["fill", "contain", "cover"]);
|
||||
declare_enum("ImageRendering", &["smooth", "pixelated"]);
|
||||
declare_enum("EventResult", &["reject", "accept"]);
|
||||
|
@ -229,7 +234,10 @@ impl TypeRegister {
|
|||
);
|
||||
declare_enum("PointerEventKind", &["cancel", "down", "up"]);
|
||||
declare_enum("PointerEventButton", &["none", "left", "right", "middle"]);
|
||||
register.insert_type(DIALOG_BUTTON_ROLE_ENUM.with(|x| x.clone()));
|
||||
DIALOG_BUTTON_ROLE_ENUM
|
||||
.with(|e| register.insert_type_with_name(Type::Enumeration(e.clone()), e.name.clone()));
|
||||
LAYOUT_ALIGNMENT_ENUM
|
||||
.with(|e| register.insert_type_with_name(Type::Enumeration(e.clone()), e.name.clone()));
|
||||
|
||||
register.supported_property_animation_types.insert(Type::Float32.to_string());
|
||||
register.supported_property_animation_types.insert(Type::Int32.to_string());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue