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::{translate::*, Quark};
8
9use crate::{
10    ffi, prelude::*, subclass::prelude::*, CellArea, CellLayout, CellRenderer, TreeIter, TreeModel,
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    let instance = &*(cell_layout as *mut T::Instance);
288    let imp = instance.imp();
289
290    imp.area().into_glib_ptr()
291}
292
293unsafe extern "C" fn cell_layout_pack_start<T: CellLayoutImpl>(
294    cell_layout: *mut ffi::GtkCellLayout,
295    cellptr: *mut ffi::GtkCellRenderer,
296    expand: glib::ffi::gboolean,
297) {
298    let instance = &*(cell_layout as *mut T::Instance);
299    let imp = instance.imp();
300    let cell: Borrowed<CellRenderer> = from_glib_borrow(cellptr);
301
302    imp.pack_start(&*cell, from_glib(expand))
303}
304
305unsafe extern "C" fn cell_layout_pack_end<T: CellLayoutImpl>(
306    cell_layout: *mut ffi::GtkCellLayout,
307    cellptr: *mut ffi::GtkCellRenderer,
308    expand: glib::ffi::gboolean,
309) {
310    let instance = &*(cell_layout as *mut T::Instance);
311    let imp = instance.imp();
312    let cell: Borrowed<CellRenderer> = from_glib_borrow(cellptr);
313
314    imp.pack_end(&*cell, from_glib(expand))
315}
316
317unsafe extern "C" fn cell_layout_clear<T: CellLayoutImpl>(cell_layout: *mut ffi::GtkCellLayout) {
318    let instance = &*(cell_layout as *mut T::Instance);
319    let imp = instance.imp();
320
321    imp.clear()
322}
323
324unsafe extern "C" fn cell_layout_reorder<T: CellLayoutImpl>(
325    cell_layout: *mut ffi::GtkCellLayout,
326    cellptr: *mut ffi::GtkCellRenderer,
327    position: i32,
328) {
329    let instance = &*(cell_layout as *mut T::Instance);
330    let imp = instance.imp();
331    let cell: Borrowed<CellRenderer> = from_glib_borrow(cellptr);
332
333    imp.reorder(&*cell, position)
334}
335
336unsafe extern "C" fn cell_layout_add_attribute<T: CellLayoutImpl>(
337    cell_layout: *mut ffi::GtkCellLayout,
338    cellptr: *mut ffi::GtkCellRenderer,
339    attributeptr: *const libc::c_char,
340    column: i32,
341) {
342    let instance = &*(cell_layout as *mut T::Instance);
343    let imp = instance.imp();
344    let cell: Borrowed<CellRenderer> = from_glib_borrow(cellptr);
345    let attribute: Borrowed<glib::GString> = from_glib_borrow(attributeptr);
346
347    imp.add_attribute(&*cell, &attribute, column)
348}
349
350unsafe extern "C" fn cell_layout_clear_attributes<T: CellLayoutImpl>(
351    cell_layout: *mut ffi::GtkCellLayout,
352    cellptr: *mut ffi::GtkCellRenderer,
353) {
354    let instance = &*(cell_layout as *mut T::Instance);
355    let imp = instance.imp();
356    let cell: Borrowed<CellRenderer> = from_glib_borrow(cellptr);
357
358    imp.clear_attributes(&*cell)
359}
360
361unsafe extern "C" fn cell_layout_set_cell_data_func<T: CellLayoutImpl>(
362    cell_layout: *mut ffi::GtkCellLayout,
363    cellptr: *mut ffi::GtkCellRenderer,
364    callback: ffi::GtkCellLayoutDataFunc,
365    user_data: glib::ffi::gpointer,
366    destroy_notify: glib::ffi::GDestroyNotify,
367) {
368    let instance = &*(cell_layout as *mut T::Instance);
369    let imp = instance.imp();
370
371    let cell: Borrowed<CellRenderer> = from_glib_borrow(cellptr);
372
373    let callback = if callback.is_none() {
374        None
375    } else {
376        Some(CellLayoutDataCallback {
377            callback,
378            user_data,
379            destroy_notify,
380        })
381    };
382
383    imp.set_cell_data_func(&*cell, callback)
384}
385
386unsafe extern "C" fn cell_layout_get_cells<T: CellLayoutImpl>(
387    cell_layout: *mut ffi::GtkCellLayout,
388) -> *mut glib::ffi::GList {
389    let instance = &*(cell_layout as *mut T::Instance);
390    let imp = instance.imp();
391
392    let cells = imp.cells();
393
394    static QUARK: OnceLock<Quark> = OnceLock::new();
395    let quark = *QUARK.get_or_init(|| Quark::from_str("gtk-rs-subclass-cell-layout-get-cells"));
396
397    // transfer container: list owned by the caller by not the actual content
398    // so we need to keep the cells around and return a ptr of the list
399    imp.obj().set_qdata(quark, cells.clone());
400    cells.to_glib_container().0
401}