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