slint_interpreter/
value_model.rs

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
4use crate::api::Value;
5use core::cell::Cell;
6use i_slint_core::model::{Model, ModelNotify, ModelRc, ModelTracker};
7
8pub struct ValueModel {
9    value: Value,
10}
11
12impl ValueModel {
13    pub fn new(value: Value) -> Self {
14        Self { value }
15    }
16}
17
18impl ModelTracker for ValueModel {
19    fn attach_peer(&self, peer: i_slint_core::model::ModelPeer) {
20        if let Value::Model(ref model_ptr) = self.value {
21            model_ptr.model_tracker().attach_peer(peer)
22        }
23    }
24
25    fn track_row_count_changes(&self) {
26        if let Value::Model(ref model_ptr) = self.value {
27            model_ptr.model_tracker().track_row_count_changes()
28        }
29    }
30
31    fn track_row_data_changes(&self, row: usize) {
32        if let Value::Model(ref model_ptr) = self.value {
33            model_ptr.model_tracker().track_row_data_changes(row)
34        }
35    }
36}
37
38impl Model for ValueModel {
39    type Data = Value;
40
41    fn row_count(&self) -> usize {
42        match &self.value {
43            Value::Bool(b) => {
44                if *b {
45                    1
46                } else {
47                    0
48                }
49            }
50            Value::Number(x) => x.max(Default::default()) as usize,
51            Value::Void => 0,
52            Value::Model(model_ptr) => model_ptr.row_count(),
53            x => panic!("Invalid model {x:?}"),
54        }
55    }
56
57    fn row_data(&self, row: usize) -> Option<Self::Data> {
58        if row >= self.row_count() {
59            None
60        } else {
61            Some(match &self.value {
62                Value::Bool(_) => Value::Void,
63                Value::Number(_) => Value::Number(row as _),
64                Value::Model(model_ptr) => model_ptr.row_data(row)?,
65                x => panic!("Invalid model {x:?}"),
66            })
67        }
68    }
69
70    fn model_tracker(&self) -> &dyn ModelTracker {
71        self
72    }
73
74    fn set_row_data(&self, row: usize, data: Self::Data) {
75        match &self.value {
76            Value::Model(model_ptr) => model_ptr.set_row_data(row, data),
77            _ => eprintln!("Trying to change the value of a read-only integer model."),
78        }
79    }
80
81    fn as_any(&self) -> &dyn core::any::Any {
82        self
83    }
84}
85
86/// A model for conditional elements
87#[derive(Default)]
88pub(crate) struct BoolModel {
89    value: Cell<bool>,
90    notify: ModelNotify,
91}
92
93impl Model for BoolModel {
94    type Data = Value;
95    fn row_count(&self) -> usize {
96        if self.value.get() {
97            1
98        } else {
99            0
100        }
101    }
102    fn row_data(&self, row: usize) -> Option<Self::Data> {
103        (row == 0 && self.value.get()).then_some(Value::Void)
104    }
105    fn model_tracker(&self) -> &dyn ModelTracker {
106        &self.notify
107    }
108}
109
110impl BoolModel {
111    pub fn set_value(&self, val: bool) {
112        let old = self.value.replace(val);
113        if old != val {
114            self.notify.reset();
115        }
116    }
117}
118
119// A map model that wraps a Model
120pub struct ValueMapModel<T>(pub ModelRc<T>);
121
122impl<T: TryFrom<Value> + Into<Value> + 'static> Model for ValueMapModel<T> {
123    type Data = Value;
124
125    fn row_count(&self) -> usize {
126        self.0.row_count()
127    }
128
129    fn row_data(&self, row: usize) -> Option<Self::Data> {
130        self.0.row_data(row).map(|x| x.into())
131    }
132
133    fn model_tracker(&self) -> &dyn ModelTracker {
134        self.0.model_tracker()
135    }
136
137    fn as_any(&self) -> &dyn core::any::Any {
138        self
139    }
140
141    fn set_row_data(&self, row: usize, data: Self::Data) {
142        if let Ok(data) = data.try_into() {
143            self.0.set_row_data(row, data)
144        }
145    }
146}