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 BLayout(), 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 BLayout(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 LayoutView(); 87 } 88 } 89 90 91 BSize 92 BCardLayout::MinSize() 93 { 94 _ValidateMinMax(); 95 return fMin; 96 } 97 98 99 BSize 100 BCardLayout::MaxSize() 101 { 102 _ValidateMinMax(); 103 return fMax; 104 } 105 106 107 BSize 108 BCardLayout::PreferredSize() 109 { 110 _ValidateMinMax(); 111 return fPreferred; 112 } 113 114 115 BAlignment 116 BCardLayout::Alignment() 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() 178 { 179 BLayout::InvalidateLayout(); 180 181 fMinMaxValid = false; 182 } 183 184 185 void 186 BCardLayout::LayoutView() 187 { 188 _ValidateMinMax(); 189 190 BSize size = View()->Bounds().Size(); 191 size.width = max_c(size.width, fMin.width); 192 size.height = max_c(size.height, fMin.height); 193 194 if (fVisibleItem != NULL) 195 fVisibleItem->AlignInFrame(BRect(0, 0, size.width, size.height)); 196 } 197 198 199 status_t 200 BCardLayout::Archive(BMessage* into, bool deep) const 201 { 202 BArchiver archiver(into); 203 status_t err = BLayout::Archive(into, deep); 204 205 if (err == B_OK && deep) 206 err = into->AddInt32(kVisibleItemField, IndexOfItem(fVisibleItem)); 207 208 return archiver.Finish(err); 209 } 210 211 212 status_t 213 BCardLayout::AllUnarchived(const BMessage* from) 214 { 215 status_t err = BLayout::AllUnarchived(from); 216 if (err != B_OK) 217 return err; 218 219 int32 visibleIndex; 220 err = from->FindInt32(kVisibleItemField, &visibleIndex); 221 if (err == B_OK) 222 SetVisibleItem(visibleIndex); 223 224 return err; 225 } 226 227 228 BArchivable* 229 BCardLayout::Instantiate(BMessage* from) 230 { 231 if (validate_instantiation(from, "BCardLayout")) 232 return new BCardLayout(from); 233 return NULL; 234 } 235 236 237 bool 238 BCardLayout::ItemAdded(BLayoutItem* item, int32 atIndex) 239 { 240 item->SetVisible(false); 241 return true; 242 } 243 244 245 void 246 BCardLayout::ItemRemoved(BLayoutItem* item, int32 fromIndex) 247 { 248 if (fVisibleItem == item) { 249 BLayoutItem* newVisibleItem = NULL; 250 SetVisibleItem(newVisibleItem); 251 } 252 } 253 254 255 void 256 BCardLayout::_ValidateMinMax() 257 { 258 if (fMinMaxValid) 259 return; 260 261 fMin.width = 0; 262 fMin.height = 0; 263 fMax.width = B_SIZE_UNLIMITED; 264 fMax.height = B_SIZE_UNLIMITED; 265 fPreferred.width = 0; 266 fPreferred.height = 0; 267 268 int32 itemCount = CountItems(); 269 for (int32 i = 0; i < itemCount; i++) { 270 BLayoutItem* item = ItemAt(i); 271 272 BSize min = item->MinSize(); 273 BSize max = item->MaxSize(); 274 BSize preferred = item->PreferredSize(); 275 276 fMin.width = max_c(fMin.width, min.width); 277 fMin.height = max_c(fMin.height, min.height); 278 279 fMax.width = min_c(fMax.width, max.width); 280 fMax.height = min_c(fMax.height, max.height); 281 282 fPreferred.width = max_c(fPreferred.width, preferred.width); 283 fPreferred.height = max_c(fPreferred.height, preferred.height); 284 } 285 286 fMax.width = max_c(fMax.width, fMin.width); 287 fMax.height = max_c(fMax.height, fMin.height); 288 289 fPreferred.width = max_c(fPreferred.width, fMin.width); 290 fPreferred.height = max_c(fPreferred.height, fMin.height); 291 fPreferred.width = min_c(fPreferred.width, fMax.width); 292 fPreferred.height = min_c(fPreferred.height, fMax.height); 293 294 fMinMaxValid = true; 295 296 if (BView* view = View()) 297 view->ResetLayoutInvalidation(); 298 } 299