mirror of
				https://github.com/slint-ui/slint.git
				synced 2025-11-03 21:24:17 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			134 lines
		
	
	
	
		
			5.5 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			134 lines
		
	
	
	
		
			5.5 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
// Copyright © SixtyFPS GmbH <info@slint.dev>
 | 
						|
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
 | 
						|
 | 
						|
/*!
 | 
						|
Make sure that the Repeated expression are just components without any children
 | 
						|
 */
 | 
						|
 | 
						|
use crate::expression_tree::{Expression, NamedReference};
 | 
						|
use crate::langtype::ElementType;
 | 
						|
use crate::object_tree::*;
 | 
						|
use smol_str::SmolStr;
 | 
						|
use std::cell::RefCell;
 | 
						|
use std::rc::Rc;
 | 
						|
 | 
						|
pub fn process_repeater_components(component: &Rc<Component>) {
 | 
						|
    create_repeater_components(component);
 | 
						|
    adjust_references(component);
 | 
						|
}
 | 
						|
 | 
						|
fn create_repeater_components(component: &Rc<Component>) {
 | 
						|
    recurse_elem(&component.root_element, &(), &mut |elem, _| {
 | 
						|
        let is_listview = match &elem.borrow().repeated {
 | 
						|
            Some(r) => r.is_listview.clone(),
 | 
						|
            None => return,
 | 
						|
        };
 | 
						|
        let parent_element = Rc::downgrade(elem);
 | 
						|
        let mut elem = elem.borrow_mut();
 | 
						|
 | 
						|
        if matches!(&elem.base_type, ElementType::Component(c) if c.parent_element.upgrade().is_some())
 | 
						|
        {
 | 
						|
            debug_assert!(std::rc::Weak::ptr_eq(
 | 
						|
                &parent_element,
 | 
						|
                &elem.base_type.as_component().parent_element
 | 
						|
            ));
 | 
						|
            // Already processed (can happen if a component is both used and exported root)
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        let comp = Rc::new(Component {
 | 
						|
            root_element: Rc::new(RefCell::new(Element {
 | 
						|
                id: elem.id.clone(),
 | 
						|
                base_type: std::mem::take(&mut elem.base_type),
 | 
						|
                bindings: std::mem::take(&mut elem.bindings),
 | 
						|
                change_callbacks: std::mem::take(&mut elem.change_callbacks),
 | 
						|
                property_analysis: std::mem::take(&mut elem.property_analysis),
 | 
						|
                children: std::mem::take(&mut elem.children),
 | 
						|
                property_declarations: std::mem::take(&mut elem.property_declarations),
 | 
						|
                named_references: Default::default(),
 | 
						|
                repeated: None,
 | 
						|
                is_component_placeholder: false,
 | 
						|
                debug: elem.debug.clone(),
 | 
						|
                enclosing_component: Default::default(),
 | 
						|
                states: std::mem::take(&mut elem.states),
 | 
						|
                transitions: std::mem::take(&mut elem.transitions),
 | 
						|
                child_of_layout: elem.child_of_layout || is_listview.is_some(),
 | 
						|
                layout_info_prop: elem.layout_info_prop.take(),
 | 
						|
                default_fill_parent: elem.default_fill_parent,
 | 
						|
                accessibility_props: std::mem::take(&mut elem.accessibility_props),
 | 
						|
                geometry_props: elem.geometry_props.clone(),
 | 
						|
                is_flickable_viewport: elem.is_flickable_viewport,
 | 
						|
                has_popup_child: elem.has_popup_child,
 | 
						|
                item_index: Default::default(), // Not determined yet
 | 
						|
                item_index_of_first_children: Default::default(),
 | 
						|
                is_legacy_syntax: elem.is_legacy_syntax,
 | 
						|
                inline_depth: 0,
 | 
						|
            })),
 | 
						|
            parent_element,
 | 
						|
            ..Component::default()
 | 
						|
        });
 | 
						|
 | 
						|
        if let Some(listview) = is_listview {
 | 
						|
            if !comp.root_element.borrow().is_binding_set("height", false) {
 | 
						|
                let preferred = Expression::PropertyReference(NamedReference::new(
 | 
						|
                    &comp.root_element,
 | 
						|
                    SmolStr::new_static("preferred-height"),
 | 
						|
                ));
 | 
						|
                comp.root_element
 | 
						|
                    .borrow_mut()
 | 
						|
                    .bindings
 | 
						|
                    .insert("height".into(), RefCell::new(preferred.into()));
 | 
						|
            }
 | 
						|
            if !comp.root_element.borrow().is_binding_set("width", false) {
 | 
						|
                comp.root_element.borrow_mut().bindings.insert(
 | 
						|
                    "width".into(),
 | 
						|
                    RefCell::new(Expression::PropertyReference(listview.listview_width).into()),
 | 
						|
                );
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        let weak = Rc::downgrade(&comp);
 | 
						|
        recurse_elem(&comp.root_element, &(), &mut |e, _| {
 | 
						|
            e.borrow_mut().enclosing_component = weak.clone()
 | 
						|
        });
 | 
						|
        create_repeater_components(&comp);
 | 
						|
        elem.base_type = ElementType::Component(comp);
 | 
						|
    });
 | 
						|
 | 
						|
    for p in component.popup_windows.borrow().iter() {
 | 
						|
        create_repeater_components(&p.component);
 | 
						|
    }
 | 
						|
    for c in component.menu_item_tree.borrow().iter() {
 | 
						|
        create_repeater_components(c);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/// Make sure that references to property within the repeated element actually point to the reference
 | 
						|
/// to the root of the newly created component
 | 
						|
fn adjust_references(comp: &Rc<Component>) {
 | 
						|
    visit_all_named_references(comp, &mut |nr| {
 | 
						|
        if nr.name() == "$model" {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        let e = nr.element();
 | 
						|
        if e.borrow().repeated.is_some() {
 | 
						|
            if let ElementType::Component(c) = e.borrow().base_type.clone() {
 | 
						|
                *nr = NamedReference::new(&c.root_element, nr.name().clone())
 | 
						|
            };
 | 
						|
        }
 | 
						|
    });
 | 
						|
    // Transform any references to the repeated element to refer to the root of each instance.
 | 
						|
    visit_all_expressions(comp, |expr, _| {
 | 
						|
        expr.visit_recursive_mut(&mut |expr| {
 | 
						|
            if let Expression::ElementReference(ref mut element_ref) = expr {
 | 
						|
                if let Some(repeater_element) =
 | 
						|
                    element_ref.upgrade().filter(|e| e.borrow().repeated.is_some())
 | 
						|
                {
 | 
						|
                    let inner_element =
 | 
						|
                        repeater_element.borrow().base_type.as_component().root_element.clone();
 | 
						|
                    *element_ref = Rc::downgrade(&inner_element);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        })
 | 
						|
    });
 | 
						|
}
 |