Skip to main content

gtk4/subclass/
cell_layout.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3// rustdoc-stripper-ignore-next
4//! Traits intended for implementing the [`CellLayout`] interface.
5use std::sync::OnceLock;
6
7use glib::{Quark, translate::*};
8
9use crate::{
10    CellArea, CellLayout, CellRenderer, TreeIter, TreeModel, ffi, prelude::*, subclass::prelude::*,
11};
12
13#[derive(Debug)]
14pub struct CellLayoutDataCallback {
15    callback: ffi::GtkCellLayoutDataFunc,
16    user_data: glib::ffi::gpointer,
17    destroy_notify: glib::ffi::GDestroyNotify,
18}
19
20impl CellLayoutDataCallback {
21    pub fn call<C: IsA<CellLayout>, R: IsA<CellRenderer>, M: IsA<TreeModel>>(
22        &self,
23        cell_layout: &C,
24        cell_renderer: &R,
25        model: &M,
26        iter: &TreeIter,
27    ) {
28        unsafe {
29            if let Some(callback) = self.callback {
30                callback(
31                    cell_layout.as_ref().to_glib_none().0,
32                    cell_renderer.as_ref().to_glib_none().0,
33                    model.as_ref().to_glib_none().0,
34                    mut_override(iter.to_glib_none().0),
35                    self.user_data,
36                );
37            }
38        }
39    }
40}
41
42impl Drop for CellLayoutDataCallback {
43    #[inline]
44    fn drop(&mut self) {
45        unsafe {
46            if let Some(destroy_notify) = self.destroy_notify {
47                destroy_notify(self.user_data);
48            }
49        }
50    }
51}
52
53#[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
54#[allow(deprecated)]
55pub trait CellLayoutImpl: ObjectImpl + ObjectSubclass<Type: IsA<CellLayout>> {
56    fn add_attribute<R: IsA<CellRenderer>>(&self, cell: &R, attribute: &str, column: i32) {
57        self.parent_add_attribute(cell, attribute, column)
58    }
59
60    fn clear_attributes<R: IsA<CellRenderer>>(&self, cell: &R) {
61        self.parent_clear_attributes(cell)
62    }
63
64    fn cells(&self) -> Vec<CellRenderer> {
65        self.parent_cells()
66    }
67
68    fn set_cell_data_func<R: IsA<CellRenderer>>(
69        &self,
70
71        cell: &R,
72        callback: Option<CellLayoutDataCallback>,
73    ) {
74        self.parent_set_cell_data_func(cell, callback)
75    }
76
77    fn reorder<R: IsA<CellRenderer>>(&self, cell: &R, position: i32) {
78        self.parent_reorder(cell, position)
79    }
80
81    fn clear(&self) {
82        self.parent_clear()
83    }
84
85    fn pack_start<R: IsA<CellRenderer>>(&self, cell: &R, expand: bool) {
86        self.parent_pack_start(cell, expand)
87    }
88
89    fn pack_end<R: IsA<CellRenderer>>(&self, cell: &R, expand: bool) {
90        self.parent_pack_end(cell, expand)
91    }
92
93    fn area(&self) -> Option<CellArea> {
94        self.parent_area()
95    }
96}
97
98#[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
99#[allow(deprecated)]
100pub trait CellLayoutImplExt: CellLayoutImpl {
101    fn parent_add_attribute<R: IsA<CellRenderer>>(&self, cell: &R, attribute: &str, column: i32) {
102        unsafe {
103            let type_data = Self::type_data();
104            let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
105                as *const ffi::GtkCellLayoutIface;
106
107            if let Some(f) = (*parent_iface).add_attribute {
108                f(
109                    self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
110                    cell.as_ref().to_glib_none().0,
111                    attribute.to_glib_none().0,
112                    column,
113                );
114            }
115        }
116    }
117
118    fn parent_clear_attributes<R: IsA<CellRenderer>>(&self, cell: &R) {
119        unsafe {
120            let type_data = Self::type_data();
121            let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
122                as *const ffi::GtkCellLayoutIface;
123
124            if let Some(f) = (*parent_iface).clear_attributes {
125                f(
126                    self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
127                    cell.as_ref().to_glib_none().0,
128                );
129            }
130        }
131    }
132
133    fn parent_cells(&self) -> Vec<CellRenderer> {
134        unsafe {
135            let type_data = Self::type_data();
136            let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
137                as *const ffi::GtkCellLayoutIface;
138
139            let f = (*parent_iface)
140                .get_cells
141                .as_ref()
142                .expect("no parent \"get_cells\" implementation");
143
144            let cells = f(self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0);
145            FromGlibPtrArrayContainerAsVec::from_glib_container_as_vec(cells)
146        }
147    }
148
149    fn parent_set_cell_data_func<R: IsA<CellRenderer>>(
150        &self,
151
152        cell: &R,
153        callback: Option<CellLayoutDataCallback>,
154    ) {
155        unsafe {
156            let type_data = Self::type_data();
157            let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
158                as *const ffi::GtkCellLayoutIface;
159
160            let f = (*parent_iface)
161                .set_cell_data_func
162                .as_ref()
163                .expect("no parent \"set_cell_data_func\" implementation");
164
165            if let Some(data_cb) = callback {
166                f(
167                    self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
168                    cell.as_ref().to_glib_none().0,
169                    data_cb.callback,
170                    data_cb.user_data,
171                    data_cb.destroy_notify,
172                );
173            } else {
174                f(
175                    self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
176                    cell.as_ref().to_glib_none().0,
177                    None,
178                    std::ptr::null_mut(),
179                    None,
180                );
181            }
182        }
183    }
184
185    fn parent_reorder<R: IsA<CellRenderer>>(&self, cell: &R, position: i32) {
186        {
187            unsafe {
188                let type_data = Self::type_data();
189                let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
190                    as *const ffi::GtkCellLayoutIface;
191
192                if let Some(f) = (*parent_iface).reorder {
193                    f(
194                        self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
195                        cell.as_ref().to_glib_none().0,
196                        position,
197                    );
198                }
199            }
200        }
201    }
202
203    fn parent_clear(&self) {
204        unsafe {
205            let type_data = Self::type_data();
206            let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
207                as *const ffi::GtkCellLayoutIface;
208
209            if let Some(f) = (*parent_iface).clear {
210                f(self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0);
211            }
212        }
213    }
214
215    fn parent_pack_start<R: IsA<CellRenderer>>(&self, cell: &R, expand: bool) {
216        unsafe {
217            let type_data = Self::type_data();
218            let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
219                as *const ffi::GtkCellLayoutIface;
220
221            if let Some(f) = (*parent_iface).pack_start {
222                f(
223                    self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
224                    cell.as_ref().to_glib_none().0,
225                    expand.into_glib(),
226                );
227            }
228        }
229    }
230
231    fn parent_pack_end<R: IsA<CellRenderer>>(&self, cell: &R, expand: bool) {
232        unsafe {
233            let type_data = Self::type_data();
234            let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
235                as *const ffi::GtkCellLayoutIface;
236
237            if let Some(f) = (*parent_iface).pack_end {
238                f(
239                    self.obj().unsafe_cast_ref::<CellLayout>().to_glib_none().0,
240                    cell.as_ref().to_glib_none().0,
241                    expand.into_glib(),
242                );
243            }
244        }
245    }
246
247    fn parent_area(&self) -> Option<CellArea> {
248        unsafe {
249            let type_data = Self::type_data();
250            let parent_iface = type_data.as_ref().parent_interface::<CellLayout>()
251                as *const ffi::GtkCellLayoutIface;
252
253            (*parent_iface).get_area.map(|f| {
254                from_glib_none(f(self
255                    .obj()
256                    .unsafe_cast_ref::<CellLayout>()
257                    .to_glib_none()
258                    .0))
259            })
260        }
261    }
262}
263
264impl<T: CellLayoutImpl> CellLayoutImplExt for T {}
265
266unsafe impl<T: CellLayoutImpl> IsImplementable<T> for CellLayout {
267    fn interface_init(iface: &mut glib::Interface<Self>) {
268        let iface = iface.as_mut();
269
270        assert_initialized_main_thread!();
271
272        iface.get_area = Some(cell_layout_get_area::<T>);
273        iface.pack_start = Some(cell_layout_pack_start::<T>);
274        iface.pack_end = Some(cell_layout_pack_end::<T>);
275        iface.clear = Some(cell_layout_clear::<T>);
276        iface.reorder = Some(cell_layout_reorder::<T>);
277        iface.add_attribute = Some(cell_layout_add_attribute::<T>);
278        iface.clear_attributes = Some(cell_layout_clear_attributes::<T>);
279        iface.set_cell_data_func = Some(cell_layout_set_cell_data_func::<T>);
280        iface.get_cells = Some(cell_layout_get_cells::<T>);
281    }
282}
283
284unsafe extern "C" fn cell_layout_get_area<T: CellLayoutImpl>(
285    cell_layout: *mut ffi::GtkCellLayout,
286) -> *mut ffi::GtkCellArea {
287    unsafe {
288        let instance = &*(cell_layout as *mut T::Instance);
289        let imp = instance.imp();
290
291        imp.area().into_glib_ptr()
292    }
293}
294
295unsafe extern "C" fn cell_layout_pack_start<T: CellLayoutImpl>(
296    cell_layout: *mut ffi::GtkCellLayout,
297    cellptr: *mut ffi::GtkCellRenderer,
298    expand: glib::ffi::gboolean,
299) {
300    unsafe {
301        let instance = &*(cell_layout as *mut T::Instance);
302        let imp = instance.imp();
303        let cell: Borrowed<CellRenderer> = from_glib_borrow(cellptr);
304
305        imp.pack_start(&*cell, from_glib(expand))
306    }
307}
308
309unsafe extern "C" fn cell_layout_pack_end<T: CellLayoutImpl>(
310    cell_layout: *mut ffi::GtkCellLayout,
311    cellptr: *mut ffi::GtkCellRenderer,
312    expand: glib::ffi::gboolean,
313) {
314    unsafe {
315        let instance = &*(cell_layout as *mut T::Instance);
316        let imp = instance.imp();
317        let cell: Borrowed<CellRenderer> = from_glib_borrow(cellptr);
318
319        imp.pack_end(&*cell, from_glib(expand))
320    }
321}
322
323unsafe extern "C" fn cell_layout_clear<T: CellLayoutImpl>(cell_layout: *mut ffi::GtkCellLayout) {
324    unsafe {
325        let instance = &*(cell_layout as *mut T::Instance);
326        let imp = instance.imp();
327
328        imp.clear()
329    }
330}
331
332unsafe extern "C" fn cell_layout_reorder<T: CellLayoutImpl>(
333    cell_layout: *mut ffi::GtkCellLayout,
334    cellptr: *mut ffi::GtkCellRenderer,
335    position: i32,
336) {
337    unsafe {
338        let instance = &*(cell_layout as *mut T::Instance);
339        let imp = instance.imp();
340        let cell: Borrowed<CellRenderer> = from_glib_borrow(cellptr);
341
342        imp.reorder(&*cell, position)
343    }
344}
345
346unsafe extern "C" fn cell_layout_add_attribute<T: CellLayoutImpl>(
347    cell_layout: *mut ffi::GtkCellLayout,
348    cellptr: *mut ffi::GtkCellRenderer,
349    attributeptr: *const libc::c_char,
350    column: i32,
351) {
352    unsafe {
353        let instance = &*(cell_layout as *mut T::Instance);
354        let imp = instance.imp();
355        let cell: Borrowed<CellRenderer> = from_glib_borrow(cellptr);
356        let attribute: Borrowed<glib::GString> = from_glib_borrow(attributeptr);
357
358        imp.add_attribute(&*cell, &attribute, column)
359    }
360}
361
362unsafe extern "C" fn cell_layout_clear_attributes<T: CellLayoutImpl>(
363    cell_layout: *mut ffi::GtkCellLayout,
364    cellptr: *mut ffi::GtkCellRenderer,
365) {
366    unsafe {
367        let instance = &*(cell_layout as *mut T::Instance);
368        let imp = instance.imp();
369        let cell: Borrowed<CellRenderer> = from_glib_borrow(cellptr);
370
371        imp.clear_attributes(&*cell)
372    }
373}
374
375unsafe extern "C" fn cell_layout_set_cell_data_func<T: CellLayoutImpl>(
376    cell_layout: *mut ffi::GtkCellLayout,
377    cellptr: *mut ffi::GtkCellRenderer,
378    callback: ffi::GtkCellLayoutDataFunc,
379    user_data: glib::ffi::gpointer,
380    destroy_notify: glib::ffi::GDestroyNotify,
381) {
382    unsafe {
383        let instance = &*(cell_layout as *mut T::Instance);
384        let imp = instance.imp();
385
386        let cell: Borrowed<CellRenderer> = from_glib_borrow(cellptr);
387
388        let callback = if callback.is_none() {
389            None
390        } else {
391            Some(CellLayoutDataCallback {
392                callback,
393                user_data,
394                destroy_notify,
395            })
396        };
397
398        imp.set_cell_data_func(&*cell, callback)
399    }
400}
401
402unsafe extern "C" fn cell_layout_get_cells<T: CellLayoutImpl>(
403    cell_layout: *mut ffi::GtkCellLayout,
404) -> *mut glib::ffi::GList {
405    unsafe {
406        let instance = &*(cell_layout as *mut T::Instance);
407        let imp = instance.imp();
408
409        let cells = imp.cells();
410
411        static QUARK: OnceLock<Quark> = OnceLock::new();
412        let quark = *QUARK.get_or_init(|| Quark::from_str("gtk-rs-subclass-cell-layout-get-cells"));
413
414        // transfer container: list owned by the caller by not the actual content
415        // so we need to keep the cells around and return a ptr of the list
416        imp.obj().set_qdata(quark, cells.clone());
417        cells.to_glib_container().0
418    }
419}