gtk4/subclass/
cell_renderer.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 subclassing [`CellRenderer`].
5
6use std::mem;
7
8use glib::{translate::*, GString};
9use libc::{c_char, c_int};
10
11use crate::{
12    ffi, prelude::*, subclass::prelude::*, CellEditable, CellRenderer, CellRendererState,
13    SizeRequestMode, Snapshot, Widget,
14};
15
16#[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
17#[allow(deprecated)]
18pub trait CellRendererImpl: ObjectImpl + ObjectSubclass<Type: IsA<CellRenderer>> {
19    fn activate<P: IsA<Widget>>(
20        &self,
21        event: Option<&gdk::Event>,
22        widget: &P,
23        path: &str,
24        background_area: &gdk::Rectangle,
25        cell_area: &gdk::Rectangle,
26        flags: CellRendererState,
27    ) -> bool {
28        self.parent_activate(event, widget, path, background_area, cell_area, flags)
29    }
30
31    fn editing_canceled(&self) {
32        self.parent_editing_canceled()
33    }
34
35    fn editing_started(&self, editable: &CellEditable, path: &str) {
36        self.parent_editing_started(editable, path)
37    }
38
39    #[doc(alias = "get_aligned_area")]
40    fn aligned_area<P: IsA<Widget>>(
41        &self,
42        widget: &P,
43        flags: CellRendererState,
44        cell_area: &gdk::Rectangle,
45    ) -> gdk::Rectangle {
46        self.parent_aligned_area(widget, flags, cell_area)
47    }
48
49    #[doc(alias = "get_preferred_height_for_width")]
50    fn preferred_height_for_width<P: IsA<Widget>>(&self, widget: &P, width: i32) -> (i32, i32) {
51        self.parent_preferred_height_for_width(widget, width)
52    }
53
54    #[doc(alias = "get_preferred_height")]
55    fn preferred_height<P: IsA<Widget>>(&self, widget: &P) -> (i32, i32) {
56        self.parent_preferred_height(widget)
57    }
58
59    #[doc(alias = "get_preferred_width_for_height")]
60    fn preferred_width_for_height<P: IsA<Widget>>(&self, widget: &P, height: i32) -> (i32, i32) {
61        self.parent_preferred_width_for_height(widget, height)
62    }
63
64    #[doc(alias = "get_preferred_width")]
65    fn preferred_width<P: IsA<Widget>>(&self, widget: &P) -> (i32, i32) {
66        self.parent_preferred_width(widget)
67    }
68
69    #[doc(alias = "get_request_mode")]
70    fn request_mode(&self) -> SizeRequestMode {
71        self.parent_request_mode()
72    }
73
74    fn snapshot<P: IsA<Widget>>(
75        &self,
76        snapshot: &Snapshot,
77        widget: &P,
78        background_area: &gdk::Rectangle,
79        cell_area: &gdk::Rectangle,
80        flags: CellRendererState,
81    ) {
82        self.parent_snapshot(snapshot, widget, background_area, cell_area, flags);
83    }
84
85    fn start_editing<P: IsA<Widget>>(
86        &self,
87        event: Option<&gdk::Event>,
88        widget: &P,
89        path: &str,
90        background_area: &gdk::Rectangle,
91        cell_area: &gdk::Rectangle,
92        flags: CellRendererState,
93    ) -> Option<CellEditable> {
94        self.parent_start_editing(event, widget, path, background_area, cell_area, flags)
95    }
96}
97
98#[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
99#[allow(deprecated)]
100pub trait CellRendererImplExt: CellRendererImpl {
101    fn parent_request_mode(&self) -> SizeRequestMode {
102        unsafe {
103            let data = Self::type_data();
104            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
105            let f = (*parent_class).get_request_mode.unwrap();
106            from_glib(f(self
107                .obj()
108                .unsafe_cast_ref::<CellRenderer>()
109                .to_glib_none()
110                .0))
111        }
112    }
113
114    fn parent_preferred_width<P: IsA<Widget>>(&self, widget: &P) -> (i32, i32) {
115        unsafe {
116            let data = Self::type_data();
117            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
118            let f = (*parent_class).get_preferred_width.unwrap();
119
120            let mut minimum_size = mem::MaybeUninit::uninit();
121            let mut natural_size = mem::MaybeUninit::uninit();
122            f(
123                self.obj()
124                    .unsafe_cast_ref::<CellRenderer>()
125                    .to_glib_none()
126                    .0,
127                widget.as_ref().to_glib_none().0,
128                minimum_size.as_mut_ptr(),
129                natural_size.as_mut_ptr(),
130            );
131            (minimum_size.assume_init(), natural_size.assume_init())
132        }
133    }
134
135    fn parent_preferred_width_for_height<P: IsA<Widget>>(
136        &self,
137        widget: &P,
138        height: i32,
139    ) -> (i32, i32) {
140        unsafe {
141            let data = Self::type_data();
142            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
143            let f = (*parent_class).get_preferred_width_for_height.unwrap();
144
145            let mut minimum_size = mem::MaybeUninit::uninit();
146            let mut natural_size = mem::MaybeUninit::uninit();
147            f(
148                self.obj()
149                    .unsafe_cast_ref::<CellRenderer>()
150                    .to_glib_none()
151                    .0,
152                widget.as_ref().to_glib_none().0,
153                height,
154                minimum_size.as_mut_ptr(),
155                natural_size.as_mut_ptr(),
156            );
157            (minimum_size.assume_init(), natural_size.assume_init())
158        }
159    }
160    fn parent_preferred_height<P: IsA<Widget>>(&self, widget: &P) -> (i32, i32) {
161        unsafe {
162            let data = Self::type_data();
163            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
164            let f = (*parent_class).get_preferred_height.unwrap();
165            let mut minimum_size = mem::MaybeUninit::uninit();
166            let mut natural_size = mem::MaybeUninit::uninit();
167            f(
168                self.obj()
169                    .unsafe_cast_ref::<CellRenderer>()
170                    .to_glib_none()
171                    .0,
172                widget.as_ref().to_glib_none().0,
173                minimum_size.as_mut_ptr(),
174                natural_size.as_mut_ptr(),
175            );
176            (minimum_size.assume_init(), natural_size.assume_init())
177        }
178    }
179    fn parent_preferred_height_for_width<P: IsA<Widget>>(
180        &self,
181        widget: &P,
182        width: i32,
183    ) -> (i32, i32) {
184        unsafe {
185            let data = Self::type_data();
186            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
187            let f = (*parent_class).get_preferred_height_for_width.unwrap();
188            let mut minimum_size = mem::MaybeUninit::uninit();
189            let mut natural_size = mem::MaybeUninit::uninit();
190            f(
191                self.obj()
192                    .unsafe_cast_ref::<CellRenderer>()
193                    .to_glib_none()
194                    .0,
195                widget.as_ref().to_glib_none().0,
196                width,
197                minimum_size.as_mut_ptr(),
198                natural_size.as_mut_ptr(),
199            );
200            (minimum_size.assume_init(), natural_size.assume_init())
201        }
202    }
203
204    fn parent_aligned_area<P: IsA<Widget>>(
205        &self,
206        widget: &P,
207        flags: CellRendererState,
208        cell_area: &gdk::Rectangle,
209    ) -> gdk::Rectangle {
210        unsafe {
211            let data = Self::type_data();
212            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
213            let mut aligned_area = gdk::Rectangle::uninitialized();
214            let f = (*parent_class).get_aligned_area.unwrap();
215            f(
216                self.obj()
217                    .unsafe_cast_ref::<CellRenderer>()
218                    .to_glib_none()
219                    .0,
220                widget.as_ref().to_glib_none().0,
221                flags.into_glib(),
222                cell_area.to_glib_none().0,
223                aligned_area.to_glib_none_mut().0,
224            );
225            aligned_area
226        }
227    }
228
229    fn parent_snapshot<P: IsA<Widget>>(
230        &self,
231        snapshot: &Snapshot,
232        widget: &P,
233        background_area: &gdk::Rectangle,
234        cell_area: &gdk::Rectangle,
235        flags: CellRendererState,
236    ) {
237        unsafe {
238            let data = Self::type_data();
239            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
240            if let Some(f) = (*parent_class).snapshot {
241                f(
242                    self.obj()
243                        .unsafe_cast_ref::<CellRenderer>()
244                        .to_glib_none()
245                        .0,
246                    snapshot.to_glib_none().0,
247                    widget.as_ref().to_glib_none().0,
248                    background_area.to_glib_none().0,
249                    cell_area.to_glib_none().0,
250                    flags.into_glib(),
251                )
252            }
253        }
254    }
255
256    // Returns true if the event was consumed/handled
257    fn parent_activate<P: IsA<Widget>>(
258        &self,
259        event: Option<&gdk::Event>,
260        widget: &P,
261        path: &str,
262        background_area: &gdk::Rectangle,
263        cell_area: &gdk::Rectangle,
264        flags: CellRendererState,
265    ) -> bool {
266        unsafe {
267            let data = Self::type_data();
268            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
269            if let Some(f) = (*parent_class).activate {
270                from_glib(f(
271                    self.obj()
272                        .unsafe_cast_ref::<CellRenderer>()
273                        .to_glib_none()
274                        .0,
275                    mut_override(event.to_glib_none().0),
276                    widget.as_ref().to_glib_none().0,
277                    path.to_glib_none().0,
278                    background_area.to_glib_none().0,
279                    cell_area.to_glib_none().0,
280                    flags.into_glib(),
281                ))
282            } else {
283                false
284            }
285        }
286    }
287
288    fn parent_start_editing<P: IsA<Widget>>(
289        &self,
290        event: Option<&gdk::Event>,
291        widget: &P,
292        path: &str,
293        background_area: &gdk::Rectangle,
294        cell_area: &gdk::Rectangle,
295        flags: CellRendererState,
296    ) -> Option<CellEditable> {
297        unsafe {
298            let data = Self::type_data();
299            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
300            if let Some(f) = (*parent_class).start_editing {
301                from_glib_none(f(
302                    self.obj()
303                        .unsafe_cast_ref::<CellRenderer>()
304                        .to_glib_none()
305                        .0,
306                    mut_override(event.to_glib_none().0),
307                    widget.as_ref().to_glib_none().0,
308                    path.to_glib_none().0,
309                    background_area.to_glib_none().0,
310                    cell_area.to_glib_none().0,
311                    flags.into_glib(),
312                ))
313            } else {
314                None
315            }
316        }
317    }
318
319    fn parent_editing_canceled(&self) {
320        unsafe {
321            let data = Self::type_data();
322            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
323            if let Some(f) = (*parent_class).editing_canceled {
324                f(self
325                    .obj()
326                    .unsafe_cast_ref::<CellRenderer>()
327                    .to_glib_none()
328                    .0)
329            }
330        }
331    }
332
333    fn parent_editing_started(&self, editable: &CellEditable, path: &str) {
334        unsafe {
335            let data = Self::type_data();
336            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkCellRendererClass;
337            if let Some(f) = (*parent_class).editing_started {
338                f(
339                    self.obj()
340                        .unsafe_cast_ref::<CellRenderer>()
341                        .to_glib_none()
342                        .0,
343                    editable.to_glib_none().0,
344                    path.to_glib_none().0,
345                )
346            }
347        }
348    }
349}
350
351impl<T: CellRendererImpl> CellRendererImplExt for T {}
352
353unsafe impl<T: CellRendererImpl> IsSubclassable<T> for CellRenderer {
354    fn class_init(class: &mut ::glib::Class<Self>) {
355        Self::parent_class_init::<T>(class);
356
357        assert_initialized_main_thread!();
358
359        let klass = class.as_mut();
360
361        klass.activate = Some(cell_renderer_activate::<T>);
362        klass.editing_canceled = Some(cell_renderer_editing_canceled::<T>);
363        klass.editing_started = Some(cell_renderer_editing_started::<T>);
364        klass.get_aligned_area = Some(cell_renderer_get_aligned_area::<T>);
365        klass.get_preferred_height_for_width =
366            Some(cell_renderer_get_preferred_height_for_width::<T>);
367        klass.get_preferred_height = Some(cell_renderer_get_preferred_height::<T>);
368        klass.get_preferred_width_for_height =
369            Some(cell_renderer_get_preferred_width_for_height::<T>);
370        klass.get_preferred_width = Some(cell_renderer_get_preferred_width::<T>);
371        klass.get_request_mode = Some(cell_renderer_get_request_mode::<T>);
372        klass.snapshot = Some(cell_renderer_snapshot::<T>);
373        klass.start_editing = Some(cell_renderer_start_editing::<T>);
374    }
375}
376
377unsafe extern "C" fn cell_renderer_activate<T: CellRendererImpl>(
378    ptr: *mut ffi::GtkCellRenderer,
379    evtptr: *mut gdk::ffi::GdkEvent,
380    wdgtptr: *mut ffi::GtkWidget,
381    pathptr: *const c_char,
382    bgptr: *const gdk::ffi::GdkRectangle,
383    cellptr: *const gdk::ffi::GdkRectangle,
384    flags: ffi::GtkCellRendererState,
385) -> glib::ffi::gboolean {
386    let instance = &*(ptr as *mut T::Instance);
387    let imp = instance.imp();
388    let widget: Borrowed<Widget> = from_glib_borrow(wdgtptr);
389    let evt: Borrowed<Option<gdk::Event>> = from_glib_borrow(evtptr);
390
391    imp.activate(
392        evt.as_ref().as_ref(),
393        &*widget,
394        &GString::from_glib_borrow(pathptr),
395        &from_glib_borrow(bgptr),
396        &from_glib_borrow(cellptr),
397        from_glib(flags),
398    )
399    .into_glib()
400}
401
402unsafe extern "C" fn cell_renderer_editing_canceled<T: CellRendererImpl>(
403    ptr: *mut ffi::GtkCellRenderer,
404) {
405    let instance = &*(ptr as *mut T::Instance);
406    let imp = instance.imp();
407
408    imp.editing_canceled();
409}
410
411unsafe extern "C" fn cell_renderer_editing_started<T: CellRendererImpl>(
412    ptr: *mut ffi::GtkCellRenderer,
413    editableptr: *mut ffi::GtkCellEditable,
414    pathptr: *const c_char,
415) {
416    let instance = &*(ptr as *mut T::Instance);
417    let imp = instance.imp();
418    let editable = from_glib_borrow(editableptr);
419
420    imp.editing_started(&editable, &GString::from_glib_borrow(pathptr));
421}
422
423unsafe extern "C" fn cell_renderer_get_aligned_area<T: CellRendererImpl>(
424    ptr: *mut ffi::GtkCellRenderer,
425    wdgtptr: *mut ffi::GtkWidget,
426    flags: ffi::GtkCellRendererState,
427    cellarea: *const gdk::ffi::GdkRectangle,
428    alignedptr: *mut gdk::ffi::GdkRectangle,
429) {
430    let instance = &*(ptr as *mut T::Instance);
431    let imp = instance.imp();
432    let widget: Borrowed<Widget> = from_glib_borrow(wdgtptr);
433
434    let rectangle = imp.aligned_area(&*widget, from_glib(flags), &from_glib_borrow(cellarea));
435    *alignedptr = *rectangle.to_glib_none().0;
436}
437
438unsafe extern "C" fn cell_renderer_get_preferred_height_for_width<T: CellRendererImpl>(
439    ptr: *mut ffi::GtkCellRenderer,
440    wdgtptr: *mut ffi::GtkWidget,
441    width: c_int,
442    min_height_ptr: *mut c_int,
443    nat_height_ptr: *mut c_int,
444) {
445    let instance = &*(ptr as *mut T::Instance);
446    let imp = instance.imp();
447    let widget: Borrowed<Widget> = from_glib_borrow(wdgtptr);
448
449    let (min_height, nat_height) = imp.preferred_height_for_width(&*widget, width);
450    if !min_height_ptr.is_null() {
451        *min_height_ptr = min_height;
452    }
453    if !nat_height_ptr.is_null() {
454        *nat_height_ptr = nat_height;
455    }
456}
457
458unsafe extern "C" fn cell_renderer_get_preferred_height<T: CellRendererImpl>(
459    ptr: *mut ffi::GtkCellRenderer,
460    wdgtptr: *mut ffi::GtkWidget,
461    minptr: *mut c_int,
462    natptr: *mut c_int,
463) {
464    let instance = &*(ptr as *mut T::Instance);
465    let imp = instance.imp();
466    let widget: Borrowed<Widget> = from_glib_borrow(wdgtptr);
467
468    let (min_size, nat_size) = imp.preferred_height(&*widget);
469    if !minptr.is_null() {
470        *minptr = min_size;
471    }
472    if !natptr.is_null() {
473        *natptr = nat_size;
474    }
475}
476
477unsafe extern "C" fn cell_renderer_get_preferred_width_for_height<T: CellRendererImpl>(
478    ptr: *mut ffi::GtkCellRenderer,
479    wdgtptr: *mut ffi::GtkWidget,
480    height: c_int,
481    min_width_ptr: *mut c_int,
482    nat_width_ptr: *mut c_int,
483) {
484    let instance = &*(ptr as *mut T::Instance);
485    let imp = instance.imp();
486    let widget: Borrowed<Widget> = from_glib_borrow(wdgtptr);
487
488    let (min_width, nat_width) = imp.preferred_width_for_height(&*widget, height);
489    if !min_width_ptr.is_null() {
490        *min_width_ptr = min_width;
491    }
492    if !nat_width_ptr.is_null() {
493        *nat_width_ptr = nat_width;
494    }
495}
496
497unsafe extern "C" fn cell_renderer_get_preferred_width<T: CellRendererImpl>(
498    ptr: *mut ffi::GtkCellRenderer,
499    wdgtptr: *mut ffi::GtkWidget,
500    minptr: *mut c_int,
501    natptr: *mut c_int,
502) {
503    let instance = &*(ptr as *mut T::Instance);
504    let imp = instance.imp();
505    let widget: Borrowed<Widget> = from_glib_borrow(wdgtptr);
506
507    let (min_size, nat_size) = imp.preferred_width(&*widget);
508    if !minptr.is_null() {
509        *minptr = min_size;
510    }
511    if !natptr.is_null() {
512        *natptr = nat_size;
513    }
514}
515
516unsafe extern "C" fn cell_renderer_get_request_mode<T: CellRendererImpl>(
517    ptr: *mut ffi::GtkCellRenderer,
518) -> ffi::GtkSizeRequestMode {
519    let instance = &*(ptr as *mut T::Instance);
520    let imp = instance.imp();
521
522    imp.request_mode().into_glib()
523}
524
525unsafe extern "C" fn cell_renderer_snapshot<T: CellRendererImpl>(
526    ptr: *mut ffi::GtkCellRenderer,
527    snapshotptr: *mut ffi::GtkSnapshot,
528    wdgtptr: *mut ffi::GtkWidget,
529    bgptr: *const gdk::ffi::GdkRectangle,
530    cellptr: *const gdk::ffi::GdkRectangle,
531    flags: ffi::GtkCellRendererState,
532) {
533    let instance = &*(ptr as *mut T::Instance);
534    let imp = instance.imp();
535    let widget: Borrowed<Widget> = from_glib_borrow(wdgtptr);
536    let snapshot: Borrowed<Snapshot> = from_glib_borrow(snapshotptr);
537
538    imp.snapshot(
539        &snapshot,
540        &*widget,
541        &from_glib_borrow(bgptr),
542        &from_glib_borrow(cellptr),
543        from_glib(flags),
544    );
545}
546
547unsafe extern "C" fn cell_renderer_start_editing<T: CellRendererImpl>(
548    ptr: *mut ffi::GtkCellRenderer,
549    evtptr: *mut gdk::ffi::GdkEvent,
550    wdgtptr: *mut ffi::GtkWidget,
551    pathptr: *const c_char,
552    bgptr: *const gdk::ffi::GdkRectangle,
553    cellptr: *const gdk::ffi::GdkRectangle,
554    flags: ffi::GtkCellRendererState,
555) -> *mut ffi::GtkCellEditable {
556    let instance = &*(ptr as *mut T::Instance);
557    let imp = instance.imp();
558    let widget: Borrowed<Widget> = from_glib_borrow(wdgtptr);
559    let evt: Borrowed<Option<gdk::Event>> = from_glib_borrow(evtptr);
560
561    imp.start_editing(
562        evt.as_ref().as_ref(),
563        &*widget,
564        &GString::from_glib_borrow(pathptr),
565        &from_glib_borrow(bgptr),
566        &from_glib_borrow(cellptr),
567        from_glib(flags),
568    )
569    .to_glib_none()
570    .0
571}