2 * Copyright 2006-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2014 Haiku, Inc. All rights reserved.
5 * Distributed under the terms of the MIT License.
8 * John Scipione, jscipione@gmail.com
9 * Ingo Weinhold, ingo_weinhold@gmx.de
12 #include <LayoutUtils.h>
20 #include "ViewLayoutItem.h"
25 // BLayoutUtils::AddSizesFloat(float a, float b)
27 // float sum = a + b + 1;
28 // if (sum >= B_SIZE_UNLIMITED)
29 // return B_SIZE_UNLIMITED;
36 // BLayoutUtils::AddSizesFloat(float a, float b, float c)
38 // return AddSizesFloat(AddSizesFloat(a, b), c);
44 BLayoutUtils::AddSizesInt32(int32 a
, int32 b
)
46 if (a
>= B_SIZE_UNLIMITED
- b
)
47 return B_SIZE_UNLIMITED
;
54 BLayoutUtils::AddSizesInt32(int32 a
, int32 b
, int32 c
)
56 return AddSizesInt32(AddSizesInt32(a
, b
), c
);
62 BLayoutUtils::AddDistances(float a
, float b
)
64 float sum
= a
+ b
+ 1;
65 if (sum
>= B_SIZE_UNLIMITED
)
66 return B_SIZE_UNLIMITED
;
74 BLayoutUtils::AddDistances(float a
, float b
, float c
)
76 return AddDistances(AddDistances(a
, b
), c
);
80 // // SubtractSizesFloat
82 // BLayoutUtils::SubtractSizesFloat(float a, float b)
92 BLayoutUtils::SubtractSizesInt32(int32 a
, int32 b
)
102 BLayoutUtils::SubtractDistances(float a
, float b
)
110 // FixSizeConstraints
112 BLayoutUtils::FixSizeConstraints(float& min
, float& max
, float& preferred
)
118 else if (preferred
> max
)
123 // FixSizeConstraints
125 BLayoutUtils::FixSizeConstraints(BSize
& min
, BSize
& max
, BSize
& preferred
)
127 FixSizeConstraints(min
.width
, max
.width
, preferred
.width
);
128 FixSizeConstraints(min
.height
, max
.height
, preferred
.height
);
134 BLayoutUtils::ComposeSize(BSize size
, BSize layoutSize
)
136 if (!size
.IsWidthSet())
137 size
.width
= layoutSize
.width
;
138 if (!size
.IsHeightSet())
139 size
.height
= layoutSize
.height
;
147 BLayoutUtils::ComposeAlignment(BAlignment alignment
, BAlignment layoutAlignment
)
149 if (!alignment
.IsHorizontalSet())
150 alignment
.horizontal
= layoutAlignment
.horizontal
;
151 if (!alignment
.IsVerticalSet())
152 alignment
.vertical
= layoutAlignment
.vertical
;
159 // This method restricts the dimensions of the resulting rectangle according
160 // to the available size specified by maxSize.
162 BLayoutUtils::AlignInFrame(BRect frame
, BSize maxSize
, BAlignment alignment
)
164 // align according to the given alignment
165 if (maxSize
.width
< frame
.Width()
166 && alignment
.horizontal
!= B_ALIGN_USE_FULL_WIDTH
) {
167 frame
.left
+= (int)((frame
.Width() - maxSize
.width
)
168 * alignment
.RelativeHorizontal());
169 frame
.right
= frame
.left
+ maxSize
.width
;
171 if (maxSize
.height
< frame
.Height()
172 && alignment
.vertical
!= B_ALIGN_USE_FULL_HEIGHT
) {
173 frame
.top
+= (int)((frame
.Height() - maxSize
.height
)
174 * alignment
.RelativeVertical());
175 frame
.bottom
= frame
.top
+ maxSize
.height
;
184 BLayoutUtils::AlignInFrame(BView
* view
, BRect frame
)
186 BSize maxSize
= view
->MaxSize();
187 BAlignment alignment
= view
->LayoutAlignment();
188 if (view
->HasHeightForWidth()) {
189 // The view has height for width, so we do the horizontal alignment
190 // ourselves and restrict the height max constraint respectively.
191 if (maxSize
.width
< frame
.Width()
192 && alignment
.horizontal
!= B_ALIGN_USE_FULL_WIDTH
) {
193 frame
.OffsetBy(floorf((frame
.Width() - maxSize
.width
)
194 * alignment
.RelativeHorizontal()), 0);
195 frame
.right
= frame
.left
+ maxSize
.width
;
197 alignment
.horizontal
= B_ALIGN_USE_FULL_WIDTH
;
200 float preferredHeight
;
201 view
->GetHeightForWidth(frame
.Width(), &minHeight
, &maxHeight
,
203 frame
.bottom
= frame
.top
+ std::max(frame
.Height(), minHeight
);
204 maxSize
.height
= minHeight
;
206 frame
= AlignInFrame(frame
, maxSize
, alignment
);
207 view
->MoveTo(frame
.LeftTop());
208 view
->ResizeTo(frame
.Size());
213 // This method, unlike AlignInFrame(), provides the possibility to return
214 // a rectangle with dimensions greater than the available size.
216 BLayoutUtils::AlignOnRect(BRect rect
, BSize size
, BAlignment alignment
)
218 rect
.left
+= (int)((rect
.Width() - size
.width
)
219 * alignment
.RelativeHorizontal());
220 rect
.top
+= (int)(((rect
.Height() - size
.height
))
221 * alignment
.RelativeVertical());
222 rect
.right
= rect
.left
+ size
.width
;
223 rect
.bottom
= rect
.top
+ size
.height
;
229 /*! Offsets a rectangle's location so that it lies fully in a given rectangular
232 If the rectangle is too wide/high to fully fit in the frame, its left/top
233 edge is offset to 0. The rect's size always remains unchanged.
235 \param rect The rectangle to be moved.
236 \param frameSize The size of the frame the rect shall be moved into. The
237 frame's left-top is (0, 0).
238 \return The modified rect.
241 BLayoutUtils::MoveIntoFrame(BRect rect
, BSize frameSize
)
243 BPoint
leftTop(rect
.LeftTop());
245 // enforce horizontal limits; favor left edge
246 if (rect
.right
> frameSize
.width
)
247 leftTop
.x
-= rect
.right
- frameSize
.width
;
251 // enforce vertical limits; favor top edge
252 if (rect
.bottom
> frameSize
.height
)
253 leftTop
.y
-= rect
.bottom
- frameSize
.height
;
257 return rect
.OffsetToSelf(leftTop
);
262 BLayoutUtils::GetLayoutTreeDump(BView
* view
)
265 _GetLayoutTreeDump(view
, 0, result
);
271 BLayoutUtils::GetLayoutTreeDump(BLayoutItem
* item
)
274 _GetLayoutTreeDump(item
, 0, false, result
);
280 BLayoutUtils::_GetLayoutTreeDump(BView
* view
, int level
, BString
& _output
)
283 indent
.SetTo(' ', level
* 2);
286 _output
<< indent
<< "<null view>\n";
290 BRect frame
= view
->Frame();
291 BSize min
= view
->MinSize();
292 BSize max
= view
->MinSize();
293 BSize preferred
= view
->PreferredSize();
294 _output
<< BString().SetToFormat(
296 "%s frame: (%f, %f, %f, %f)\n"
299 "%s pref: (%f, %f)\n",
300 indent
.String(), view
, typeid(*view
).name(),
301 indent
.String(), frame
.left
, frame
.top
, frame
.right
, frame
.bottom
,
302 indent
.String(), min
.width
, min
.height
,
303 indent
.String(), max
.width
, max
.height
,
304 indent
.String(), preferred
.width
, preferred
.height
);
306 if (BLayout
* layout
= view
->GetLayout()) {
307 _GetLayoutTreeDump(layout
, level
, true, _output
);
311 int32 count
= view
->CountChildren();
312 for (int32 i
= 0; i
< count
; i
++) {
313 _output
<< indent
<< " ---\n";
314 _GetLayoutTreeDump(view
->ChildAt(i
), level
+ 1, _output
);
320 BLayoutUtils::_GetLayoutTreeDump(BLayoutItem
* item
, int level
,
321 bool isViewLayout
, BString
& _output
)
323 if (BViewLayoutItem
* viewItem
= dynamic_cast<BViewLayoutItem
*>(item
)) {
324 _GetLayoutTreeDump(viewItem
->View(), level
, _output
);
329 indent
.SetTo(' ', level
* 2);
332 _output
<< indent
<< "<null item>\n";
336 BLayout
* layout
= dynamic_cast<BLayout
*>(item
);
337 BRect frame
= item
->Frame();
338 BSize min
= item
->MinSize();
339 BSize max
= item
->MinSize();
340 BSize preferred
= item
->PreferredSize();
342 _output
<< indent
<< BString().SetToFormat(" [layout %p (%s)]\n",
343 layout
, typeid(*layout
).name());
345 _output
<< indent
<< BString().SetToFormat("item %p (%s):\n",
346 item
, typeid(*item
).name());
348 _output
<< BString().SetToFormat(
349 "%s frame: (%f, %f, %f, %f)\n"
352 "%s pref: (%f, %f)\n",
353 indent
.String(), frame
.left
, frame
.top
, frame
.right
, frame
.bottom
,
354 indent
.String(), min
.width
, min
.height
,
355 indent
.String(), max
.width
, max
.height
,
356 indent
.String(), preferred
.width
, preferred
.height
);
361 int32 count
= layout
->CountItems();
362 for (int32 i
= 0; i
< count
; i
++) {
363 _output
<< indent
<< " ---\n";
364 _GetLayoutTreeDump(layout
->ItemAt(i
), level
+ 1, false, _output
);