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 } 45 area->fRow = row; 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 } 53 area->fColumn = column; 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 = area->fRow; 65 if (row) { 66 row->fAreas.RemoveItem(area); 67 area->fRow = NULL; 68 if (row->fAreas.CountItems() == 0) { 69 fRows.RemoveItem(row); 70 delete row; 71 } 72 _UpdateConstraints(row); 73 } 74 75 Column* column = area->fColumn; 76 if (column) { 77 column->fAreas.RemoveItem(area); 78 area->fColumn = NULL; 79 if (column->fAreas.CountItems() == 0) { 80 fColumns.RemoveItem(column); 81 delete column; 82 } 83 _UpdateConstraints(column); 84 } 85 } 86 87 88 void 89 RowColumnManager::UpdateConstraints() 90 { 91 for (int32 i = 0; i < fRows.CountItems(); i++) 92 _UpdateConstraints(fRows.ItemAt(i)); 93 for (int32 i = 0; i < fColumns.CountItems(); i++) 94 _UpdateConstraints(fColumns.ItemAt(i)); 95 } 96 97 98 void 99 RowColumnManager::TabsChanged(Area* area) 100 { 101 RemoveArea(area); 102 AddArea(area); 103 } 104 105 106 Row* 107 RowColumnManager::_FindRowFor(Area* area) 108 { 109 for (int32 i = 0; i < fRows.CountItems(); i++) { 110 Row* row = fRows.ItemAt(i); 111 if (row->fTop.Get() == area->Top() 112 && row->fBottom.Get() == area->Bottom()) 113 return row; 114 } 115 return NULL; 116 } 117 118 119 Column* 120 RowColumnManager::_FindColumnFor(Area* area) 121 { 122 for (int32 i = 0; i < fColumns.CountItems(); i++) { 123 Column* column = fColumns.ItemAt(i); 124 if (column->fLeft.Get() == area->Left() 125 && column->fRight.Get() == area->Right()) 126 return column; 127 } 128 return NULL; 129 } 130 131 132 double 133 RowColumnManager::_PreferredHeight(Row* row, double& weight) 134 { 135 weight = 0; 136 int nAreas = 0; 137 double pref = 0; 138 for (int32 i = 0; i < row->fAreas.CountItems(); i++) { 139 BSize prefSize = row->fAreas.ItemAt(i)->Item()->PreferredSize(); 140 if (prefSize.height > 0) { 141 nAreas++; 142 pref += prefSize.height; 143 } 144 double negPen = row->fAreas.ItemAt(i)->ShrinkPenalties().height; 145 if (negPen > 0) 146 weight += negPen; 147 } 148 if (nAreas == 0) { 149 pref = 0; 150 weight = 1; 151 } else { 152 pref /= nAreas; 153 weight /= nAreas; 154 } 155 return pref; 156 } 157 158 159 double 160 RowColumnManager::_PreferredWidth(Column* column, double& weight) 161 { 162 weight = 0; 163 int nAreas = 0; 164 double pref = 0; 165 for (int32 i = 0; i < column->fAreas.CountItems(); i++) { 166 BSize prefSize = column->fAreas.ItemAt(i)->Item()->PreferredSize(); 167 if (prefSize.width > 0) { 168 nAreas++; 169 pref += prefSize.width; 170 } 171 double negPen = column->fAreas.ItemAt(i)->ShrinkPenalties().height; 172 if (negPen > 0) 173 weight += negPen; 174 } 175 if (nAreas == 0) { 176 pref = 0; 177 weight = 1; 178 } else { 179 pref /= nAreas; 180 weight /= nAreas; 181 } 182 return pref; 183 } 184 185 186 void 187 RowColumnManager::_UpdateConstraints(Row* row) 188 { 189 double weight; 190 double prefSize = _PreferredHeight(row, weight); 191 if (prefSize >= 0) { 192 if (row->fPrefSizeConstraint == NULL) { 193 row->fPrefSizeConstraint = fLinearSpec->AddConstraint(1, 194 row->fBottom, -1, row->fTop, kEQ, prefSize, weight, weight); 195 } else { 196 row->fPrefSizeConstraint->SetRightSide(prefSize); 197 row->fPrefSizeConstraint->SetPenaltyNeg(weight); 198 row->fPrefSizeConstraint->SetPenaltyPos(weight); 199 } 200 } else { 201 delete row->fPrefSizeConstraint; 202 row->fPrefSizeConstraint = NULL; 203 } 204 } 205 206 207 void 208 RowColumnManager::_UpdateConstraints(Column* column) 209 { 210 double weight; 211 double prefSize = _PreferredWidth(column, weight); 212 if (prefSize >= 0) { 213 if (column->fPrefSizeConstraint == NULL) { 214 column->fPrefSizeConstraint = fLinearSpec->AddConstraint(1, 215 column->fRight, -1, column->fLeft, kEQ, prefSize, weight, 216 weight); 217 } else { 218 column->fPrefSizeConstraint->SetRightSide(prefSize); 219 column->fPrefSizeConstraint->SetPenaltyNeg(weight); 220 column->fPrefSizeConstraint->SetPenaltyPos(weight); 221 } 222 } else { 223 delete column->fPrefSizeConstraint; 224 column->fPrefSizeConstraint = NULL; 225 } 226 } 227 228 229 } // end BALM namespace 230 231