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 13namespace { 14 const char* kVisibleItemField = "BCardLayout:visibleItem"; 15} 16 17 18BCardLayout::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 30BCardLayout::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 43BCardLayout::~BCardLayout() 44{ 45} 46 47 48BLayoutItem* 49BCardLayout::VisibleItem() const 50{ 51 return fVisibleItem; 52} 53 54 55int32 56BCardLayout::VisibleIndex() const 57{ 58 return IndexOfItem(fVisibleItem); 59} 60 61 62void 63BCardLayout::SetVisibleItem(int32 index) 64{ 65 SetVisibleItem(ItemAt(index)); 66} 67 68 69void 70BCardLayout::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 98BSize 99BCardLayout::BaseMinSize() 100{ 101 _ValidateMinMax(); 102 return fMin; 103} 104 105 106BSize 107BCardLayout::BaseMaxSize() 108{ 109 _ValidateMinMax(); 110 return fMax; 111} 112 113 114BSize 115BCardLayout::BasePreferredSize() 116{ 117 _ValidateMinMax(); 118 return fPreferred; 119} 120 121 122BAlignment 123BCardLayout::BaseAlignment() 124{ 125 return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); 126} 127 128 129bool 130BCardLayout::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 142void 143BCardLayout::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 183void 184BCardLayout::LayoutInvalidated(bool children) 185{ 186 fMinMaxValid = false; 187} 188 189 190void 191BCardLayout::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 209status_t 210BCardLayout::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 222status_t 223BCardLayout::AllArchived(BMessage* archive) const 224{ 225 return BAbstractLayout::AllArchived(archive); 226} 227 228 229status_t 230BCardLayout::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 245status_t 246BCardLayout::ItemArchived(BMessage* into, BLayoutItem* item, int32 index) const 247{ 248 return BAbstractLayout::ItemArchived(into, item, index); 249} 250 251 252status_t 253BCardLayout::ItemUnarchived(const BMessage* from, BLayoutItem* item, 254 int32 index) 255{ 256 return BAbstractLayout::ItemUnarchived(from, item, index); 257} 258 259 260 261BArchivable* 262BCardLayout::Instantiate(BMessage* from) 263{ 264 if (validate_instantiation(from, "BCardLayout")) 265 return new BCardLayout(from); 266 return NULL; 267} 268 269 270bool 271BCardLayout::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 281void 282BCardLayout::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 293void 294BCardLayout::_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 337status_t 338BCardLayout::Perform(perform_code d, void* arg) 339{ 340 return BAbstractLayout::Perform(d, arg); 341} 342 343 344void BCardLayout::_ReservedCardLayout1() {} 345void BCardLayout::_ReservedCardLayout2() {} 346void BCardLayout::_ReservedCardLayout3() {} 347void BCardLayout::_ReservedCardLayout4() {} 348void BCardLayout::_ReservedCardLayout5() {} 349void BCardLayout::_ReservedCardLayout6() {} 350void BCardLayout::_ReservedCardLayout7() {} 351void BCardLayout::_ReservedCardLayout8() {} 352void BCardLayout::_ReservedCardLayout9() {} 353void BCardLayout::_ReservedCardLayout10() {} 354 355