gtk4/subclass/
layout_manager.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 [`LayoutManager`](crate::LayoutManager).
5
6use glib::translate::*;
7use libc::c_int;
8
9use crate::{
10    ffi, prelude::*, subclass::prelude::*, LayoutChild, LayoutManager, Orientation,
11    SizeRequestMode, Widget,
12};
13
14pub trait LayoutManagerImpl: LayoutManagerImplExt + ObjectImpl {
15    /// Assigns the given @width, @height, and @baseline to
16    /// a @widget, and computes the position and sizes of the children of
17    /// the @widget using the layout management policy of @self.
18    /// ## `widget`
19    /// the [`Widget`][crate::Widget] using @self
20    /// ## `width`
21    /// the new width of the @widget
22    /// ## `height`
23    /// the new height of the @widget
24    /// ## `baseline`
25    /// the baseline position of the @widget, or -1
26    fn allocate(&self, widget: &Widget, width: i32, height: i32, baseline: i32) {
27        self.parent_allocate(widget, width, height, baseline)
28    }
29
30    /// Create a [`LayoutChild`][crate::LayoutChild] instance for the given @for_child widget.
31    /// ## `widget`
32    /// the widget using the @self
33    /// ## `for_child`
34    /// the child of @widget
35    ///
36    /// # Returns
37    ///
38    /// a [`LayoutChild`][crate::LayoutChild]
39    fn create_layout_child(&self, widget: &Widget, for_child: &Widget) -> LayoutChild {
40        self.parent_create_layout_child(widget, for_child)
41    }
42    // rustdoc-stripper-ignore-next
43    /// Only set if the child implemented LayoutChildImpl
44    fn layout_child_type() -> Option<glib::Type> {
45        None
46    }
47
48    /// a virtual function, used to return the preferred
49    ///   request mode for the layout manager; for instance, "width for height"
50    ///   or "height for width"; see [`SizeRequestMode`][crate::SizeRequestMode]
51    #[doc(alias = "get_request_mode")]
52    fn request_mode(&self, widget: &Widget) -> SizeRequestMode {
53        self.parent_request_mode(widget)
54    }
55
56    /// Measures the size of the @widget using @self, for the
57    /// given @orientation and size.
58    ///
59    /// See the [`Widget`][crate::Widget] documentation on layout management for
60    /// more details.
61    /// ## `widget`
62    /// the [`Widget`][crate::Widget] using @self
63    /// ## `orientation`
64    /// the orientation to measure
65    /// ## `for_size`
66    /// Size for the opposite of @orientation; for instance, if
67    ///   the @orientation is [`Orientation::Horizontal`][crate::Orientation::Horizontal], this is the height
68    ///   of the widget; if the @orientation is [`Orientation::Vertical`][crate::Orientation::Vertical], this
69    ///   is the width of the widget. This allows to measure the height for the
70    ///   given width, and the width for the given height. Use -1 if the size
71    ///   is not known
72    ///
73    /// # Returns
74    ///
75    ///
76    /// ## `minimum`
77    /// the minimum size for the given size and
78    ///   orientation
79    ///
80    /// ## `natural`
81    /// the natural, or preferred size for the
82    ///   given size and orientation
83    ///
84    /// ## `minimum_baseline`
85    /// the baseline position for the
86    ///   minimum size
87    ///
88    /// ## `natural_baseline`
89    /// the baseline position for the
90    ///   natural size
91    fn measure(
92        &self,
93        widget: &Widget,
94        orientation: Orientation,
95        for_size: i32,
96    ) -> (i32, i32, i32, i32) {
97        self.parent_measure(widget, orientation, for_size)
98    }
99
100    /// a virtual function, called when the widget using the layout
101    ///   manager is attached to a [`Root`][crate::Root]
102    fn root(&self) {
103        self.parent_root()
104    }
105
106    /// a virtual function, called when the widget using the layout
107    ///   manager is detached from a [`Root`][crate::Root]
108    fn unroot(&self) {
109        self.parent_unroot()
110    }
111}
112
113mod sealed {
114    pub trait Sealed {}
115    impl<T: super::LayoutManagerImplExt> Sealed for T {}
116}
117
118pub trait LayoutManagerImplExt: sealed::Sealed + ObjectSubclass {
119    fn parent_allocate(&self, widget: &Widget, width: i32, height: i32, baseline: i32) {
120        unsafe {
121            let data = Self::type_data();
122            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkLayoutManagerClass;
123            if let Some(f) = (*parent_class).allocate {
124                f(
125                    self.obj()
126                        .unsafe_cast_ref::<LayoutManager>()
127                        .to_glib_none()
128                        .0,
129                    widget.to_glib_none().0,
130                    width,
131                    height,
132                    baseline,
133                )
134            }
135        }
136    }
137
138    fn parent_create_layout_child(&self, widget: &Widget, for_child: &Widget) -> LayoutChild {
139        unsafe {
140            let data = Self::type_data();
141            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkLayoutManagerClass;
142            let f = (*parent_class)
143                .create_layout_child
144                .expect("No parent class impl for \"create_layout_child\"");
145            from_glib_none(f(
146                self.obj()
147                    .unsafe_cast_ref::<LayoutManager>()
148                    .to_glib_none()
149                    .0,
150                widget.to_glib_none().0,
151                for_child.to_glib_none().0,
152            ))
153        }
154    }
155
156    fn parent_request_mode(&self, widget: &Widget) -> SizeRequestMode {
157        unsafe {
158            let data = Self::type_data();
159            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkLayoutManagerClass;
160            let f = (*parent_class)
161                .get_request_mode
162                .expect("No parent class impl for \"get_request_mode\"");
163            from_glib(f(
164                self.obj()
165                    .unsafe_cast_ref::<LayoutManager>()
166                    .to_glib_none()
167                    .0,
168                widget.to_glib_none().0,
169            ))
170        }
171    }
172
173    fn parent_measure(
174        &self,
175        widget: &Widget,
176        orientation: Orientation,
177        for_size: i32,
178    ) -> (i32, i32, i32, i32) {
179        unsafe {
180            let data = Self::type_data();
181            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkLayoutManagerClass;
182            let f = (*parent_class)
183                .measure
184                .expect("No parent class impl for \"measure\"");
185
186            let mut minimum = 0;
187            let mut natural = 0;
188            let mut minimum_baseline = -1;
189            let mut natural_baseline = -1;
190            f(
191                self.obj()
192                    .unsafe_cast_ref::<LayoutManager>()
193                    .to_glib_none()
194                    .0,
195                widget.to_glib_none().0,
196                orientation.into_glib(),
197                for_size,
198                &mut minimum,
199                &mut natural,
200                &mut minimum_baseline,
201                &mut natural_baseline,
202            );
203            (minimum, natural, minimum_baseline, natural_baseline)
204        }
205    }
206
207    fn parent_root(&self) {
208        unsafe {
209            let data = Self::type_data();
210            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkLayoutManagerClass;
211            if let Some(f) = (*parent_class).root {
212                f(self
213                    .obj()
214                    .unsafe_cast_ref::<LayoutManager>()
215                    .to_glib_none()
216                    .0)
217            }
218        }
219    }
220
221    fn parent_unroot(&self) {
222        unsafe {
223            let data = Self::type_data();
224            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkLayoutManagerClass;
225            if let Some(f) = (*parent_class).unroot {
226                f(self
227                    .obj()
228                    .unsafe_cast_ref::<LayoutManager>()
229                    .to_glib_none()
230                    .0)
231            }
232        }
233    }
234}
235
236impl<T: LayoutManagerImpl> LayoutManagerImplExt for T {}
237
238unsafe impl<T: LayoutManagerImpl> IsSubclassable<T> for LayoutManager {
239    fn class_init(class: &mut glib::Class<Self>) {
240        Self::parent_class_init::<T>(class);
241
242        assert_initialized_main_thread!();
243
244        let klass = class.as_mut();
245        klass.allocate = Some(layout_manager_allocate::<T>);
246        klass.create_layout_child = Some(layout_manager_create_layout_child::<T>);
247        if let Some(type_) = T::layout_child_type() {
248            klass.layout_child_type = type_.into_glib();
249        }
250        klass.get_request_mode = Some(layout_manager_get_request_mode::<T>);
251        klass.measure = Some(layout_manager_measure::<T>);
252        klass.root = Some(layout_manager_root::<T>);
253        klass.unroot = Some(layout_manager_unroot::<T>);
254    }
255}
256
257unsafe extern "C" fn layout_manager_allocate<T: LayoutManagerImpl>(
258    ptr: *mut ffi::GtkLayoutManager,
259    widgetptr: *mut ffi::GtkWidget,
260    width: i32,
261    height: i32,
262    baseline: i32,
263) {
264    let instance = &*(ptr as *mut T::Instance);
265    let imp = instance.imp();
266
267    let widget: Borrowed<Widget> = from_glib_borrow(widgetptr);
268
269    imp.allocate(&widget, width, height, baseline)
270}
271
272unsafe extern "C" fn layout_manager_create_layout_child<T: LayoutManagerImpl>(
273    ptr: *mut ffi::GtkLayoutManager,
274    widgetptr: *mut ffi::GtkWidget,
275    for_childptr: *mut ffi::GtkWidget,
276) -> *mut ffi::GtkLayoutChild {
277    let instance = &*(ptr as *mut T::Instance);
278    let imp = instance.imp();
279    let widget: Borrowed<Widget> = from_glib_borrow(widgetptr);
280    let for_child: Borrowed<Widget> = from_glib_borrow(for_childptr);
281
282    imp.create_layout_child(&widget, &for_child).into_glib_ptr()
283}
284
285unsafe extern "C" fn layout_manager_get_request_mode<T: LayoutManagerImpl>(
286    ptr: *mut ffi::GtkLayoutManager,
287    widgetptr: *mut ffi::GtkWidget,
288) -> ffi::GtkSizeRequestMode {
289    let instance = &*(ptr as *mut T::Instance);
290    let imp = instance.imp();
291    let widget: Borrowed<Widget> = from_glib_borrow(widgetptr);
292
293    imp.request_mode(&widget).into_glib()
294}
295
296unsafe extern "C" fn layout_manager_measure<T: LayoutManagerImpl>(
297    ptr: *mut ffi::GtkLayoutManager,
298    widgetptr: *mut ffi::GtkWidget,
299    orientation: ffi::GtkOrientation,
300    for_size: i32,
301    minimum_ptr: *mut c_int,
302    natural_ptr: *mut c_int,
303    minimum_baseline_ptr: *mut c_int,
304    natural_baseline_ptr: *mut c_int,
305) {
306    let instance = &*(ptr as *mut T::Instance);
307    let imp = instance.imp();
308    let widget: Borrowed<Widget> = from_glib_borrow(widgetptr);
309
310    let (minimum, natural, minimum_baseline, natural_baseline) =
311        imp.measure(&widget, from_glib(orientation), for_size);
312    if !minimum_ptr.is_null() {
313        *minimum_ptr = minimum;
314    }
315    if !natural_ptr.is_null() {
316        *natural_ptr = natural;
317    }
318    if !minimum_baseline_ptr.is_null() {
319        *minimum_baseline_ptr = minimum_baseline;
320    }
321    if !natural_baseline_ptr.is_null() {
322        *natural_baseline_ptr = natural_baseline;
323    }
324}
325
326unsafe extern "C" fn layout_manager_root<T: LayoutManagerImpl>(ptr: *mut ffi::GtkLayoutManager) {
327    let instance = &*(ptr as *mut T::Instance);
328    let imp = instance.imp();
329
330    imp.root()
331}
332
333unsafe extern "C" fn layout_manager_unroot<T: LayoutManagerImpl>(ptr: *mut ffi::GtkLayoutManager) {
334    let instance = &*(ptr as *mut T::Instance);
335    let imp = instance.imp();
336
337    imp.unroot()
338}