1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
// This file was generated by gir (https://github.com/gtk-rs/gir)
// from gir-files (https://github.com/gtk-rs/gir-files)
// DO NOT EDIT

use crate::{AnchorHints, Gravity, Rectangle};
use glib::translate::*;

glib::wrapper! {
    /// The [`PopupLayout`][crate::PopupLayout] struct contains information that is
    /// necessary position a [`Popup`][crate::Popup] relative to its parent.
    ///
    /// The positioning requires a negotiation with the windowing system,
    /// since it depends on external constraints, such as the position of
    /// the parent surface, and the screen dimensions.
    ///
    /// The basic ingredients are a rectangle on the parent surface,
    /// and the anchor on both that rectangle and the popup. The anchors
    /// specify a side or corner to place next to each other.
    ///
    /// ![Popup anchors](popup-anchors.png)
    ///
    /// For cases where placing the anchors next to each other would make
    /// the popup extend offscreen, the layout includes some hints for how
    /// to resolve this problem. The hints may suggest to flip the anchor
    /// position to the other side, or to 'slide' the popup along a side,
    /// or to resize it.
    ///
    /// ![Flipping popups](popup-flip.png)
    ///
    /// ![Sliding popups](popup-slide.png)
    ///
    /// These hints may be combined.
    ///
    /// Ultimatively, it is up to the windowing system to determine the position
    /// and size of the popup. You can learn about the result by calling
    /// [`PopupExt::position_x()`][crate::prelude::PopupExt::position_x()], [`PopupExt::position_y()`][crate::prelude::PopupExt::position_y()],
    /// [`PopupExt::rect_anchor()`][crate::prelude::PopupExt::rect_anchor()] and [`PopupExt::surface_anchor()`][crate::prelude::PopupExt::surface_anchor()]
    /// after the popup has been presented. This can be used to adjust the rendering.
    /// For example, [GtkPopover](../gtk4/class.Popover.html) changes its arrow position
    /// accordingly. But you have to be careful avoid changing the size of the popover,
    /// or it has to be presented again.
    #[derive(Debug, PartialOrd, Ord, Hash)]
    pub struct PopupLayout(Shared<ffi::GdkPopupLayout>);

    match fn {
        ref => |ptr| ffi::gdk_popup_layout_ref(ptr),
        unref => |ptr| ffi::gdk_popup_layout_unref(ptr),
        type_ => || ffi::gdk_popup_layout_get_type(),
    }
}

impl PopupLayout {
    /// Create a popup layout description.
    ///
    /// Used together with [`PopupExt::present()`][crate::prelude::PopupExt::present()] to describe how a popup
    /// surface should be placed and behave on-screen.
    ///
    /// @anchor_rect is relative to the top-left corner of the surface's parent.
    /// @rect_anchor and @surface_anchor determine anchor points on @anchor_rect
    /// and surface to pin together.
    ///
    /// The position of @anchor_rect's anchor point can optionally be offset using
    /// [`set_offset()`][Self::set_offset()], which is equivalent to offsetting the
    /// position of surface.
    /// ## `anchor_rect`
    /// the anchor [`Rectangle`][crate::Rectangle] to align @surface with
    /// ## `rect_anchor`
    /// the point on @anchor_rect to align with @surface's anchor point
    /// ## `surface_anchor`
    /// the point on @surface to align with @rect's anchor point
    ///
    /// # Returns
    ///
    /// newly created instance of [`PopupLayout`][crate::PopupLayout]
    #[doc(alias = "gdk_popup_layout_new")]
    pub fn new(
        anchor_rect: &Rectangle,
        rect_anchor: Gravity,
        surface_anchor: Gravity,
    ) -> PopupLayout {
        assert_initialized_main_thread!();
        unsafe {
            from_glib_full(ffi::gdk_popup_layout_new(
                anchor_rect.to_glib_none().0,
                rect_anchor.into_glib(),
                surface_anchor.into_glib(),
            ))
        }
    }

    #[doc(alias = "gdk_popup_layout_copy")]
    #[must_use]
    pub fn copy(&self) -> PopupLayout {
        unsafe { from_glib_full(ffi::gdk_popup_layout_copy(self.to_glib_none().0)) }
    }

    #[doc(alias = "gdk_popup_layout_equal")]
    fn equal(&self, other: &PopupLayout) -> bool {
        unsafe {
            from_glib(ffi::gdk_popup_layout_equal(
                self.to_glib_none().0,
                other.to_glib_none().0,
            ))
        }
    }

    /// Get the [`AnchorHints`][crate::AnchorHints].
    ///
    /// # Returns
    ///
    /// the [`AnchorHints`][crate::AnchorHints]
    #[doc(alias = "gdk_popup_layout_get_anchor_hints")]
    #[doc(alias = "get_anchor_hints")]
    pub fn anchor_hints(&self) -> AnchorHints {
        unsafe {
            from_glib(ffi::gdk_popup_layout_get_anchor_hints(
                self.to_glib_none().0,
            ))
        }
    }

    /// Get the anchor rectangle.
    ///
    /// # Returns
    ///
    /// The anchor rectangle
    #[doc(alias = "gdk_popup_layout_get_anchor_rect")]
    #[doc(alias = "get_anchor_rect")]
    pub fn anchor_rect(&self) -> Rectangle {
        unsafe { from_glib_none(ffi::gdk_popup_layout_get_anchor_rect(self.to_glib_none().0)) }
    }

