Skip to main content

gtk/subclass/
tree_view.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::{
4    object::{Cast, IsA},
5    subclass::prelude::*,
6    translate::*,
7};
8
9use super::container::ContainerImpl;
10
11use crate::{MovementStep, TreeIter, TreePath, TreeView, TreeViewColumn, ffi};
12
13pub trait TreeViewImpl: ContainerImpl + ObjectSubclass<Type: IsA<TreeView>> {
14    /// Activates the cell determined by `path` and `column`.
15    /// ## `path`
16    /// The [`TreePath`][crate::TreePath] to be activated.
17    /// ## `column`
18    /// The [`TreeViewColumn`][crate::TreeViewColumn] to be activated.
19    fn row_activated(&self, path: &TreePath, column: Option<&TreeViewColumn>) {
20        self.parent_row_activated(path, column);
21    }
22
23    fn test_expand_row(&self, iter: &TreeIter, path: &TreePath) -> bool {
24        self.parent_test_expand_row(iter, path)
25    }
26
27    fn test_collapse_row(&self, iter: &TreeIter, path: &TreePath) -> bool {
28        self.parent_test_collapse_row(iter, path)
29    }
30
31    fn row_expanded(&self, iter: &TreeIter, path: &TreePath) {
32        self.parent_row_expanded(iter, path);
33    }
34
35    fn row_collapsed(&self, iter: &TreeIter, path: &TreePath) {
36        self.parent_row_collapsed(iter, path);
37    }
38
39    fn columns_changed(&self) {
40        self.parent_columns_changed();
41    }
42
43    fn cursor_changed(&self) {
44        self.parent_cursor_changed();
45    }
46
47    fn move_cursor(&self, step: MovementStep, count: i32) -> bool {
48        self.parent_move_cursor(step, count)
49    }
50
51    fn select_all(&self) -> bool {
52        self.parent_select_all()
53    }
54
55    fn unselect_all(&self) -> bool {
56        self.parent_unselect_all()
57    }
58
59    fn select_cursor_row(&self, start_editing: bool) -> bool {
60        self.parent_select_cursor_row(start_editing)
61    }
62
63    fn toggle_cursor_row(&self) -> bool {
64        self.parent_toggle_cursor_row()
65    }
66
67    fn expand_collapse_cursor_row(&self, logical: bool, expand: bool, open_all: bool) -> bool {
68        self.parent_expand_collapse_cursor_row(logical, expand, open_all)
69    }
70
71    fn select_cursor_parent(&self) -> bool {
72        self.parent_select_cursor_parent()
73    }
74
75    fn start_interactive_search(&self) -> bool {
76        self.parent_start_interactive_search()
77    }
78}
79
80pub trait TreeViewImplExt: TreeViewImpl {
81    fn parent_row_activated(&self, path: &TreePath, column: Option<&TreeViewColumn>) {
82        unsafe {
83            let data = Self::type_data();
84            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTreeViewClass;
85            if let Some(f) = (*parent_class).row_activated {
86                f(
87                    self.obj().unsafe_cast_ref::<TreeView>().to_glib_none().0,
88                    path.to_glib_none().0,
89                    column.to_glib_none().0,
90                )
91            }
92        }
93    }
94
95    fn parent_test_expand_row(&self, iter: &TreeIter, path: &TreePath) -> bool {
96        unsafe {
97            let data = Self::type_data();
98            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTreeViewClass;
99            if let Some(f) = (*parent_class).test_expand_row {
100                from_glib(f(
101                    self.obj().unsafe_cast_ref::<TreeView>().to_glib_none().0,
102                    mut_override(iter.to_glib_none().0),
103                    path.to_glib_none().0,
104                ))
105            } else {
106                false
107            }
108        }
109    }
110
111    fn parent_test_collapse_row(&self, iter: &TreeIter, path: &TreePath) -> bool {
112        unsafe {
113            let data = Self::type_data();
114            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTreeViewClass;
115            if let Some(f) = (*parent_class).test_collapse_row {
116                from_glib(f(
117                    self.obj().unsafe_cast_ref::<TreeView>().to_glib_none().0,
118                    mut_override(iter.to_glib_none().0),
119                    path.to_glib_none().0,
120                ))
121            } else {
122                false
123            }
124        }
125    }
126
127    fn parent_row_expanded(&self, iter: &TreeIter, path: &TreePath) {
128        unsafe {
129            let data = Self::type_data();
130            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTreeViewClass;
131            if let Some(f) = (*parent_class).row_expanded {
132                f(
133                    self.obj().unsafe_cast_ref::<TreeView>().to_glib_none().0,
134                    mut_override(iter.to_glib_none().0),
135                    path.to_glib_none().0,
136                )
137            }
138        }
139    }
140
141    fn parent_row_collapsed(&self, iter: &TreeIter, path: &TreePath) {
142        unsafe {
143            let data = Self::type_data();
144            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTreeViewClass;
145            if let Some(f) = (*parent_class).row_collapsed {
146                f(
147                    self.obj().unsafe_cast_ref::<TreeView>().to_glib_none().0,
148                    mut_override(iter.to_glib_none().0),
149                    path.to_glib_none().0,
150                )
151            }
152        }
153    }
154
155    fn parent_columns_changed(&self) {
156        unsafe {
157            let data = Self::type_data();
158            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTreeViewClass;
159            if let Some(f) = (*parent_class).columns_changed {
160                f(self.obj().unsafe_cast_ref::<TreeView>().to_glib_none().0);
161            }
162        }
163    }
164
165    fn parent_cursor_changed(&self) {
166        unsafe {
167            let data = Self::type_data();
168            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTreeViewClass;
169            if let Some(f) = (*parent_class).cursor_changed {
170                f(self.obj().unsafe_cast_ref::<TreeView>().to_glib_none().0);
171            }
172        }
173    }
174
175    fn parent_move_cursor(&self, step: MovementStep, count: i32) -> bool {
176        unsafe {
177            let data = Self::type_data();
178            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTreeViewClass;
179            if let Some(f) = (*parent_class).move_cursor {
180                from_glib(f(
181                    self.obj().unsafe_cast_ref::<TreeView>().to_glib_none().0,
182                    step.into_glib(),
183                    count,
184                ))
185            } else {
186                false
187            }
188        }
189    }
190
191    fn parent_select_all(&self) -> bool {
192        unsafe {
193            let data = Self::type_data();
194            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTreeViewClass;
195            if let Some(f) = (*parent_class).select_all {
196                from_glib(f(self.obj().unsafe_cast_ref::<TreeView>().to_glib_none().0))
197            } else {
198                false
199            }
200        }
201    }
202
203    fn parent_unselect_all(&self) -> bool {
204        unsafe {
205            let data = Self::type_data();
206            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTreeViewClass;
207            if let Some(f) = (*parent_class).unselect_all {
208                from_glib(f(self.obj().unsafe_cast_ref::<TreeView>().to_glib_none().0))
209            } else {
210                false
211            }
212        }
213    }
214
215    fn parent_select_cursor_row(&self, start_editing: bool) -> bool {
216        unsafe {
217            let data = Self::type_data();
218            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTreeViewClass;
219            if let Some(f) = (*parent_class).select_cursor_row {
220                from_glib(f(
221                    self.obj().unsafe_cast_ref::<TreeView>().to_glib_none().0,
222                    start_editing.into_glib(),
223                ))
224            } else {
225                false
226            }
227        }
228    }
229
230    fn parent_toggle_cursor_row(&self) -> bool {
231        unsafe {
232            let data = Self::type_data();
233            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTreeViewClass;
234            if let Some(f) = (*parent_class).toggle_cursor_row {
235                from_glib(f(self.obj().unsafe_cast_ref::<TreeView>().to_glib_none().0))
236            } else {
237                false
238            }
239        }
240    }
241
242    fn parent_expand_collapse_cursor_row(
243        &self,
244        logical: bool,
245        expand: bool,
246        open_all: bool,
247    ) -> bool {
248        unsafe {
249            let data = Self::type_data();
250            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTreeViewClass;
251            if let Some(f) = (*parent_class).expand_collapse_cursor_row {
252                from_glib(f(
253                    self.obj().unsafe_cast_ref::<TreeView>().to_glib_none().0,
254                    logical.into_glib(),
255                    expand.into_glib(),
256                    open_all.into_glib(),
257                ))
258            } else {
259                false
260            }
261        }
262    }
263
264    fn parent_select_cursor_parent(&self) -> bool {
265        unsafe {
266            let data = Self::type_data();
267            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTreeViewClass;
268            if let Some(f) = (*parent_class).select_cursor_parent {
269                from_glib(f(self.obj().unsafe_cast_ref::<TreeView>().to_glib_none().0))
270            } else {
271                false
272            }
273        }
274    }
275
276    fn parent_start_interactive_search(&self) -> bool {
277        unsafe {
278            let data = Self::type_data();
279            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTreeViewClass;
280            if let Some(f) = (*parent_class).start_interactive_search {
281                from_glib(f(self.obj().unsafe_cast_ref::<TreeView>().to_glib_none().0))
282            } else {
283                false
284            }
285        }
286    }
287}
288
289impl<T: TreeViewImpl> TreeViewImplExt for T {}
290
291unsafe impl<T: TreeViewImpl> IsSubclassable<T> for TreeView {
292    fn class_init(class: &mut ::glib::Class<Self>) {
293        Self::parent_class_init::<T>(class);
294
295        if !crate::rt::is_initialized() {
296            panic!("GTK has to be initialized first");
297        }
298
299        let klass = class.as_mut();
300        klass.row_activated = Some(tree_view_row_activated::<T>);
301        klass.test_expand_row = Some(tree_view_test_expand_row::<T>);
302        klass.test_collapse_row = Some(tree_view_test_collapse_row::<T>);
303        klass.row_expanded = Some(tree_view_row_expanded::<T>);
304        klass.row_collapsed = Some(tree_view_row_collapsed::<T>);
305        klass.columns_changed = Some(tree_view_columns_changed::<T>);
306        klass.cursor_changed = Some(tree_view_cursor_changed::<T>);
307        klass.move_cursor = Some(tree_view_move_cursor::<T>);
308        klass.select_all = Some(tree_view_select_all::<T>);
309        klass.unselect_all = Some(tree_view_unselect_all::<T>);
310        klass.select_cursor_row = Some(tree_view_select_cursor_row::<T>);
311        klass.toggle_cursor_row = Some(tree_view_toggle_cursor_row::<T>);
312        klass.expand_collapse_cursor_row = Some(tree_view_expand_collapse_cursor_row::<T>);
313        klass.select_cursor_parent = Some(tree_view_select_cursor_parent::<T>);
314        klass.start_interactive_search = Some(tree_view_start_interactive_search::<T>);
315    }
316}
317
318unsafe extern "C" fn tree_view_row_activated<T: TreeViewImpl>(
319    ptr: *mut ffi::GtkTreeView,
320    pathptr: *mut ffi::GtkTreePath,
321    columnptr: *mut ffi::GtkTreeViewColumn,
322) {
323    unsafe {
324        let instance = &*(ptr as *mut T::Instance);
325        let imp = instance.imp();
326        let column: Option<Borrowed<TreeViewColumn>> = if columnptr.is_null() {
327            None
328        } else {
329            Some(from_glib_borrow(columnptr))
330        };
331        imp.row_activated(&from_glib_borrow(pathptr), column.as_deref());
332    }
333}
334
335unsafe extern "C" fn tree_view_test_expand_row<T: TreeViewImpl>(
336    ptr: *mut ffi::GtkTreeView,
337    iterptr: *mut ffi::GtkTreeIter,
338    pathptr: *mut ffi::GtkTreePath,
339) -> glib::ffi::gboolean {
340    unsafe {
341        let instance = &*(ptr as *mut T::Instance);
342        let imp = instance.imp();
343        imp.test_expand_row(&from_glib_borrow(iterptr), &from_glib_borrow(pathptr))
344            .into_glib()
345    }
346}
347
348unsafe extern "C" fn tree_view_test_collapse_row<T: TreeViewImpl>(
349    ptr: *mut ffi::GtkTreeView,
350    iterptr: *mut ffi::GtkTreeIter,
351    pathptr: *mut ffi::GtkTreePath,
352) -> glib::ffi::gboolean {
353    unsafe {
354        let instance = &*(ptr as *mut T::Instance);
355        let imp = instance.imp();
356        imp.test_collapse_row(&from_glib_borrow(iterptr), &from_glib_borrow(pathptr))
357            .into_glib()
358    }
359}
360
361unsafe extern "C" fn tree_view_row_expanded<T: TreeViewImpl>(
362    ptr: *mut ffi::GtkTreeView,
363    iterptr: *mut ffi::GtkTreeIter,
364    pathptr: *mut ffi::GtkTreePath,
365) {
366    unsafe {
367        let instance = &*(ptr as *mut T::Instance);
368        let imp = instance.imp();
369        imp.row_expanded(&from_glib_borrow(iterptr), &from_glib_borrow(pathptr));
370    }
371}
372
373unsafe extern "C" fn tree_view_row_collapsed<T: TreeViewImpl>(
374    ptr: *mut ffi::GtkTreeView,
375    iterptr: *mut ffi::GtkTreeIter,
376    pathptr: *mut ffi::GtkTreePath,
377) {
378    unsafe {
379        let instance = &*(ptr as *mut T::Instance);
380        let imp = instance.imp();
381        imp.row_collapsed(&from_glib_borrow(iterptr), &from_glib_borrow(pathptr));
382    }
383}
384
385unsafe extern "C" fn tree_view_columns_changed<T: TreeViewImpl>(ptr: *mut ffi::GtkTreeView) {
386    unsafe {
387        let instance = &*(ptr as *mut T::Instance);
388        let imp = instance.imp();
389        imp.columns_changed();
390    }
391}
392
393unsafe extern "C" fn tree_view_cursor_changed<T: TreeViewImpl>(ptr: *mut ffi::GtkTreeView) {
394    unsafe {
395        let instance = &*(ptr as *mut T::Instance);
396        let imp = instance.imp();
397        imp.cursor_changed();
398    }
399}
400
401unsafe extern "C" fn tree_view_move_cursor<T: TreeViewImpl>(
402    ptr: *mut ffi::GtkTreeView,
403    step: ffi::GtkMovementStep,
404    count: glib::ffi::gint,
405) -> glib::ffi::gboolean {
406    unsafe {
407        let instance = &*(ptr as *mut T::Instance);
408        let imp = instance.imp();
409        imp.move_cursor(from_glib(step), count).into_glib()
410    }
411}
412
413unsafe extern "C" fn tree_view_select_all<T: TreeViewImpl>(
414    ptr: *mut ffi::GtkTreeView,
415) -> glib::ffi::gboolean {
416    unsafe {
417        let instance = &*(ptr as *mut T::Instance);
418        let imp = instance.imp();
419        imp.select_all().into_glib()
420    }
421}
422
423unsafe extern "C" fn tree_view_unselect_all<T: TreeViewImpl>(
424    ptr: *mut ffi::GtkTreeView,
425) -> glib::ffi::gboolean {
426    unsafe {
427        let instance = &*(ptr as *mut T::Instance);
428        let imp = instance.imp();
429        imp.unselect_all().into_glib()
430    }
431}
432
433unsafe extern "C" fn tree_view_select_cursor_row<T: TreeViewImpl>(
434    ptr: *mut ffi::GtkTreeView,
435    start_editing: glib::ffi::gboolean,
436) -> glib::ffi::gboolean {
437    unsafe {
438        let instance = &*(ptr as *mut T::Instance);
439        let imp = instance.imp();
440        imp.select_cursor_row(from_glib(start_editing)).into_glib()
441    }
442}
443
444unsafe extern "C" fn tree_view_toggle_cursor_row<T: TreeViewImpl>(
445    ptr: *mut ffi::GtkTreeView,
446) -> glib::ffi::gboolean {
447    unsafe {
448        let instance = &*(ptr as *mut T::Instance);
449        let imp = instance.imp();
450        imp.toggle_cursor_row().into_glib()
451    }
452}
453
454unsafe extern "C" fn tree_view_expand_collapse_cursor_row<T: TreeViewImpl>(
455    ptr: *mut ffi::GtkTreeView,
456    logical: glib::ffi::gboolean,
457    expand: glib::ffi::gboolean,
458    open_all: glib::ffi::gboolean,
459) -> glib::ffi::gboolean {
460    unsafe {
461        let instance = &*(ptr as *mut T::Instance);
462        let imp = instance.imp();
463        imp.expand_collapse_cursor_row(from_glib(logical), from_glib(expand), from_glib(open_all))
464            .into_glib()
465    }
466}
467
468unsafe extern "C" fn tree_view_select_cursor_parent<T: TreeViewImpl>(
469    ptr: *mut ffi::GtkTreeView,
470) -> glib::ffi::gboolean {
471    unsafe {
472        let instance = &*(ptr as *mut T::Instance);
473        let imp = instance.imp();
474        imp.select_cursor_parent().into_glib()
475    }
476}
477
478unsafe extern "C" fn tree_view_start_interactive_search<T: TreeViewImpl>(
479    ptr: *mut ffi::GtkTreeView,
480) -> glib::ffi::gboolean {
481    unsafe {
482        let instance = &*(ptr as *mut T::Instance);
483        let imp = instance.imp();
484        imp.start_interactive_search().into_glib()
485    }
486}