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