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 if (fVisibleItem != NULL) 82 fVisibleItem->SetVisible(false); 83 84 fVisibleItem = item; 85 86 if (fVisibleItem != NULL) { 87 fVisibleItem->SetVisible(true); 88 89 Relayout(); 90 } 91 } 92 93 94 BSize 95 BCardLayout::BaseMinSize() 96 { 97 _ValidateMinMax(); 98 return fMin; 99 } 100 101 102 BSize 103 BCardLayout::BaseMaxSize() 104 { 105 _ValidateMinMax(); 106 return fMax; 107 } 108 109 110 BSize 111 BCardLayout::BasePreferredSize() 112 { 113 _ValidateMinMax(); 114 return fPreferred; 115 } 116 117 118 BAlignment 119 BCardLayout::BaseAlignment() 120 { 121 return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); 122 } 123 124 125 bool 126 BCardLayout::HasHeightForWidth() 127 { 128 int32 count = CountItems(); 129 for (int32 i = 0; i < count; i++) { 130 if (ItemAt(i)->HasHeightForWidth()) 131 return true; 132 } 133 134 return false; 135 } 136 137 138 void 139 BCardLayout::GetHeightForWidth(float width, float* min, float* max, 140 float* preferred) 141 { 142 _ValidateMinMax(); 143 144 // init with useful values 145 float minHeight = fMin.height; 146 float maxHeight = fMax.height; 147 float preferredHeight = fPreferred.height; 148 149 // apply the items' constraints 150 int32 count = CountItems(); 151 for (int32 i = 0; i < count; i++) { 152 BLayoutItem* item = ItemAt(i); 153 if (item->HasHeightForWidth()) { 154 float itemMinHeight; 155 float itemMaxHeight; 156 float itemPreferredHeight; 157 item->GetHeightForWidth(width, &itemMinHeight, &itemMaxHeight, 158 &itemPreferredHeight); 159 minHeight = max_c(minHeight, itemMinHeight); 160 maxHeight = min_c(maxHeight, itemMaxHeight); 161 preferredHeight = min_c(preferredHeight, itemPreferredHeight); 162 } 163 } 164 165 // adjust max and preferred, if necessary 166 maxHeight = max_c(maxHeight, minHeight); 167 preferredHeight = max_c(preferredHeight, minHeight); 168 preferredHeight = min_c(preferredHeight, maxHeight); 169 170 if (min) 171 *min = minHeight; 172 if (max) 173 *max = maxHeight; 174 if (preferred) 175 *preferred = preferredHeight; 176 } 177 178 179 void 180 BCardLayout::LayoutInvalidated(bool children) 181 { 182 fMinMaxValid = false; 183 } 184 185 186 void 187 BCardLayout::DoLayout() 188 { 189 _ValidateMinMax(); 190 191 BSize size(LayoutArea().Size()); 192 193 // this cannot be done when we are viewless, as our children 194 // would not get cut off in the right place. 195 if (Owner()) { 196 size.width = max_c(size.width, fMin.width); 197 size.height = max_c(size.height, fMin.height); 198 } 199 200 if (fVisibleItem != NULL) 201 fVisibleItem->AlignInFrame(BRect(LayoutArea().LeftTop(), size)); 202 } 203 204 205 status_t 206 BCardLayout::Archive(BMessage* into, bool deep) const 207 { 208 BArchiver archiver(into); 209 status_t err = BAbstractLayout::Archive(into, deep); 210 211 if (err == B_OK && deep) 212 err = into->AddInt32(kVisibleItemField, IndexOfItem(fVisibleItem)); 213 214 return archiver.Finish(err); 215 } 216 217 218 status_t 219 BCardLayout::AllArchived(BMessage* archive) const 220 { 221 return BAbstractLayout::AllArchived(archive); 222 } 223 224 225 status_t 226 BCardLayout::AllUnarchived(const BMessage* from) 227 { 228 status_t err = BLayout::AllUnarchived(from); 229 if (err != B_OK) 230 return err; 231 232 int32 visibleIndex; 233 err = from->FindInt32(kVisibleItemField, &visibleIndex); 234 if (err == B_OK) 235 SetVisibleItem(visibleIndex); 236 237 return err; 238 } 239 240 241 status_t 242 BCardLayout::ItemArchived(BMessage* into, BLayoutItem* item, int32 index) const 243 { 244 return BAbstractLayout::ItemArchived(into, item, index); 245 } 246 247 248 status_t 249 BCardLayout::ItemUnarchived(const BMessage* from, BLayoutItem* item, 250 int32 index) 251 { 252 return BAbstractLayout::ItemUnarchived(from, item, index); 253 } 254 255 256 257 BArchivable* 258 BCardLayout::Instantiate(BMessage* from) 259 { 260 if (validate_instantiation(from, "BCardLayout")) 261 return new BCardLayout(from); 262 return NULL; 263 } 264 265 266 bool 267 BCardLayout::ItemAdded(BLayoutItem* item, int32 atIndex) 268 { 269 item->SetVisible(false); 270 return true; 271 } 272 273 274 void 275 BCardLayout::ItemRemoved(BLayoutItem* item, int32 fromIndex) 276 { 277 if (fVisibleItem == item) { 278 BLayoutItem* newVisibleItem = NULL; 279 SetVisibleItem(newVisibleItem); 280 } 281 } 282 283 284 void 285 BCardLayout::_ValidateMinMax() 286 { 287 if (fMinMaxValid) 288 return; 289 290 fMin.width = 0; 291 fMin.height = 0; 292 fMax.width = B_SIZE_UNLIMITED; 293 fMax.height = B_SIZE_UNLIMITED; 294 fPreferred.width = 0; 295 fPreferred.height = 0; 296 297 int32 itemCount = CountItems(); 298 for (int32 i = 0; i < itemCount; i++) { 299 BLayoutItem* item = ItemAt(i); 300 301 BSize min = item->MinSize(); 302 BSize max = item->MaxSize(); 303 BSize preferred = item->PreferredSize(); 304 305 fMin.width = max_c(fMin.width, min.width); 306 fMin.height = max_c(fMin.height, min.height); 307 308 fMax.width = min_c(fMax.width, max.width); 309 fMax.height = min_c(fMax.height, max.height); 310 311 fPreferred.width = max_c(fPreferred.width, preferred.width); 312 fPreferred.height = max_c(fPreferred.height, preferred.height); 313 } 314 315 fMax.width = max_c(fMax.width, fMin.width); 316 fMax.height = max_c(fMax.height, fMin.height); 317 318 fPreferred.width = max_c(fPreferred.width, fMin.width); 319 fPreferred.height = max_c(fPreferred.height, fMin.height); 320 fPreferred.width = min_c(fPreferred.width, fMax.width); 321 fPreferred.height = min_c(fPreferred.height, fMax.height); 322 323 fMinMaxValid = true; 324 ResetLayoutInvalidation(); 325 } 326 327 328 status_t 329 BCardLayout::Perform(perform_code d, void* arg) 330 { 331 return BAbstractLayout::Perform(d, arg); 332 } 333 334 335 void BCardLayout::_ReservedCardLayout1() {} 336 void BCardLayout::_ReservedCardLayout2() {} 337 void BCardLayout::_ReservedCardLayout3() {} 338 void BCardLayout::_ReservedCardLayout4() {} 339 void BCardLayout::_ReservedCardLayout5() {} 340 void BCardLayout::_ReservedCardLayout6() {} 341 void BCardLayout::_ReservedCardLayout7() {} 342 void BCardLayout::_ReservedCardLayout8() {} 343 void BCardLayout::_ReservedCardLayout9() {} 344 void BCardLayout::_ReservedCardLayout10() {} 345 346