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`].
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: ObjectImpl + ObjectSubclass<Type: IsA<LayoutManager>> {
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
113pub trait LayoutManagerImplExt: LayoutManagerImpl {
114    fn parent_allocate(&self, widget: &Widget, width: i32, height: i32, baseline: i32) {
115        unsafe {
116            let data = Self::type_data();
117            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkLayoutManagerClass;
118            if let Some(f) = (*parent_class).allocate {
119                f(
120                    self.obj()
121                        .unsafe_cast_ref::<LayoutManager>()
122                        .to_glib_none()
123                        .0,
124                    widget.to_glib_none().0,
125                    width,
126                    height,
127                    baseline,
128                )
129            }
130        }
131    }
132
133    fn parent_create_layout_child(&self, widget: &Widget, for_child: &Widget) -> LayoutChild {
134        unsafe {
135            let data = Self::type_data();
136            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkLayoutManagerClass;
137            let f = (*parent_class)
138                .create_layout_child
139                .expect("No parent class impl for \"create_layout_child\"");
140            from_glib_none(f(
141                self.obj()
142                    .unsafe_cast_ref::<LayoutManager>()
143                    .to_glib_none()
144                    .0,
145                widget.to_glib_none().0,
146                for_child.to_glib_none().0,
147            ))
148        }
149    }
150
151    fn parent_request_mode(&self, widget: &Widget) -> SizeRequestMode {
152        unsafe {
153            let data = Self::type_data();
154            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkLayoutManagerClass;
155            let f = (*parent_class)
156                .get_request_mode
157                .expect("No parent class impl for \"get_request_mode\"");
158            from_glib(f(
159                self.obj()
160                    .unsafe_cast_ref::<LayoutManager>()
161                    .to_glib_none()
162                    .0,
163                widget.to_glib_none().0,
164            ))
165        }
166    }
167
168    fn parent_measure(
169        &self,
170        widget: &Widget,
171        orientation: Orientation,
172        for_size: i32,
173    ) -> (i32, i32, i32, i32) {
174        unsafe {
175            let data = Self::type_data();
176            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkLayoutManagerClass;
177            let f = (*parent_class)
178                .measure
179                .expect("No parent class impl for \"measure\"");
180
181            let mut minimum = 0;
182            let mut natural = 0;
183            let mut minimum_baseline = -1;
184            let mut natural_baseline = -1;
185            f(
186                self.obj()
187                    .unsafe_cast_ref::<LayoutManager>()
188                    .to_glib_none()
189                    .0,
190                widget.to_glib_none().0,
191                orientation.into_glib(),
192                for_size,
193                &mut minimum,
194                &mut natural,
195                &mut minimum_baseline,
196                &mut natural_baseline,
197            );
198            (minimum, natural, minimum_baseline, natural_baseline)
199        }
200    }
201
202    fn parent_root(&self) {
203        unsafe {
204            let data = Self::type_data();
205            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkLayoutManagerClass;
206            if let Some(f) = (*parent_class).root {
207                f(self
208                    .obj()
209                    .unsafe_cast_ref::<LayoutManager>()
210                    .to_glib_none()
211                    .0)
212            }
213        }
214    }
215
216    fn parent_unroot(&self) {
217        unsafe {
218            let data = Self::type_data();
219            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkLayoutManagerClass;
220            if let Some(f) = (*parent_class).unroot {
221                f(self
222                    .obj()
223                    .unsafe_cast_ref::<LayoutManager>()
224                    .to_glib_none()
225                    .0)
226            }
227        }
228    }
229}
230
231impl<T: LayoutManagerImpl> LayoutManagerImplExt for T {}
232
233unsafe impl<T: LayoutManagerImpl> IsSubclassable<T> for LayoutManager {
234    fn class_init(class: &mut glib::Class<Self>) {
235        Self::parent_class_init::<T>(class);
236
237        assert_initialized_main_thread!();
238
239        let klass = class.as_mut();
240        klass.allocate = Some(layout_manager_allocate::<T>);
241        klass.create_layout_child = Some(layout_manager_create_layout_child::<T>);
242        if let Some(type_) = T::layout_child_type() {
243            klass.layout_child_type = type_.into_glib();
244        }
245        klass.get_request_mode = Some(layout_manager_get_request_mode::<T>);
246        klass.measure = Some(layout_manager_measure::<T>);
247        klass.root = Some(layout_manager_root::<T>);
248        klass.unroot = Some(layout_manager_unroot::<T>);
249    }
250}
251
252unsafe extern "C" fn layout_manager_allocate<T: LayoutManagerImpl>(
253    ptr: *mut ffi::GtkLayoutManager,
254    widgetptr: *mut ffi::GtkWidget,
255    width: i32,
256    height: i32,
257    baseline: i32,
258) {
259    let instance = &*(ptr as *mut T::Instance);
260    let imp = instance.imp();
261
262    let widget: Borrowed<Widget> = from_glib_borrow(widgetptr);
263
264    imp.allocate(&widget, width, height, baseline)
265}
266
267unsafe extern "C" fn layout_manager_create_layout_child<T: LayoutManagerImpl>(
268    ptr: *mut ffi::GtkLayoutManager,
269    widgetptr: *mut ffi::GtkWidget,
270    for_childptr: *mut ffi::GtkWidget,
271) -> *mut ffi::GtkLayoutChild {
272    let instance = &*(ptr as *mut T::Instance);
273    let imp = instance.imp();
274    let widget: Borrowed<Widget> = from_glib_borrow(widgetptr);
275    let for_child: Borrowed<Widget> = from_glib_borrow(for_childptr);
276
277    imp.create_layout_child(&widget, &for_child).into_glib_ptr()
278}
279
280unsafe extern "C" fn layout_manager_get_request_mode<T: LayoutManagerImpl>(
281    ptr: *mut ffi::GtkLayoutManager,
282    widgetptr: *mut ffi::GtkWidget,
283) -> ffi::GtkSizeRequestMode {
284    let instance = &*(ptr as *mut T::Instance);
285    let imp = instance.imp();
286    let widget: Borrowed<Widget> = from_glib_borrow(widgetptr);
287
288    imp.request_mode(&widget).into_glib()
289}
290
291unsafe extern "C" fn layout_manager_measure<T: LayoutManagerImpl>(
292    ptr: *mut ffi::GtkLayoutManager,
293    widgetptr: *mut ffi::GtkWidget,
294    orientation: ffi::GtkOrientation,
295    for_size: i32,
296    minimum_ptr: *mut c_int,
297    natural_ptr: *mut c_int,
298    minimum_baseline_ptr: *mut c_int,
299    natural_baseline_ptr: *mut c_int,
300) {
301    let instance = &*(ptr as *mut T::Instance);
302    let imp = instance.imp();
303    let widget: Borrowed<Widget> = from_glib_borrow(widgetptr);
304
305    let (minimum, natural, minimum_baseline, natural_baseline) =
306        imp.measure(&widget, from_glib(orientation), for_size);
307    if !minimum_ptr.is_null() {
308        *minimum_ptr = minimum;
309    }
310    if !natural_ptr.is_null() {
311        *natural_ptr = natural;
312    }
313    if !minimum_baseline_ptr.is_null() {
314        *minimum_baseline_ptr = minimum_baseline;
315    }
316    if !natural_baseline_ptr.is_null() {
317        *natural_baseline_ptr = natural_baseline;
318    }
319}
320
321unsafe extern "C" fn layout_manager_root<T: LayoutManagerImpl>(ptr: *mut ffi::GtkLayoutManager) {
322    let instance = &*(ptr as *mut T::Instance);
323    let imp = instance.imp();
324
325    imp.root()
326}
327
328unsafe extern "C" fn layout_manager_unroot<T: LayoutManagerImpl>(ptr: *mut ffi::GtkLayoutManager) {
329    let instance = &*(ptr as *mut T::Instance);
330    let imp = instance.imp();
331
332    imp.unroot()
333}