    /// Returns the anchor position on the anchor rectangle.
    ///
    /// # Returns
    ///
    /// the anchor on the anchor rectangle.
    #[doc(alias = "gdk_popup_layout_get_rect_anchor")]
    #[doc(alias = "get_rect_anchor")]
    pub fn rect_anchor(&self) -> Gravity {
        unsafe { from_glib(ffi::gdk_popup_layout_get_rect_anchor(self.to_glib_none().0)) }
    }

    /// Obtains the shadow widths of this layout.
    ///
    /// # Returns
    ///
    ///
    /// ## `left`
    /// return location for the left shadow width
    ///
    /// ## `right`
    /// return location for the right shadow width
    ///
    /// ## `top`
    /// return location for the top shadow width
    ///
    /// ## `bottom`
    /// return location for the bottom shadow width
    #[cfg(feature = "v4_2")]
    #[cfg_attr(docsrs, doc(cfg(feature = "v4_2")))]
    #[doc(alias = "gdk_popup_layout_get_shadow_width")]
    #[doc(alias = "get_shadow_width")]
    pub fn shadow_width(&self) -> (i32, i32, i32, i32) {
        unsafe {
            let mut left = std::mem::MaybeUninit::uninit();
            let mut right = std::mem::MaybeUninit::uninit();
            let mut top = std::mem::MaybeUninit::uninit();
            let mut bottom = std::mem::MaybeUninit::uninit();
            ffi::gdk_popup_layout_get_shadow_width(
                self.to_glib_none().0,
                left.as_mut_ptr(),
                right.as_mut_ptr(),
                top.as_mut_ptr(),
                bottom.as_mut_ptr(),
            );
            (
                left.assume_init(),
                right.assume_init(),
                top.assume_init(),
                bottom.assume_init(),
            )
        }
    }

    /// Returns the anchor position on the popup surface.
    ///
    /// # Returns
    ///
    /// the anchor on the popup surface.
    #[doc(alias = "gdk_popup_layout_get_surface_anchor")]
    #[doc(alias = "get_surface_anchor")]
    pub fn surface_anchor(&self) -> Gravity {
        unsafe {
            from_glib(ffi::gdk_popup_layout_get_surface_anchor(
                self.to_glib_none().0,
            ))
        }
    }

    /// Set new anchor hints.
    ///
    /// The set @anchor_hints determines how @surface will be moved
    /// if the anchor points cause it to move off-screen. For example,
    /// [`AnchorHints::FLIP_X`][crate::AnchorHints::FLIP_X] will replace [`Gravity::NorthWest`][crate::Gravity::NorthWest] with
    /// [`Gravity::NorthEast`][crate::Gravity::NorthEast] and vice versa if @surface extends
    /// beyond the left or right edges of the monitor.
    /// ## `anchor_hints`
    /// the new [`AnchorHints`][crate::AnchorHints]
    #[doc(alias = "gdk_popup_layout_set_anchor_hints")]
    pub fn set_anchor_hints(&self, anchor_hints: AnchorHints) {
        unsafe {
            ffi::gdk_popup_layout_set_anchor_hints(self.to_glib_none().0, anchor_hints.into_glib());
        }
    }

    /// Set the anchor rectangle.
    /// ## `anchor_rect`
    /// the new anchor rectangle
    #[doc(alias = "gdk_popup_layout_set_anchor_rect")]
    pub fn set_anchor_rect(&self, anchor_rect: &Rectangle) {
        unsafe {
            ffi::gdk_popup_layout_set_anchor_rect(
                self.to_glib_none().0,
                anchor_rect.to_glib_none().0,
            );
        }
    }

    /// Offset the position of the anchor rectangle with the given delta.
    /// ## `dx`
    /// x delta to offset the anchor rectangle with
    /// ## `dy`
    /// y delta to offset the anchor rectangle with
    #[doc(alias = "gdk_popup_layout_set_offset")]
    pub fn set_offset(&self, dx: i32, dy: i32) {
        unsafe {
            ffi::gdk_popup_layout_set_offset(self.to_glib_none().0, dx, dy);
        }
    }

    /// Set the anchor on the anchor rectangle.
    /// ## `anchor`
    /// the new rect anchor
    #[doc(alias = "gdk_popup_layout_set_rect_anchor")]
    pub fn set_rect_anchor(&self, anchor: Gravity) {
        unsafe {
            ffi::gdk_popup_layout_set_rect_anchor(self.to_glib_none().0, anchor.into_glib());
        }
    }

    /// Sets the shadow width of the popup.
    ///
    /// The shadow width corresponds to the part of the computed
    /// surface size that would consist of the shadow margin
    /// surrounding the window, would there be any.
    /// ## `left`
    /// width of the left part of the shadow
    /// ## `right`
    /// width of the right part of the shadow
    /// ## `top`
    /// height of the top part of the shadow
    /// ## `bottom`
    /// height of the bottom part of the shadow
    #[cfg(feature = "v4_2")]
    #[cfg_attr(docsrs, doc(cfg(feature = "v4_2")))]
    #[doc(alias = "gdk_popup_layout_set_shadow_width")]
    pub fn set_shadow_width(&self, left: i32, right: i32, top: i32, bottom: i32) {
        unsafe {
            ffi::gdk_popup_layout_set_shadow_width(self.to_glib_none().0, left, right, top, bottom);
        }
    }

    /// Set the anchor on the popup surface.
    /// ## `anchor`
    /// the new popup surface anchor
    #[doc(alias = "gdk_popup_layout_set_surface_anchor")]
    pub fn set_surface_anchor(&self, anchor: Gravity) {
        unsafe {
            ffi::gdk_popup_layout_set_surface_anchor(self.to_glib_none().0, anchor.into_glib());
        }
    }
}

impl PartialEq for PopupLayout {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.equal(other)
    }
}

impl Eq for PopupLayout {}