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