1 /* 2 * Copyright 2006-2009, Ingo Weinhold <ingo_weinhold@gmx.de>. 3 * All rights reserved. Distributed under the terms of the MIT License. 4 */ 5 6 #include <CardLayout.h> 7 8 #include <LayoutItem.h> 9 #include <Message.h> 10 #include <View.h> 11 12 13 namespace { 14 const char* kVisibleItemField = "BCardLayout:visibleItem"; 15 } 16 17 18 BCardLayout::BCardLayout() 19 : 20 BAbstractLayout(), 21 fMin(0, 0), 22 fMax(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED), 23 fPreferred(0, 0), 24 fVisibleItem(NULL), 25 fMinMaxValid(false) 26 { 27 } 28 29 30 BCardLayout::BCardLayout(BMessage* from) 31 : 32 BAbstractLayout(BUnarchiver::PrepareArchive(from)), 33 fMin(0, 0), 34 fMax(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED), 35 fPreferred(0, 0), 36 fVisibleItem(NULL), 37 fMinMaxValid(false) 38 { 39 BUnarchiver(from).Finish(); 40 } 41 42 43 BCardLayout::~BCardLayout() 44 { 45 } 46 47 48 BLayoutItem* 49 BCardLayout::VisibleItem() const 50 { 51 return fVisibleItem; 52 } 53 54 55 int32 56 BCardLayout::VisibleIndex() const 57 { 58 return IndexOfItem(fVisibleItem); 59 } 60 61 62 void 63 BCardLayout::SetVisibleItem(int32 index) 64 { 65 SetVisibleItem(ItemAt(index)); 66 } 67 68 69 void 70 BCardLayout::SetVisibleItem(BLayoutItem* item) 71 { 72 if (item == fVisibleItem) 73 return; 74 75 if (item != NULL && IndexOfItem(item) < 0) { 76 debugger("BCardLayout::SetVisibleItem(BLayoutItem*): this item is not " 77 "part of this layout, or the item does not exist."); 78 return; 79 } 80 81 // Changing an item's visibility will invalidate its parent's layout (us), 82 // which would normally cause the min-max to be re-computed. But in this 83 // case, that is unnecessary, and so we can skip it. 84 const bool minMaxValid = fMinMaxValid; 85 86 if (fVisibleItem != NULL) 87 fVisibleItem->SetVisible(false); 88 89 fVisibleItem = item; 90 91 if (fVisibleItem != NULL) 92 fVisibleItem->SetVisible(true); 93 94 fMinMaxValid = minMaxValid; 95 } 96 97 98 BSize 99 BCardLayout::BaseMinSize() 100 { 101 _ValidateMinMax(); 102 return fMin; 103 } 104 105 106 BSize 107 BCardLayout::BaseMaxSize() 108 { 109 _ValidateMinMax(); 110 return fMax; 111 } 112 113 114 BSize 115 BCardLayout::BasePreferredSize() 116 { 117 _ValidateMinMax(); 118 return fPreferred; 119 } 120 121 122 BAlignment 123 BCardLayout::BaseAlignment() 124 { 125 return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); 126 } 127 128 129 bool 130 BCardLayout::HasHeightForWidth() 131 { 132 int32 count = CountItems(); 133 for (int32 i = 0; i < count; i++) { 134 if (ItemAt(i)->HasHeightForWidth()) 135 return true; 136 } 137 138 return false; 139 } 140 141 142 void 143 BCardLayout::GetHeightForWidth(float width, float* min, float* max, 144 float* preferred) 145 { 146 _ValidateMinMax(); 147 148 // init with useful values 149 float minHeight = fMin.height; 150 float maxHeight = fMax.height; 151 float preferredHeight = fPreferred.height; 152 153 // apply the items' constraints 154 int32 count = CountItems(); 155 for (int32 i = 0; i < count; i++) { 156 BLayoutItem* item = ItemAt(i); 157 if (item->HasHeightForWidth()) { 158 float itemMinHeight; 159 float itemMaxHeight; 160 float itemPreferredHeight; 161 item->GetHeightForWidth(width, &itemMinHeight, &itemMaxHeight, 162 &itemPreferredHeight); 163 minHeight = max_c(minHeight, itemMinHeight); 164 maxHeight = min_c(maxHeight, itemMaxHeight); 165 preferredHeight = min_c(preferredHeight, itemPreferredHeight); 166 } 167 } 168 169 // adjust max and preferred, if necessary 170 maxHeight = max_c(maxHeight, minHeight); 171 preferredHeight = max_c(preferredHeight, minHeight); 172 preferredHeight = min_c(preferredHeight, maxHeight); 173 174 if (min) 175 *min = minHeight; 176 if (max) 177 *max = maxHeight; 178 if (preferred) 179 *preferred = preferredHeight; 180 } 181 182 183 void 184 BCardLayout::LayoutInvalidated(bool children) 185 { 186 fMinMaxValid = false; 187 } 188 189 190 void 191 BCardLayout::DoLayout() 192 { 193 _ValidateMinMax(); 194 195 BSize size(LayoutArea().Size()); 196 197 // this cannot be done when we are viewless, as our children 198 // would not get cut off in the right place. 199 if (Owner()) { 200 size.width = max_c(size.width, fMin.width); 201 size.height = max_c(size.height, fMin.height); 202 } 203 204 if (fVisibleItem != NULL) 205 fVisibleItem->AlignInFrame(BRect(LayoutArea().LeftTop(), size)); 206 } 207 208 209 status_t 210 BCardLayout::Archive(BMessage* into, bool deep) const 211 { 212 BArchiver archiver(into); 213 status_t err = BAbstractLayout::Archive(into, deep); 214 215 if (err == B_OK && deep) 216 err = into->AddInt32(kVisibleItemField, IndexOfItem(fVisibleItem)); 217 218 return archiver.Finish(err); 219 } 220 221 222 status_t 223 BCardLayout::AllArchived(BMessage* archive) const 224 { 225 return BAbstractLayout::AllArchived(archive); 226 } 227 228 229 status_t 230 BCardLayout::AllUnarchived(const BMessage* from) 231 { 232 status_t err = BLayout::AllUnarchived(from); 233 if (err != B_OK) 234 return err; 235 236 int32 visibleIndex; 237 err = from->FindInt32(kVisibleItemField, &visibleIndex); 238 if (err == B_OK) 239 SetVisibleItem(visibleIndex); 240 241 return err; 242 } 243 244 245 status_t 246 BCardLayout::ItemArchived(BMessage* into, BLayoutItem* item, int32 index) const 247 { 248 return BAbstractLayout::ItemArchived(into, item, index); 249 } 250 251 252 status_t 253 BCardLayout::ItemUnarchived(const BMessage* from, BLayoutItem* item, 254 int32 index) 255 { 256 return BAbstractLayout::ItemUnarchived(from, item, index); 257 } 258 259 260 261 BArchivable* 262 BCardLayout::Instantiate(BMessage* from) 263 { 264 if (validate_instantiation(from, "BCardLayout")) 265 return new BCardLayout(from); 266 return NULL; 267 } 268 269 270 bool 271 BCardLayout::ItemAdded(BLayoutItem* item, int32 atIndex) 272 { 273 if (CountItems() <= 1) 274 SetVisibleItem(item); 275 else 276 item->SetVisible(false); 277 return true; 278 } 279 280 281 void 282 BCardLayout::ItemRemoved(BLayoutItem* item, int32 fromIndex) 283 { 284 fMinMaxValid = false; 285 286 if (fVisibleItem == item) { 287 BLayoutItem* newVisibleItem = NULL; 288 SetVisibleItem(newVisibleItem); 289 } 290 } 291 292 293 void 294 BCardLayout::_ValidateMinMax() 295 { 296 if (fMinMaxValid) 297 return; 298 299 fMin.width = 0; 300 fMin.height = 0; 301 fMax.width = B_SIZE_UNLIMITED; 302 fMax.height = B_SIZE_UNLIMITED; 303 fPreferred.width = 0; 304 fPreferred.height = 0; 305 306 int32 itemCount = CountItems(); 307 for (int32 i = 0; i < itemCount; i++) { 308 BLayoutItem* item = ItemAt(i); 309 310 BSize min = item->MinSize(); 311 BSize max = item->MaxSize(); 312 BSize preferred = item->PreferredSize(); 313 314 fMin.width = max_c(fMin.width, min.width); 315 fMin.height = max_c(fMin.height, min.height); 316 317 fMax.width = min_c(fMax.width, max.width); 318 fMax.height = min_c(fMax.height, max.height); 319 320 fPreferred.width = max_c(fPreferred.width, preferred.width); 321 fPreferred.height = max_c(fPreferred.height, preferred.height); 322 } 323 324 fMax.width = max_c(fMax.width, fMin.width); 325 fMax.height = max_c(fMax.height, fMin.height); 326 327 fPreferred.width = max_c(fPreferred.width, fMin.width); 328 fPreferred.height = max_c(fPreferred.height, fMin.height); 329 fPreferred.width = min_c(fPreferred.width, fMax.width); 330 fPreferred.height = min_c(fPreferred.height, fMax.height); 331 332 fMinMaxValid = true; 333 ResetLayoutInvalidation(); 334 } 335 336 337 status_t 338 BCardLayout::Perform(perform_code d, void* arg) 339 { 340 return BAbstractLayout::Perform(d, arg); 341 } 342 343 344 void BCardLayout::_ReservedCardLayout1() {} 345 void BCardLayout::_ReservedCardLayout2() {} 346 void BCardLayout::_ReservedCardLayout3() {} 347 void BCardLayout::_ReservedCardLayout4() {} 348 void BCardLayout::_ReservedCardLayout5() {} 349 void BCardLayout::_ReservedCardLayout6() {} 350 void BCardLayout::_ReservedCardLayout7() {} 351 void BCardLayout::_ReservedCardLayout8() {} 352 void BCardLayout::_ReservedCardLayout9() {} 353 void BCardLayout::_ReservedCardLayout10() {} 354 355