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