1use 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>) {
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}