1 /* 2 * Copyright 2010, Haiku, Inc. 3 * Copyright 2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>. 4 * All rights reserved. Distributed under the terms of the MIT License. 5 */ 6 7 8 #include <GroupLayout.h> 9 10 #include <LayoutItem.h> 11 #include <Message.h> 12 13 #include <new> 14 15 16 using std::nothrow; 17 18 19 namespace { 20 const char* const kItemWeightField = "BGroupLayout:item:weight"; 21 const char* const kVerticalField = "BGroupLayout:vertical"; 22 } 23 24 25 struct BGroupLayout::ItemLayoutData { 26 float weight; 27 28 ItemLayoutData() 29 : weight(1) 30 { 31 } 32 }; 33 34 35 BGroupLayout::BGroupLayout(enum orientation orientation, float spacing) 36 : 37 BTwoDimensionalLayout(), 38 fOrientation(orientation) 39 { 40 SetSpacing(spacing); 41 } 42 43 44 BGroupLayout::BGroupLayout(BMessage* from) 45 : 46 BTwoDimensionalLayout(from) 47 { 48 bool isVertical; 49 if (from->FindBool(kVerticalField, &isVertical) != B_OK) 50 isVertical = false; 51 fOrientation = isVertical ? B_VERTICAL : B_HORIZONTAL; 52 } 53 54 55 BGroupLayout::~BGroupLayout() 56 { 57 } 58 59 60 float 61 BGroupLayout::Spacing() const 62 { 63 return fHSpacing; 64 } 65 66 67 void 68 BGroupLayout::SetSpacing(float spacing) 69 { 70 if (spacing != fHSpacing) { 71 fHSpacing = spacing; 72 fVSpacing = spacing; 73 InvalidateLayout(); 74 } 75 } 76 77 78 orientation 79 BGroupLayout::Orientation() const 80 { 81 return fOrientation; 82 } 83 84 85 void 86 BGroupLayout::SetOrientation(enum orientation orientation) 87 { 88 if (orientation != fOrientation) { 89 fOrientation = orientation; 90 91 InvalidateLayout(); 92 } 93 } 94 95 96 float 97 BGroupLayout::ItemWeight(int32 index) const 98 { 99 if (index < 0 || index >= CountItems()) 100 return 0; 101 102 ItemLayoutData* data = _LayoutDataForItem(ItemAt(index)); 103 return (data ? data->weight : 0); 104 } 105 106 107 void 108 BGroupLayout::SetItemWeight(int32 index, float weight) 109 { 110 if (index < 0 || index >= CountItems()) 111 return; 112 113 if (ItemLayoutData* data = _LayoutDataForItem(ItemAt(index))) 114 data->weight = weight; 115 116 InvalidateLayout(); 117 } 118 119 120 BLayoutItem* 121 BGroupLayout::AddView(BView* child) 122 { 123 return BTwoDimensionalLayout::AddView(child); 124 } 125 126 127 BLayoutItem* 128 BGroupLayout::AddView(int32 index, BView* child) 129 { 130 return BTwoDimensionalLayout::AddView(index, child); 131 } 132 133 134 BLayoutItem* 135 BGroupLayout::AddView(BView* child, float weight) 136 { 137 return AddView(-1, child, weight); 138 } 139 140 141 BLayoutItem* 142 BGroupLayout::AddView(int32 index, BView* child, float weight) 143 { 144 BLayoutItem* item = AddView(index, child); 145 if (ItemLayoutData* data = _LayoutDataForItem(item)) 146 data->weight = weight; 147 148 return item; 149 } 150 151 152 bool 153 BGroupLayout::AddItem(BLayoutItem* item) 154 { 155 return BTwoDimensionalLayout::AddItem(item); 156 } 157 158 159 bool 160 BGroupLayout::AddItem(int32 index, BLayoutItem* item) 161 { 162 return BTwoDimensionalLayout::AddItem(index, item); 163 } 164 165 166 bool 167 BGroupLayout::AddItem(BLayoutItem* item, float weight) 168 { 169 return AddItem(-1, item, weight); 170 } 171 172 173 bool 174 BGroupLayout::AddItem(int32 index, BLayoutItem* item, float weight) 175 { 176 bool success = AddItem(index, item); 177 if (success) { 178 if (ItemLayoutData* data = _LayoutDataForItem(item)) 179 data->weight = weight; 180 } 181 182 return success; 183 } 184 185 186 status_t 187 BGroupLayout::Archive(BMessage* into, bool deep) const 188 { 189 BArchiver archiver(into); 190 status_t err = BTwoDimensionalLayout::Archive(into, deep); 191 192 if (err == B_OK) 193 err = into->AddBool(kVerticalField, fOrientation == B_VERTICAL); 194 195 return archiver.Finish(err); 196 } 197 198 199 status_t 200 BGroupLayout::AllUnarchived(const BMessage* from) 201 { 202 return BTwoDimensionalLayout::AllUnarchived(from); 203 } 204 205 206 BArchivable* 207 BGroupLayout::Instantiate(BMessage* from) 208 { 209 if (validate_instantiation(from, "BGroupLayout")) 210 return new(nothrow) BGroupLayout(from); 211 return NULL; 212 } 213 214 215 status_t 216 BGroupLayout::ItemArchived(BMessage* into, 217 BLayoutItem* item, int32 index) const 218 { 219 return into->AddFloat(kItemWeightField, _LayoutDataForItem(item)->weight); 220 } 221 222 223 status_t 224 BGroupLayout::ItemUnarchived(const BMessage* from, 225 BLayoutItem* item, int32 index) 226 { 227 float weight; 228 status_t err = from->FindFloat(kItemWeightField, index, &weight); 229 230 if (err == B_OK) 231 _LayoutDataForItem(item)->weight = weight; 232 233 return err; 234 } 235 236 237 bool 238 BGroupLayout::ItemAdded(BLayoutItem* item, int32 atIndex) 239 { 240 item->SetLayoutData(new(nothrow) ItemLayoutData); 241 return item->LayoutData() != NULL; 242 } 243 244 245 void 246 BGroupLayout::ItemRemoved(BLayoutItem* item, int32 fromIndex) 247 { 248 if (ItemLayoutData* data = _LayoutDataForItem(item)) { 249 item->SetLayoutData(NULL); 250 delete data; 251 } 252 } 253 254 255 void 256 BGroupLayout::PrepareItems(enum orientation orientation) 257 { 258 // filter the visible items 259 fVisibleItems.MakeEmpty(); 260 int32 itemCount = CountItems(); 261 for (int i = 0; i < itemCount; i++) { 262 BLayoutItem* item = ItemAt(i); 263 if (item->IsVisible()) 264 fVisibleItems.AddItem(item); 265 } 266 } 267 268 269 int32 270 BGroupLayout::InternalCountColumns() 271 { 272 return (fOrientation == B_HORIZONTAL ? fVisibleItems.CountItems() : 1); 273 } 274 275 276 int32 277 BGroupLayout::InternalCountRows() 278 { 279 return (fOrientation == B_VERTICAL ? fVisibleItems.CountItems() : 1); 280 } 281 282 283 void 284 BGroupLayout::GetColumnRowConstraints(enum orientation orientation, int32 index, 285 ColumnRowConstraints* constraints) 286 { 287 if (index >= 0 && index < fVisibleItems.CountItems()) { 288 BLayoutItem* item = (BLayoutItem*)fVisibleItems.ItemAt(index); 289 constraints->min = -1; 290 constraints->max = B_SIZE_UNLIMITED; 291 if (ItemLayoutData* data = _LayoutDataForItem(item)) 292 constraints->weight = data->weight; 293 else 294 constraints->weight = 1; 295 } 296 } 297 298 299 void 300 BGroupLayout::GetItemDimensions(BLayoutItem* item, Dimensions* dimensions) 301 { 302 int32 index = fVisibleItems.IndexOf(item); 303 if (index < 0) 304 return; 305 306 if (fOrientation == B_HORIZONTAL) { 307 dimensions->x = index; 308 dimensions->y = 0; 309 dimensions->width = 1; 310 dimensions->height = 1; 311 } else { 312 dimensions->x = 0; 313 dimensions->y = index; 314 dimensions->width = 1; 315 dimensions->height = 1; 316 } 317 } 318 319 320 BGroupLayout::ItemLayoutData* 321 BGroupLayout::_LayoutDataForItem(BLayoutItem* item) const 322 { 323 if (!item) 324 return NULL; 325 return (ItemLayoutData*)item->LayoutData(); 326 } 327