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