1 /* 2 * Copyright 2011, Haiku, Inc. All rights reserved. 3 * Copyright 2011, Clemens Zeidler <haiku@clemens-zeidler.de> 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include "RowColumnManager.h" 9 10 11 #include <LayoutItem.h> 12 13 14 using namespace LinearProgramming; 15 16 17 namespace BALM { 18 19 20 RowColumnManager::RowColumnManager(LinearSpec* spec) 21 : 22 fLinearSpec(spec) 23 { 24 25 } 26 27 28 RowColumnManager::~RowColumnManager() 29 { 30 for (int32 i = 0; i < fRows.CountItems(); i++) 31 delete fRows.ItemAt(i)->fPrefSizeConstraint; 32 33 for (int32 i = 0; i < fColumns.CountItems(); i++) 34 delete fColumns.ItemAt(i)->fPrefSizeConstraint; 35 } 36 37 38 void 39 RowColumnManager::AddArea(Area* area) 40 { 41 Row* row = _FindRowFor(area); 42 if (row == NULL) { 43 row = new Row(fLinearSpec, area->Top(), area->Bottom()); 44 fRows.AddItem(row); 45 } 46 area->fRow = row; 47 row->fAreas.AddItem(area); 48 49 Column* column = _FindColumnFor(area); 50 if (column == NULL) { 51 column = new Column(fLinearSpec, area->Left(), area->Right()); 52 fColumns.AddItem(column); 53 } 54 area->fColumn = column; 55 column->fAreas.AddItem(area); 56 57 _UpdateConstraints(row); 58 _UpdateConstraints(column); 59 } 60 61 62 void 63 RowColumnManager::RemoveArea(Area* area) 64 { 65 Row* row = area->fRow; 66 if (row) { 67 row->fAreas.RemoveItem(area); 68 area->fRow = NULL; 69 if (row->fAreas.CountItems() == 0) { 70 fRows.RemoveItem(row); 71 delete row; 72 } else 73 _UpdateConstraints(row); 74 } 75 76 Column* column = area->fColumn; 77 if (column) { 78 column->fAreas.RemoveItem(area); 79 area->fColumn = NULL; 80 if (column->fAreas.CountItems() == 0) { 81 fColumns.RemoveItem(column); 82 delete column; 83 } else 84 _UpdateConstraints(column); 85 } 86 } 87 88 89 void 90 RowColumnManager::UpdateConstraints() 91 { 92 for (int32 i = 0; i < fRows.CountItems(); i++) 93 _UpdateConstraints(fRows.ItemAt(i)); 94 for (int32 i = 0; i < fColumns.CountItems(); i++) 95 _UpdateConstraints(fColumns.ItemAt(i)); 96 } 97 98 99 void 100 RowColumnManager::TabsChanged(Area* area) 101 { 102 RemoveArea(area); 103 AddArea(area); 104 } 105 106 107 Row* 108 RowColumnManager::_FindRowFor(Area* area) 109 { 110 for (int32 i = 0; i < fRows.CountItems(); i++) { 111 Row* row = fRows.ItemAt(i); 112 if (row->fTop.Get() == area->Top() 113 && row->fBottom.Get() == area->Bottom()) 114 return row; 115 } 116 return NULL; 117 } 118 119 120 Column* 121 RowColumnManager::_FindColumnFor(Area* area) 122 { 123 for (int32 i = 0; i < fColumns.CountItems(); i++) { 124 Column* column = fColumns.ItemAt(i); 125 if (column->fLeft.Get() == area->Left() 126 && column->fRight.Get() == area->Right()) 127 return column; 128 } 129 return NULL; 130 } 131 132 133 double 134 RowColumnManager::_PreferredHeight(Row* row, double& weight) 135 { 136 weight = 0; 137 int nAreas = 0; 138 double pref = 0; 139 for (int32 i = 0; i < row->fAreas.CountItems(); i++) { 140 BSize prefSize = row->fAreas.ItemAt(i)->Item()->PreferredSize(); 141 if (prefSize.height <= 0) 142 continue; 143 nAreas++; 144 pref += prefSize.height; 145 double negPen = row->fAreas.ItemAt(i)->ShrinkPenalties().height; 146 if (negPen > 0) 147 weight += negPen; 148 } 149 if (nAreas == 0) { 150 pref = -1; 151 weight = 1; 152 } else { 153 pref /= nAreas; 154 weight /= nAreas; 155 } 156 return pref; 157 } 158 159 160 double 161 RowColumnManager::_PreferredWidth(Column* column, double& weight) 162 { 163 weight = 0; 164 int nAreas = 0; 165 double pref = 0; 166 for (int32 i = 0; i < column->fAreas.CountItems(); i++) { 167 BSize prefSize = column->fAreas.ItemAt(i)->Item()->PreferredSize(); 168 if (prefSize.width <= 0) 169 continue; 170 nAreas++; 171 pref += prefSize.width; 172 173 double negPen = column->fAreas.ItemAt(i)->ShrinkPenalties().height; 174 if (negPen > 0) 175 weight += negPen; 176 } 177 if (nAreas == 0) { 178 pref = -1; 179 weight = 1; 180 } else { 181 pref /= nAreas; 182 weight /= nAreas; 183 } 184 return pref; 185 } 186 187 188 void 189 RowColumnManager::_UpdateConstraints(Row* row) 190 { 191 double weight; 192 double prefSize = _PreferredHeight(row, weight); 193 if (prefSize >= 0) { 194 if (row->fPrefSizeConstraint == NULL) { 195 row->fPrefSizeConstraint = fLinearSpec->AddConstraint(1, 196 row->fBottom, -1, row->fTop, kEQ, prefSize, weight, weight); 197 row->fPrefSizeConstraint->SetLabel("Pref Height"); 198 } else { 199 row->fPrefSizeConstraint->SetRightSide(prefSize); 200 row->fPrefSizeConstraint->SetPenaltyNeg(weight); 201 row->fPrefSizeConstraint->SetPenaltyPos(weight); 202 } 203 } else { 204 delete row->fPrefSizeConstraint; 205 row->fPrefSizeConstraint = NULL; 206 } 207 } 208 209 210 void 211 RowColumnManager::_UpdateConstraints(Column* column) 212 { 213 double weight; 214 double prefSize = _PreferredWidth(column, weight); 215 if (prefSize >= 0) { 216 if (column->fPrefSizeConstraint == NULL) { 217 column->fPrefSizeConstraint = fLinearSpec->AddConstraint(1, 218 column->fRight, -1, column->fLeft, kEQ, prefSize, weight, 219 weight); 220 column->fPrefSizeConstraint->SetLabel("Pref Width"); 221 } else { 222 column->fPrefSizeConstraint->SetRightSide(prefSize); 223 column->fPrefSizeConstraint->SetPenaltyNeg(weight); 224 column->fPrefSizeConstraint->SetPenaltyPos(weight); 225 } 226 } else { 227 delete column->fPrefSizeConstraint; 228 column->fPrefSizeConstraint = NULL; 229 } 230 } 231 232 233 } // end BALM namespace 234 235