1 /* 2 * Copyright 2006-2013, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <LayoutUtils.h> 7 8 #include <typeinfo> 9 10 #include <Layout.h> 11 #include <View.h> 12 13 #include "ViewLayoutItem.h" 14 15 16 // // AddSizesFloat 17 // float 18 // BLayoutUtils::AddSizesFloat(float a, float b) 19 // { 20 // float sum = a + b + 1; 21 // if (sum >= B_SIZE_UNLIMITED) 22 // return B_SIZE_UNLIMITED; 23 // 24 // return sum; 25 // } 26 // 27 // // AddSizesFloat 28 // float 29 // BLayoutUtils::AddSizesFloat(float a, float b, float c) 30 // { 31 // return AddSizesFloat(AddSizesFloat(a, b), c); 32 // } 33 34 35 // AddSizesInt32 36 int32 37 BLayoutUtils::AddSizesInt32(int32 a, int32 b) 38 { 39 if (a >= B_SIZE_UNLIMITED - b) 40 return B_SIZE_UNLIMITED; 41 return a + b; 42 } 43 44 45 // AddSizesInt32 46 int32 47 BLayoutUtils::AddSizesInt32(int32 a, int32 b, int32 c) 48 { 49 return AddSizesInt32(AddSizesInt32(a, b), c); 50 } 51 52 53 // AddDistances 54 float 55 BLayoutUtils::AddDistances(float a, float b) 56 { 57 float sum = a + b + 1; 58 if (sum >= B_SIZE_UNLIMITED) 59 return B_SIZE_UNLIMITED; 60 61 return sum; 62 } 63 64 65 // AddDistances 66 float 67 BLayoutUtils::AddDistances(float a, float b, float c) 68 { 69 return AddDistances(AddDistances(a, b), c); 70 } 71 72 73 // // SubtractSizesFloat 74 // float 75 // BLayoutUtils::SubtractSizesFloat(float a, float b) 76 // { 77 // if (a < b) 78 // return -1; 79 // return a - b - 1; 80 // } 81 82 83 // SubtractSizesInt32 84 int32 85 BLayoutUtils::SubtractSizesInt32(int32 a, int32 b) 86 { 87 if (a < b) 88 return 0; 89 return a - b; 90 } 91 92 93 // SubtractDistances 94 float 95 BLayoutUtils::SubtractDistances(float a, float b) 96 { 97 if (a < b) 98 return -1; 99 return a - b - 1; 100 } 101 102 103 // FixSizeConstraints 104 void 105 BLayoutUtils::FixSizeConstraints(float& min, float& max, float& preferred) 106 { 107 if (max < min) 108 max = min; 109 if (preferred < min) 110 preferred = min; 111 else if (preferred > max) 112 preferred = max; 113 } 114 115 116 // FixSizeConstraints 117 void 118 BLayoutUtils::FixSizeConstraints(BSize& min, BSize& max, BSize& preferred) 119 { 120 FixSizeConstraints(min.width, max.width, preferred.width); 121 FixSizeConstraints(min.height, max.height, preferred.height); 122 } 123 124 125 // ComposeSize 126 BSize 127 BLayoutUtils::ComposeSize(BSize size, BSize layoutSize) 128 { 129 if (!size.IsWidthSet()) 130 size.width = layoutSize.width; 131 if (!size.IsHeightSet()) 132 size.height = layoutSize.height; 133 134 return size; 135 } 136 137 138 // ComposeAlignment 139 BAlignment 140 BLayoutUtils::ComposeAlignment(BAlignment alignment, BAlignment layoutAlignment) 141 { 142 if (!alignment.IsHorizontalSet()) 143 alignment.horizontal = layoutAlignment.horizontal; 144 if (!alignment.IsVerticalSet()) 145 alignment.vertical = layoutAlignment.vertical; 146 147 return alignment; 148 } 149 150 151 // AlignInFrame 152 BRect 153 BLayoutUtils::AlignInFrame(BRect frame, BSize maxSize, BAlignment alignment) 154 { 155 // align according to the given alignment 156 if (maxSize.width < frame.Width() 157 && alignment.horizontal != B_ALIGN_USE_FULL_WIDTH) { 158 frame.left += (int)((frame.Width() - maxSize.width) 159 * alignment.RelativeHorizontal()); 160 frame.right = frame.left + maxSize.width; 161 } 162 if (maxSize.height < frame.Height() 163 && alignment.vertical != B_ALIGN_USE_FULL_HEIGHT) { 164 frame.top += (int)((frame.Height() - maxSize.height) 165 * alignment.RelativeVertical()); 166 frame.bottom = frame.top + maxSize.height; 167 } 168 169 return frame; 170 } 171 172 173 // AlignInFrame 174 void 175 BLayoutUtils::AlignInFrame(BView* view, BRect frame) 176 { 177 BSize maxSize = view->MaxSize(); 178 BAlignment alignment = view->LayoutAlignment(); 179 180 if (view->HasHeightForWidth()) { 181 // The view has height for width, so we do the horizontal alignment 182 // ourselves and restrict the height max constraint respectively. 183 184 if (maxSize.width < frame.Width() 185 && alignment.horizontal != B_ALIGN_USE_FULL_WIDTH) { 186 frame.OffsetBy(floor((frame.Width() - maxSize.width) 187 * alignment.RelativeHorizontal()), 0); 188 frame.right = frame.left + maxSize.width; 189 } 190 alignment.horizontal = B_ALIGN_USE_FULL_WIDTH; 191 192 float minHeight; 193 float maxHeight; 194 float preferredHeight; 195 view->GetHeightForWidth(frame.Width(), &minHeight, &maxHeight, 196 &preferredHeight); 197 198 frame.bottom = frame.top + max_c(frame.Height(), minHeight); 199 maxSize.height = minHeight; 200 } 201 202 frame = AlignInFrame(frame, maxSize, alignment); 203 view->MoveTo(frame.LeftTop()); 204 view->ResizeTo(frame.Size()); 205 } 206 207 208 /*! Offsets a rectangle's location so that it lies fully in a given rectangular 209 frame. 210 211 If the rectangle is too wide/high to fully fit in the frame, its left/top 212 edge is offset to 0. The rect's size always remains unchanged. 213 214 \param rect The rectangle to be moved. 215 \param frameSize The size of the frame the rect shall be moved into. The 216 frame's left-top is (0, 0). 217 \return The modified rect. 218 */ 219 /*static*/ BRect 220 BLayoutUtils::MoveIntoFrame(BRect rect, BSize frameSize) 221 { 222 BPoint leftTop(rect.LeftTop()); 223 224 // enforce horizontal limits; favor left edge 225 if (rect.right > frameSize.width) 226 leftTop.x -= rect.right - frameSize.width; 227 if (leftTop.x < 0) 228 leftTop.x = 0; 229 230 // enforce vertical limits; favor top edge 231 if (rect.bottom > frameSize.height) 232 leftTop.y -= rect.bottom - frameSize.height; 233 if (leftTop.y < 0) 234 leftTop.y = 0; 235 236 return rect.OffsetToSelf(leftTop); 237 } 238 239 240 /*static*/ BString 241 BLayoutUtils::GetLayoutTreeDump(BView* view) 242 { 243 BString result; 244 _GetLayoutTreeDump(view, 0, result); 245 return result; 246 } 247 248 249 /*static*/ BString 250 BLayoutUtils::GetLayoutTreeDump(BLayoutItem* item) 251 { 252 BString result; 253 _GetLayoutTreeDump(item, 0, false, result); 254 return result; 255 } 256 257 258 /*static*/ void 259 BLayoutUtils::_GetLayoutTreeDump(BView* view, int level, BString& _output) 260 { 261 BString indent; 262 indent.SetTo(' ', level * 2); 263 264 if (view == NULL) { 265 _output << indent << "<null view>\n"; 266 return; 267 } 268 269 BRect frame = view->Frame(); 270 BSize min = view->MinSize(); 271 BSize max = view->MinSize(); 272 BSize preferred = view->PreferredSize(); 273 _output << BString().SetToFormat( 274 "%sview %p (%s):\n" 275 "%s frame: (%f, %f, %f, %f)\n" 276 "%s min: (%f, %f)\n" 277 "%s max: (%f, %f)\n" 278 "%s pref: (%f, %f)\n", 279 indent.String(), view, typeid(*view).name(), 280 indent.String(), frame.left, frame.top, frame.right, frame.bottom, 281 indent.String(), min.width, min.height, 282 indent.String(), max.width, max.height, 283 indent.String(), preferred.width, preferred.height); 284 285 if (BLayout* layout = view->GetLayout()) { 286 _GetLayoutTreeDump(layout, level, true, _output); 287 return; 288 } 289 290 int32 count = view->CountChildren(); 291 for (int32 i = 0; i < count; i++) { 292 _output << indent << " ---\n"; 293 _GetLayoutTreeDump(view->ChildAt(i), level + 1, _output); 294 } 295 } 296 297 298 /*static*/ void 299 BLayoutUtils::_GetLayoutTreeDump(BLayoutItem* item, int level, 300 bool isViewLayout, BString& _output) 301 { 302 if (BViewLayoutItem* viewItem = dynamic_cast<BViewLayoutItem*>(item)) { 303 _GetLayoutTreeDump(viewItem->View(), level, _output); 304 return; 305 } 306 307 BString indent; 308 indent.SetTo(' ', level * 2); 309 310 if (item == NULL) { 311 _output << indent << "<null item>\n"; 312 return; 313 } 314 315 BLayout* layout = dynamic_cast<BLayout*>(item); 316 BRect frame = item->Frame(); 317 BSize min = item->MinSize(); 318 BSize max = item->MinSize(); 319 BSize preferred = item->PreferredSize(); 320 if (isViewLayout) { 321 _output << indent << BString().SetToFormat(" [layout %p (%s)]\n", 322 layout, typeid(*layout).name()); 323 } else { 324 _output << indent << BString().SetToFormat("item %p (%s):\n", 325 item, typeid(*item).name()); 326 } 327 _output << BString().SetToFormat( 328 "%s frame: (%f, %f, %f, %f)\n" 329 "%s min: (%f, %f)\n" 330 "%s max: (%f, %f)\n" 331 "%s pref: (%f, %f)\n", 332 indent.String(), frame.left, frame.top, frame.right, frame.bottom, 333 indent.String(), min.width, min.height, 334 indent.String(), max.width, max.height, 335 indent.String(), preferred.width, preferred.height); 336 337 if (layout == NULL) 338 return; 339 340 int32 count = layout->CountItems(); 341 for (int32 i = 0; i < count; i++) { 342 _output << indent << " ---\n"; 343 _GetLayoutTreeDump(layout->ItemAt(i), level + 1, false, _output); 344 } 345 } 346