1use 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 imp.obj().set_qdata(quark, cells.clone());
400 cells.to_glib_container().0
401}