| 1 | // Copyright © SixtyFPS GmbH <info@slint.dev> |
| 2 | // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 |
| 3 | |
| 4 | //! Passe that transform the Timer element into a timer in the Component |
| 5 | |
| 6 | use crate::diagnostics::BuildDiagnostics; |
| 7 | use crate::expression_tree::{BuiltinFunction, Expression, NamedReference}; |
| 8 | use crate::langtype::ElementType; |
| 9 | use crate::object_tree::*; |
| 10 | use smol_str::SmolStr; |
| 11 | use std::rc::Rc; |
| 12 | |
| 13 | pub fn lower_timers(component: &Rc<Component>, diag: &mut BuildDiagnostics) { |
| 14 | recurse_elem_including_sub_components_no_borrow( |
| 15 | component, |
| 16 | &None, |
| 17 | &mut |elem: &Rc>, parent_element: &Option<ElementRc>| { |
| 18 | let is_timer: bool = matches!(&elem.borrow().base_type, ElementType::Builtin(base_type) if base_type.name == "Timer" ); |
| 19 | if is_timer { |
| 20 | lower_timer(timer_element:elem, parent_element.as_ref(), diag); |
| 21 | } |
| 22 | Some(elem.clone()) |
| 23 | }, |
| 24 | ) |
| 25 | } |
| 26 | |
| 27 | fn lower_timer( |
| 28 | timer_element: &ElementRc, |
| 29 | parent_element: Option<&ElementRc>, |
| 30 | diag: &mut BuildDiagnostics, |
| 31 | ) { |
| 32 | let parent_component = timer_element.borrow().enclosing_component.upgrade().unwrap(); |
| 33 | let Some(parent_element) = parent_element else { |
| 34 | diag.push_error("A component cannot inherit from Timer" .into(), &*timer_element.borrow()); |
| 35 | return; |
| 36 | }; |
| 37 | |
| 38 | if Rc::ptr_eq(&parent_component.root_element, timer_element) { |
| 39 | diag.push_error( |
| 40 | "Timer cannot be directly repeated or conditional" .into(), |
| 41 | &*timer_element.borrow(), |
| 42 | ); |
| 43 | return; |
| 44 | } |
| 45 | |
| 46 | if !timer_element.borrow().is_binding_set("interval" , true) { |
| 47 | diag.push_error( |
| 48 | "Timer must have a binding set for its 'interval' property" .into(), |
| 49 | &*timer_element.borrow(), |
| 50 | ); |
| 51 | return; |
| 52 | } |
| 53 | |
| 54 | // Remove the timer_element from its parent |
| 55 | let mut parent_element_borrowed = parent_element.borrow_mut(); |
| 56 | let index = parent_element_borrowed |
| 57 | .children |
| 58 | .iter() |
| 59 | .position(|child| Rc::ptr_eq(child, timer_element)) |
| 60 | .expect("Timer must be a child of its parent" ); |
| 61 | let removed = parent_element_borrowed.children.remove(index); |
| 62 | parent_component.optimized_elements.borrow_mut().push(removed); |
| 63 | drop(parent_element_borrowed); |
| 64 | if let Some((p, idx, _)) = &mut *parent_component.child_insertion_point.borrow_mut() { |
| 65 | if Rc::ptr_eq(p, parent_element) && *idx > index { |
| 66 | *idx -= 1; |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | parent_component.timers.borrow_mut().push(Timer { |
| 71 | interval: NamedReference::new(timer_element, SmolStr::new_static("interval" )), |
| 72 | running: NamedReference::new(timer_element, SmolStr::new_static("running" )), |
| 73 | triggered: NamedReference::new(timer_element, SmolStr::new_static("triggered" )), |
| 74 | }); |
| 75 | let update_timers = Expression::FunctionCall { |
| 76 | function: BuiltinFunction::UpdateTimers.into(), |
| 77 | arguments: vec![], |
| 78 | source_location: None, |
| 79 | }; |
| 80 | let change_callbacks = &mut timer_element.borrow_mut().change_callbacks; |
| 81 | change_callbacks.entry("running" .into()).or_default().borrow_mut().push(update_timers.clone()); |
| 82 | change_callbacks.entry("interval" .into()).or_default().borrow_mut().push(update_timers); |
| 83 | } |
| 84 | |