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