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::InvalidateLayout(bool children) 178 { 179 BLayout::InvalidateLayout(children); 180 181 fMinMaxValid = false; 182 } 183 184 185 void 186 BCardLayout::DerivedLayoutItems() 187 { 188 _ValidateMinMax(); 189 190 BSize size(LayoutArea().Size()); 191 192 // this cannot be done when we are viewless, as our children 193 // would not get cut off in the right place. 194 if (Owner()) { 195 size.width = max_c(size.width, fMin.width); 196 size.height = max_c(size.height, fMin.height); 197 } 198 199 if (fVisibleItem != NULL) 200 fVisibleItem->AlignInFrame(BRect(LayoutArea().LeftTop(), size)); 201 } 202 203 204 status_t 205 BCardLayout::Archive(BMessage* into, bool deep) const 206 { 207 BArchiver archiver(into); 208 status_t err = BAbstractLayout::Archive(into, deep); 209 210 if (err == B_OK && deep) 211 err = into->AddInt32(kVisibleItemField, IndexOfItem(fVisibleItem)); 212 213 return archiver.Finish(err); 214 } 215 216 217 status_t 218 BCardLayout::AllUnarchived(const BMessage* from) 219 { 220 status_t err = BLayout::AllUnarchived(from); 221 if (err != B_OK) 222 return err; 223 224 int32 visibleIndex; 225 err = from->FindInt32(kVisibleItemField, &visibleIndex); 226 if (err == B_OK) 227 SetVisibleItem(visibleIndex); 228 229 return err; 230 } 231 232 233 BArchivable* 234 BCardLayout::Instantiate(BMessage* from) 235 { 236 if (validate_instantiation(from, "BCardLayout")) 237 return new BCardLayout(from); 238 return NULL; 239 } 240 241 242 bool 243 BCardLayout::ItemAdded(BLayoutItem* item, int32 atIndex) 244 { 245 item->SetVisible(false); 246 return true; 247 } 248 249 250 void 251 BCardLayout::ItemRemoved(BLayoutItem* item, int32 fromIndex) 252 { 253 if (fVisibleItem == item) { 254 BLayoutItem* newVisibleItem = NULL; 255 SetVisibleItem(newVisibleItem); 256 } 257 } 258 259 260 void 261 BCardLayout::_ValidateMinMax() 262 { 263 if (fMinMaxValid) 264 return; 265 266 fMin.width = 0; 267 fMin.height = 0; 268 fMax.width = B_SIZE_UNLIMITED; 269 fMax.height = B_SIZE_UNLIMITED; 270 fPreferred.width = 0; 271 fPreferred.height = 0; 272 273 int32 itemCount = CountItems(); 274 for (int32 i = 0; i < itemCount; i++) { 275 BLayoutItem* item = ItemAt(i); 276 277 BSize min = item->MinSize(); 278 BSize max = item->MaxSize(); 279 BSize preferred = item->PreferredSize(); 280 281 fMin.width = max_c(fMin.width, min.width); 282 fMin.height = max_c(fMin.height, min.height); 283 284 fMax.width = min_c(fMax.width, max.width); 285 fMax.height = min_c(fMax.height, max.height); 286 287 fPreferred.width = max_c(fPreferred.width, preferred.width); 288 fPreferred.height = max_c(fPreferred.height, preferred.height); 289 } 290 291 fMax.width = max_c(fMax.width, fMin.width); 292 fMax.height = max_c(fMax.height, fMin.height); 293 294 fPreferred.width = max_c(fPreferred.width, fMin.width); 295 fPreferred.height = max_c(fPreferred.height, fMin.height); 296 fPreferred.width = min_c(fPreferred.width, fMax.width); 297 fPreferred.height = min_c(fPreferred.height, fMax.height); 298 299 fMinMaxValid = true; 300 ResetLayoutInvalidation(); 301 } 302