slint/tools/updater/experiments/geometry_changes.rs
2023-07-10 10:12:11 +02:00

103 lines
3.8 KiB
Rust

// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
use crate::Cli;
use i_slint_compiler::expression_tree::Expression;
use i_slint_compiler::langtype::Type;
use i_slint_compiler::object_tree::ElementRc;
use i_slint_compiler::parser::{SyntaxKind, SyntaxNode};
use std::io::Write;
pub(crate) fn fold_node(
node: &SyntaxNode,
file: &mut impl Write,
state: &mut crate::State,
args: &Cli,
) -> std::io::Result<bool> {
let kind = node.kind();
if kind == SyntaxKind::Element {
if state.lookup_change.scope.len() >= 2 {
let elem = &state.lookup_change.scope[state.lookup_change.scope.len() - 1];
let parent = &state.lookup_change.scope[state.lookup_change.scope.len() - 2];
if !is_layout_base(parent) && !is_path(elem) && elem.borrow().is_legacy_syntax {
let extend = elem.borrow().builtin_type().map_or(false, |b| {
b.default_size_binding
!= i_slint_compiler::langtype::DefaultSizeBinding::ImplicitSize
});
let new_props = format!(
"{}{}",
new_geometry_binding(elem, "x", "width", extend),
new_geometry_binding(elem, "y", "height", extend)
);
if !new_props.is_empty() {
let mut seen_brace = false;
for c in node.children_with_tokens() {
if seen_brace {
if c.kind() == SyntaxKind::Whitespace {
crate::visit_node_or_token(c.clone(), file, state, args)?;
}
write!(file, "{new_props}")?;
seen_brace = false;
} else if c.kind() == SyntaxKind::LBrace {
seen_brace = true;
}
crate::visit_node_or_token(c, file, state, args)?;
}
return Ok(true);
}
}
}
}
Ok(false)
}
fn new_geometry_binding(elem: &ElementRc, pos_prop: &str, size_prop: &str, extend: bool) -> String {
if elem.borrow().lookup_property(pos_prop).property_type != Type::LogicalLength {
return String::default();
}
if elem.borrow().is_binding_set(pos_prop, false) {
return String::default();
}
if extend && !elem.borrow().is_binding_set(size_prop, false) {
return String::default();
}
if let Some(b) = elem.borrow().bindings.get(size_prop) {
if let Expression::Uncompiled(x) = &b.borrow().expression {
let s = x.to_string();
if s.trim() == "100%;" || s.trim() == format!("parent.{size_prop};") {
return String::default();
}
}
}
format!("{pos_prop}:0;")
}
fn is_layout_base(elem: &ElementRc) -> bool {
match &elem.borrow().base_type {
i_slint_compiler::langtype::ElementType::Builtin(b) => {
return matches!(
b.name.as_str(),
"GridLayout" | "HorizontalLayout" | "VerticalLayout" | "Row" | "Path" | "Dialog"
);
}
i_slint_compiler::langtype::ElementType::Component(c) => {
if c.id == "ListView" {
return true;
}
if let Some(ins) = &*c.child_insertion_point.borrow() {
return is_layout_base(&ins.0);
} else {
return is_layout_base(&c.root_element);
}
}
_ => return false,
};
}
fn is_path(elem: &ElementRc) -> bool {
// Path's children are still considered in the Path for some reason, so just don't touch path
elem.borrow().base_type.to_string() == "Path"
}