docs
Loading...
Searching...
No Matches
Anchor.h
Go to the documentation of this file.
1///
2/// Copyright (C) 2026 Ultralight, Inc. All rights reserved.
3/// A license is required for commercial use. https://ultralig.ht
4///
5#pragma once
7#include <Ultralight/RefPtr.h>
8
9// X11's headers define None as a macro, which would break the None enumerators.
10#pragma push_macro("None")
11#undef None
12
13namespace ultralight {
14
15class Panel;
16
17///
18/// A window corner.
19///
20/// @see Anchor::WindowCorner()
21///
22enum class AnchorCorner : uint8_t { TopLeft = 0, TopRight, BottomLeft, BottomRight };
23
24///
25/// Cross-axis alignment of a floating panel against its anchor rect.
26///
27/// @see Anchor::Align()
28///
29enum class AnchorAlign : uint8_t { Start = 0, Center, End };
30
31///
32/// Fit behavior when an anchored floating panel does not fit on its preferred side.
33///
34/// @see Anchor::Fit()
35///
36enum class AnchorFit : uint8_t { None = 0, Flip };
37
38///
39/// Placement of a floating panel in a window.
40///
41/// An Anchor determines where a floating panel sits within an AppCore window. You pass it through
42/// ForegroundPanelOptions when adding a panel to the window's foreground layer, positioning
43/// overlays like toasts or dropdown menus.
44///
45/// This example floats a toast in the bottom-right corner of the window, nudged inward from the
46/// edge:
47///
48/// ```
49/// RefPtr<Panel> toast = window->foreground()->AddPanel(
50/// { .width = "320px", .height = "80px",
51/// .placement = Anchor::WindowCorner(AnchorCorner::BottomRight)
52/// .Offset(-16, -16) });
53/// ```
54///
55/// ## Placement Forms
56///
57/// Static factory methods define where a panel appears:
58///
59/// | Form | Placement |
60/// |------------------------|-----------------------------------------------------|
61/// | Anchor::At() | Positions the panel at absolute window coordinates. |
62/// | Anchor::WindowCorner() | Snaps the panel to a window corner. |
63/// | Anchor::WindowCenter() | Centers the panel within the window. |
64/// | Anchor::Fill() | Places the panel at the window origin. |
65/// | Anchor::Below() | Hangs the panel under a rectangle in another panel. |
66///
67/// Panels positioned with Anchor::WindowCorner() or Anchor::WindowCenter() follow the window as it
68/// resizes.
69///
70/// Calling Offset() on any form nudges the panel by horizontal and vertical offsets in logical
71/// pixels, applied after the form places the panel.
72///
73/// ## Anchoring Below an Element
74///
75/// Anchor::Below() takes a target panel and a rectangle in that panel's local logical pixels, which
76/// match the page's CSS pixels-- so bounding rectangles from dom::Element::getBoundingClientRect()
77/// pass straight through without conversion.
78///
79/// The library updates the placement every frame from the target panel's current geometry, so the
80/// floating panel follows the target as it moves.
81///
82/// Two chained methods refine placement under Anchor::Below():
83///
84/// - **Align() sets cross-axis alignment against the rectangle.** Left edges align by default, or
85/// you can center the panel or align its right edge.
86/// - **Fit() handles panels that don't fit below the rectangle.** AnchorFit::Flip places the panel
87/// above the rectangle instead.
88///
89/// This example positions a dropdown below a button from another panel, flipping it upward if space
90/// runs out:
91///
92/// ```
93/// dom::DOMRect box = button.getBoundingClientRect();
94/// RefPtr<Panel> dropdown = window->foreground()->AddPanel(
95/// { .width = "240px", .height = "180px",
96/// .placement = Anchor::Below(toolbar, Rect::FromXYWH(box.x, box.y,
97/// box.width, box.height))
98/// .Fit(AnchorFit::Flip) });
99/// ```
100///
101/// @note A floating panel's placement is fixed once the panel exists. See Foreground for how to
102/// move an existing panel.
103///
104/// @see ForegroundPanelOptions::placement, Foreground::AddPanel(),
105/// dom::Element::getBoundingClientRect()
106///
107class Anchor {
108 public:
109 ///
110 /// The placement form.
111 ///
112 enum class Kind : uint8_t {
113 Origin = 0, ///< Window origin (Fill() with the default 100% sizes).
114 At, ///< Absolute window-space logical px.
115 WindowCorner, ///< A window corner, following the window.
116 WindowCenter, ///< Centered in the window, following the window.
117 Below, ///< Under an anchor rect in a target panel.
118 };
119
120 ///
121 /// Create the default placement (the window origin).
122 ///
123 Anchor() = default;
124
125 ///
126 /// Place the panel's top-left corner at an absolute position in the window.
127 ///
128 /// @param x The x-position, in logical px from the window's left edge.
129 ///
130 /// @param y The y-position, in logical px from the window's top edge.
131 ///
132 static Anchor At(double x, double y) {
133 Anchor anchor;
134 anchor.kind_ = Kind::At;
135 anchor.x_ = x;
136 anchor.y_ = y;
137 return anchor;
138 }
139
140 ///
141 /// Snap the panel's matching corner to a corner of the window.
142 ///
143 /// The panel follows the window as it resizes. You can nudge it with Offset().
144 ///
145 /// @param corner The window corner to snap to.
146 ///
148 Anchor anchor;
149 anchor.kind_ = Kind::WindowCorner;
150 anchor.corner_ = corner;
151 return anchor;
152 }
153
154 ///
155 /// Center the panel in the window. The panel follows the window as it resizes.
156 ///
158 Anchor anchor;
159 anchor.kind_ = Kind::WindowCenter;
160 return anchor;
161 }
162
163 ///
164 /// Place the panel at the window origin, the named form of the default placement.
165 ///
166 /// With the default `100%` sizes this fills the window.
167 ///
168 static Anchor Fill() { return Anchor(); }
169
170 ///
171 /// Place the panel below an anchor rectangle in a target panel (eg, a dropdown below its box).
172 ///
173 /// The placement updates every frame from the target's current geometry.
174 ///
175 /// You can refine the placement with Align() and Fit().
176 ///
177 /// @param target The panel the anchor rectangle belongs to.
178 ///
179 /// @param rect The anchor rectangle, in the target panel's local logical pixels (which
180 /// equal the page's CSS pixels).
181 ///
182 /// \parblock
183 /// @note Anchoring one floating panel below another can lag the target by a frame while the
184 /// target moves.
185 /// \endparblock
186 ///
187 /// \parblock
188 /// @note If the target panel is removed or has not been laid out yet, the panel stays where
189 /// it was last placed.
190 /// \endparblock
191 ///
193 Anchor anchor;
194 anchor.kind_ = Kind::Below;
195 anchor.target_ = target;
196 anchor.rect_ = rect;
197 return anchor;
198 }
199
200 ///
201 /// Nudge the placement by an offset, applied after the placement form resolves (every form,
202 /// At() and the default origin included).
203 ///
204 /// @param dx The horizontal nudge, in logical px.
205 ///
206 /// @param dy The vertical nudge, in logical px.
207 ///
208 /// @return Returns a copy of this Anchor with the offset applied.
209 ///
210 [[nodiscard]] Anchor Offset(double dx, double dy) const {
211 Anchor anchor = *this;
212 anchor.offset_x_ = dx;
213 anchor.offset_y_ = dy;
214 return anchor;
215 }
216
217 ///
218 /// Align the panel against the anchor rect's cross axis. (Default: Start)
219 ///
220 /// Under Below(), Start aligns the left edges and End aligns the right edges.
221 ///
222 /// @param alignment The cross-axis alignment to use.
223 ///
224 /// @return Returns a copy of this Anchor with the alignment applied.
225 ///
226 [[nodiscard]] Anchor Align(AnchorAlign alignment) const {
227 Anchor anchor = *this;
228 anchor.align_ = alignment;
229 return anchor;
230 }
231
232 ///
233 /// Choose the fit behavior when the panel does not fit on its preferred side. (Default: None)
234 ///
235 /// Under Below(), Flip places the panel above the rect instead.
236 ///
237 /// @param fit The fit behavior to use.
238 ///
239 /// @return Returns a copy of this Anchor with the fit behavior applied.
240 ///
241 [[nodiscard]] Anchor Fit(AnchorFit fit) const {
242 Anchor anchor = *this;
243 anchor.fit_ = fit;
244 return anchor;
245 }
246
247 ///
248 /// The placement form.
249 ///
250 Kind kind() const { return kind_; }
251
252 ///
253 /// The window corner (WindowCorner() forms).
254 ///
255 AnchorCorner corner() const { return corner_; }
256
257 ///
258 /// The cross-axis alignment (Below() forms).
259 ///
260 AnchorAlign alignment() const { return align_; }
261
262 ///
263 /// The fit behavior (Below() forms).
264 ///
265 AnchorFit fit_mode() const { return fit_; }
266
267 ///
268 /// The absolute x-position, in logical px (At() forms).
269 ///
270 double x() const { return x_; }
271
272 ///
273 /// The absolute y-position, in logical px (At() forms).
274 ///
275 double y() const { return y_; }
276
277 ///
278 /// The x-offset applied after the placement form resolves, in logical px.
279 ///
280 double offset_x() const { return offset_x_; }
281
282 ///
283 /// The y-offset applied after the placement form resolves, in logical px.
284 ///
285 double offset_y() const { return offset_y_; }
286
287 ///
288 /// The target panel (Below() forms, null otherwise).
289 ///
290 RefPtr<Panel> target() const { return target_; }
291
292 ///
293 /// The anchor rect, in the target panel's local logical px (Below() forms).
294 ///
295 const Rect& rect() const { return rect_; }
296
297 private:
298 Kind kind_ = Kind::Origin;
302 double x_ = 0.0;
303 double y_ = 0.0;
304 double offset_x_ = 0.0;
305 double offset_y_ = 0.0;
306 RefPtr<Panel> target_;
307 Rect rect_ = Rect::MakeEmpty();
308};
309
310} // namespace ultralight
311
312#pragma pop_macro("None")
static Anchor WindowCorner(AnchorCorner corner)
Snap the panel's matching corner to a corner of the window.
Definition Anchor.h:147
AnchorAlign alignment() const
The cross-axis alignment (Below() forms).
Definition Anchor.h:260
Anchor Offset(double dx, double dy) const
Nudge the placement by an offset, applied after the placement form resolves (every form,...
Definition Anchor.h:210
AnchorFit fit_mode() const
The fit behavior (Below() forms).
Definition Anchor.h:265
Kind kind() const
The placement form.
Definition Anchor.h:250
AnchorCorner corner() const
The window corner (WindowCorner() forms).
Definition Anchor.h:255
static Anchor At(double x, double y)
Place the panel's top-left corner at an absolute position in the window.
Definition Anchor.h:132
Anchor Fit(AnchorFit fit) const
Choose the fit behavior when the panel does not fit on its preferred side.
Definition Anchor.h:241
const Rect & rect() const
The anchor rect, in the target panel's local logical px (Below() forms).
Definition Anchor.h:295
Anchor()=default
Create the default placement (the window origin).
static Anchor WindowCenter()
Center the panel in the window.
Definition Anchor.h:157
Anchor Align(AnchorAlign alignment) const
Align the panel against the anchor rect's cross axis.
Definition Anchor.h:226
RefPtr< Panel > target() const
The target panel (Below() forms, null otherwise).
Definition Anchor.h:290
double x() const
The absolute x-position, in logical px (At() forms).
Definition Anchor.h:270
Kind
The placement form.
Definition Anchor.h:112
@ Origin
Window origin (Fill() with the default 100% sizes).
Definition Anchor.h:113
@ WindowCenter
Centered in the window, following the window.
Definition Anchor.h:116
@ WindowCorner
A window corner, following the window.
Definition Anchor.h:115
@ At
Absolute window-space logical px.
Definition Anchor.h:114
@ Below
Under an anchor rect in a target panel.
Definition Anchor.h:117
double offset_y() const
The y-offset applied after the placement form resolves, in logical px.
Definition Anchor.h:285
double offset_x() const
The x-offset applied after the placement form resolves, in logical px.
Definition Anchor.h:280
static Anchor Fill()
Place the panel at the window origin, the named form of the default placement.
Definition Anchor.h:168
double y() const
The absolute y-position, in logical px (At() forms).
Definition Anchor.h:275
static Anchor Below(RefPtr< Panel > target, const Rect &rect)
Place the panel below an anchor rectangle in a target panel (eg, a dropdown below its box).
Definition Anchor.h:192
A layout node that hosts a single web view.
Definition Panel.h:59
A nullable smart pointer.
Definition RefPtr.h:126
Root namespace for every public Ultralight type, function, and enumeration.
AnchorCorner
A window corner.
Definition Anchor.h:22
@ TopRight
Definition Anchor.h:22
@ BottomRight
Definition Anchor.h:22
@ BottomLeft
Definition Anchor.h:22
@ TopLeft
Definition Anchor.h:22
AnchorAlign
Cross-axis alignment of a floating panel against its anchor rect.
Definition Anchor.h:29
@ Center
Definition Anchor.h:29
@ End
Definition Anchor.h:29
@ Start
Definition Anchor.h:29
AnchorFit
Fit behavior when an anchored floating panel does not fit on its preferred side.
Definition Anchor.h:36
@ None
Definition Anchor.h:36
@ Flip
Definition Anchor.h:36
Float Rectangle Helper.
Definition Geometry.h:416
static constexpr Rect MakeEmpty()
Definition Geometry.h:419