Skip to main content

gtk/
list_store.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use crate::TreeIter;
4use crate::TreeModel;
5use crate::{ListStore, ffi};
6use glib::object::{Cast, IsA};
7use glib::translate::*;
8use glib::{Type, Value, value::ToValue};
9use libc::c_int;
10use std::ptr;
11
12impl ListStore {
13    /// Creates a new list store as with `n_columns` columns each of the types passed
14    /// in. Note that only types derived from standard GObject fundamental types
15    /// are supported.
16    ///
17    /// As an example, `gtk_list_store_new (3, G_TYPE_INT, G_TYPE_STRING,
18    /// GDK_TYPE_PIXBUF);` will create a new [`ListStore`][crate::ListStore] with three columns, of type
19    /// int, string and [`gdk_pixbuf::Pixbuf`][crate::gdk_pixbuf::Pixbuf] respectively.
20    /// ## `n_columns`
21    /// number of columns in the list store
22    ///
23    /// # Returns
24    ///
25    /// a new [`ListStore`][crate::ListStore]
26    #[doc(alias = "gtk_list_store_newv")]
27    pub fn new(column_types: &[Type]) -> ListStore {
28        assert_initialized_main_thread!();
29        unsafe {
30            let mut column_types = column_types
31                .iter()
32                .map(|t| t.into_glib())
33                .collect::<Vec<_>>();
34            from_glib_full(ffi::gtk_list_store_newv(
35                column_types.len() as c_int,
36                column_types.as_mut_ptr(),
37            ))
38        }
39    }
40}
41
42mod sealed {
43    pub trait Sealed {}
44    impl<T: glib::object::IsA<crate::ListStore>> Sealed for T {}
45}
46
47pub trait GtkListStoreExtManual: IsA<ListStore> + sealed::Sealed + 'static {
48    #[doc(alias = "gtk_list_store_insert_with_valuesv")]
49    fn insert_with_values(
50        &self,
51        position: Option<u32>,
52        columns_and_values: &[(u32, &dyn ToValue)],
53    ) -> TreeIter {
54        unsafe {
55            assert!(
56                position.unwrap_or(0) <= i32::MAX as u32,
57                "can't have more than {} rows",
58                i32::MAX
59            );
60            let n_columns = ffi::gtk_tree_model_get_n_columns(
61                self.as_ref().upcast_ref::<TreeModel>().to_glib_none().0,
62            ) as u32;
63            assert!(
64                columns_and_values.len() <= n_columns as usize,
65                "got values for {} columns but only {} columns exist",
66                columns_and_values.len(),
67                n_columns
68            );
69            for (column, value) in columns_and_values {
70                assert!(
71                    *column < n_columns,
72                    "got column {} which is higher than the number of columns {n_columns}",
73                    *column,
74                );
75                let type_ = from_glib(ffi::gtk_tree_model_get_column_type(
76                    self.as_ref().upcast_ref::<TreeModel>().to_glib_none().0,
77                    *column as c_int,
78                ));
79                assert!(
80                    Value::type_transformable(value.value_type(), type_),
81                    "column {} is of type {type_} but found value of type {}",
82                    *column,
83                    value.value_type()
84                );
85            }
86
87            let columns = columns_and_values
88                .iter()
89                .map(|(c, _)| *c)
90                .collect::<Vec<_>>();
91            let values = columns_and_values
92                .iter()
93                .map(|(_, v)| v.to_value())
94                .collect::<Vec<_>>();
95
96            let mut iter = TreeIter::uninitialized();
97            ffi::gtk_list_store_insert_with_valuesv(
98                self.as_ref().to_glib_none().0,
99                iter.to_glib_none_mut().0,
100                position.map_or(-1, |n| n as c_int),
101                mut_override(columns.as_ptr() as *const c_int),
102                mut_override(values.as_ptr() as *const glib::gobject_ffi::GValue),
103                columns.len() as c_int,
104            );
105            iter
106        }
107    }
108
109    /// Reorders `self` to follow the order indicated by `new_order`. Note that
110    /// this function only works with unsorted stores.
111    /// ## `new_order`
112    /// an array of integers mapping the new
113    ///  position of each child to its old position before the re-ordering,
114    ///  i.e. `new_order``[newpos] = oldpos`. It must have
115    ///  exactly as many items as the list store’s length.
116    #[doc(alias = "gtk_list_store_reorder")]
117    fn reorder(&self, new_order: &[u32]) {
118        unsafe {
119            let count = ffi::gtk_tree_model_iter_n_children(
120                self.as_ref().upcast_ref::<TreeModel>().to_glib_none().0,
121                ptr::null_mut(),
122            );
123            let safe_count = count as usize == new_order.len();
124            debug_assert!(
125                safe_count,
126                "Incorrect `new_order` slice length. Expected `{count}`, found `{}`.",
127                new_order.len()
128            );
129            let safe_values = new_order.iter().max().is_none_or(|&max| {
130                let max = max as i32;
131                max >= 0 && max < count
132            });
133            debug_assert!(
134                safe_values,
135                "Some `new_order` slice values are out of range. Maximum safe value: \
136                 `{}`. The slice contents: `{new_order:?}`",
137                count - 1,
138            );
139            if safe_count && safe_values {
140                ffi::gtk_list_store_reorder(
141                    self.as_ref().to_glib_none().0,
142                    mut_override(new_order.as_ptr() as *const c_int),
143                );
144            }
145        }
146    }
147
148    /// Sets the value of one or more cells in the row referenced by `iter`.
149    /// The variable argument list should contain integer column numbers,
150    /// each column number followed by the value to be set.
151    /// The list is terminated by a -1. For example, to set column 0 with type
152    /// `G_TYPE_STRING` to “Foo”, you would write `gtk_list_store_set (store, iter,
153    /// 0, "Foo", -1)`.
154    ///
155    /// The value will be referenced by the store if it is a `G_TYPE_OBJECT`, and it
156    /// will be copied if it is a `G_TYPE_STRING` or `G_TYPE_BOXED`.
157    /// ## `iter`
158    /// row iterator
159    #[doc(alias = "gtk_list_store_set")]
160    #[doc(alias = "gtk_list_store_set_valuesv")]
161    fn set(&self, iter: &TreeIter, columns_and_values: &[(u32, &dyn ToValue)]) {
162        unsafe {
163            let n_columns = ffi::gtk_tree_model_get_n_columns(
164                self.as_ref().upcast_ref::<TreeModel>().to_glib_none().0,
165            ) as u32;
166            assert!(
167                columns_and_values.len() <= n_columns as usize,
168                "got values for {} columns but only {n_columns} columns exist",
169                columns_and_values.len(),
170            );
171            for (column, value) in columns_and_values {
172                assert!(
173                    *column < n_columns,
174                    "got column {} which is higher than the number of columns {n_columns}",
175                    *column,
176                );
177                let type_ = from_glib(ffi::gtk_tree_model_get_column_type(
178                    self.as_ref().upcast_ref::<TreeModel>().to_glib_none().0,
179                    *column as c_int,
180                ));
181                assert!(
182                    Value::type_transformable(value.value_type(), type_),
183                    "column {} is of type {type_} but found value of type {}",
184                    *column,
185                    value.value_type()
186                );
187            }
188
189            let columns = columns_and_values
190                .iter()
191                .map(|(c, _)| *c)
192                .collect::<Vec<_>>();
193            let values = columns_and_values
194                .iter()
195                .map(|(_, v)| v.to_value())
196                .collect::<Vec<_>>();
197
198            ffi::gtk_list_store_set_valuesv(
199                self.as_ref().to_glib_none().0,
200                mut_override(iter.to_glib_none().0),
201                mut_override(columns.as_ptr() as *const c_int),
202                mut_override(values.as_ptr() as *const glib::gobject_ffi::GValue),
203                columns.len() as c_int,
204            );
205        }
206    }
207
208    /// Sets the data in the cell specified by `iter` and `column`.
209    /// The type of `value` must be convertible to the type of the
210    /// column.
211    /// ## `iter`
212    /// A valid [`TreeIter`][crate::TreeIter] for the row being modified
213    /// ## `column`
214    /// column number to modify
215    /// ## `value`
216    /// new value for the cell
217    #[doc(alias = "gtk_list_store_set_value")]
218    fn set_value(&self, iter: &TreeIter, column: u32, value: &Value) {
219        unsafe {
220            let columns = ffi::gtk_tree_model_get_n_columns(
221                self.as_ref().upcast_ref::<TreeModel>().to_glib_none().0,
222            ) as u32;
223            assert!(
224                column < columns,
225                "got column {column} which is higher than the number of columns {columns}",
226            );
227
228            let type_ = from_glib(ffi::gtk_tree_model_get_column_type(
229                self.as_ref().upcast_ref::<TreeModel>().to_glib_none().0,
230                column as c_int,
231            ));
232            assert!(
233                Value::type_transformable(value.type_(), type_),
234                "column {column} is of type {type_} but found value of type {}",
235                value.type_()
236            );
237
238            ffi::gtk_list_store_set_value(
239                self.as_ref().to_glib_none().0,
240                mut_override(iter.to_glib_none().0),
241                column as c_int,
242                mut_override(value.to_glib_none().0),
243            );
244        }
245    }
246}
247
248impl<O: IsA<ListStore>> GtkListStoreExtManual for O {}