xref: /haiku/src/kits/interface/LayoutUtils.cpp (revision f2b4344867e97c3f4e742a1b4a15e6879644601a)
1 /*
2  * Copyright 2006-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include <LayoutUtils.h>
7 
8 #include <View.h>
9 
10 
11 // // AddSizesFloat
12 // float
13 // BLayoutUtils::AddSizesFloat(float a, float b)
14 // {
15 // 	float sum = a + b + 1;
16 // 	if (sum >= B_SIZE_UNLIMITED)
17 // 		return B_SIZE_UNLIMITED;
18 //
19 // 	return sum;
20 // }
21 //
22 // // AddSizesFloat
23 // float
24 // BLayoutUtils::AddSizesFloat(float a, float b, float c)
25 // {
26 // 	return AddSizesFloat(AddSizesFloat(a, b), c);
27 // }
28 
29 
30 // AddSizesInt32
31 int32
32 BLayoutUtils::AddSizesInt32(int32 a, int32 b)
33 {
34 	if (a >= B_SIZE_UNLIMITED - b)
35 		return B_SIZE_UNLIMITED;
36 	return a + b;
37 }
38 
39 
40 // AddSizesInt32
41 int32
42 BLayoutUtils::AddSizesInt32(int32 a, int32 b, int32 c)
43 {
44 	return AddSizesInt32(AddSizesInt32(a, b), c);
45 }
46 
47 
48 // AddDistances
49 float
50 BLayoutUtils::AddDistances(float a, float b)
51 {
52 	float sum = a + b + 1;
53 	if (sum >= B_SIZE_UNLIMITED)
54 		return B_SIZE_UNLIMITED;
55 
56 	return sum;
57 }
58 
59 
60 // AddDistances
61 float
62 BLayoutUtils::AddDistances(float a, float b, float c)
63 {
64 	return AddDistances(AddDistances(a, b), c);
65 }
66 
67 
68 // // SubtractSizesFloat
69 // float
70 // BLayoutUtils::SubtractSizesFloat(float a, float b)
71 // {
72 // 	if (a < b)
73 // 		return -1;
74 // 	return a - b - 1;
75 // }
76 
77 
78 // SubtractSizesInt32
79 int32
80 BLayoutUtils::SubtractSizesInt32(int32 a, int32 b)
81 {
82 	if (a < b)
83 		return 0;
84 	return a - b;
85 }
86 
87 
88 // SubtractDistances
89 float
90 BLayoutUtils::SubtractDistances(float a, float b)
91 {
92 	if (a < b)
93 		return -1;
94 	return a - b - 1;
95 }
96 
97 
98 // FixSizeConstraints
99 void
100 BLayoutUtils::FixSizeConstraints(float& min, float& max, float& preferred)
101 {
102 	if (max < min)
103 		max = min;
104 	if (preferred < min)
105 		preferred = min;
106 	else if (preferred > max)
107 		preferred = max;
108 }
109 
110 
111 // FixSizeConstraints
112 void
113 BLayoutUtils::FixSizeConstraints(BSize& min, BSize& max, BSize& preferred)
114 {
115 	FixSizeConstraints(min.width, max.width, preferred.width);
116 	FixSizeConstraints(min.height, max.height, preferred.height);
117 }
118 
119 
120 // ComposeSize
121 BSize
122 BLayoutUtils::ComposeSize(BSize size, BSize layoutSize)
123 {
124 	if (!size.IsWidthSet())
125 		size.width = layoutSize.width;
126 	if (!size.IsHeightSet())
127 		size.height = layoutSize.height;
128 
129 	return size;
130 }
131 
132 
133 // ComposeAlignment
134 BAlignment
135 BLayoutUtils::ComposeAlignment(BAlignment alignment, BAlignment layoutAlignment)
136 {
137 	if (!alignment.IsHorizontalSet())
138 		alignment.horizontal = layoutAlignment.horizontal;
139 	if (!alignment.IsVerticalSet())
140 		alignment.vertical = layoutAlignment.vertical;
141 
142 	return alignment;
143 }
144 
145 
146 // AlignInFrame
147 BRect
148 BLayoutUtils::AlignInFrame(BRect frame, BSize maxSize, BAlignment alignment)
149 {
150 	// align according to the given alignment
151 	if (maxSize.width < frame.Width()
152 		&& alignment.horizontal != B_ALIGN_USE_FULL_WIDTH) {
153 		frame.left += (int)((frame.Width() - maxSize.width)
154 			* alignment.RelativeHorizontal());
155 		frame.right = frame.left + maxSize.width;
156 	}
157 	if (maxSize.height < frame.Height()
158 		&& alignment.vertical != B_ALIGN_USE_FULL_HEIGHT) {
159 		frame.top += (int)((frame.Height() - maxSize.height)
160 			* alignment.RelativeVertical());
161 		frame.bottom = frame.top + maxSize.height;
162 	}
163 
164 	return frame;
165 }
166 
167 
168 // AlignInFrame
169 void
170 BLayoutUtils::AlignInFrame(BView* view, BRect frame)
171 {
172  	BSize maxSize = view->MaxSize();
173  	BAlignment alignment = view->LayoutAlignment();
174 
175  	if (view->HasHeightForWidth()) {
176  		// The view has height for width, so we do the horizontal alignment
177  		// ourselves and restrict the height max constraint respectively.
178 
179  		if (maxSize.width < frame.Width()
180  			&& alignment.horizontal != B_ALIGN_USE_FULL_WIDTH) {
181  			frame.OffsetBy(floor((frame.Width() - maxSize.width)
182  				* alignment.RelativeHorizontal()), 0);
183  			frame.right = frame.left + maxSize.width;
184  		}
185  		alignment.horizontal = B_ALIGN_USE_FULL_WIDTH;
186 
187  		float minHeight;
188  		float maxHeight;
189  		float preferredHeight;
190  		view->GetHeightForWidth(frame.Width(), &minHeight, &maxHeight,
191  			&preferredHeight);
192 
193  		frame.bottom = frame.top + max_c(frame.Height(), minHeight);
194  		maxSize.height = minHeight;
195  	}
196 
197  	frame = AlignInFrame(frame, maxSize, alignment);
198  	view->MoveTo(frame.LeftTop());
199  	view->ResizeTo(frame.Size());
200 }
201 
202 
203 /*!	Offsets a rectangle's location so that it lies fully in a given rectangular
204 	frame.
205 
206 	If the rectangle is too wide/high to fully fit in the frame, its left/top
207 	edge is offset to 0. The rect's size always remains unchanged.
208 
209 	\param rect The rectangle to be moved.
210 	\param frameSize The size of the frame the rect shall be moved into. The
211 		frame's left-top is (0, 0).
212 	\return The modified rect.
213 */
214 /*static*/ BRect
215 BLayoutUtils::MoveIntoFrame(BRect rect, BSize frameSize)
216 {
217 	BPoint leftTop(rect.LeftTop());
218 
219 	// enforce horizontal limits; favor left edge
220 	if (rect.right > frameSize.width)
221 		leftTop.x -= rect.right - frameSize.width;
222 	if (leftTop.x < 0)
223 		leftTop.x = 0;
224 
225 	// enforce vertical limits; favor top edge
226 	if (rect.bottom > frameSize.height)
227 		leftTop.y -= rect.bottom - frameSize.height;
228 	if (leftTop.y < 0)
229 		leftTop.y = 0;
230 
231 	return rect.OffsetToSelf(leftTop);
232 }
233