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 == area->Top() && row->fBottom == area->Bottom()) 112 return row; 113 } 114 return NULL; 115 } 116 117 118 Column* 119 RowColumnManager::_FindColumnFor(Area* area) 120 { 121 for (int32 i = 0; i < fColumns.CountItems(); i++) { 122 Column* column = fColumns.ItemAt(i); 123 if (column->fLeft == area->Left() && column->fRight == area->Right()) 124 return column; 125 } 126 return NULL; 127 } 128 129 130 double 131 RowColumnManager::_PreferredHeight(Row* row, double& weight) 132 { 133 weight = 0; 134 int nAreas = 0; 135 double pref = 0; 136 for (int32 i = 0; i < row->fAreas.CountItems(); i++) { 137 BSize prefSize = row->fAreas.ItemAt(i)->Item()->PreferredSize(); 138 if (prefSize.height > 0) { 139 nAreas++; 140 pref += prefSize.height; 141 } 142 double negPen = row->fAreas.ItemAt(i)->ShrinkPenalties().height; 143 if (negPen > 0) 144 weight += negPen; 145 } 146 if (nAreas == 0) { 147 pref = 0; 148 weight = 1; 149 } else { 150 pref /= nAreas; 151 weight /= nAreas; 152 } 153 return pref; 154 } 155 156 157 double 158 RowColumnManager::_PreferredWidth(Column* column, double& weight) 159 { 160 weight = 0; 161 int nAreas = 0; 162 double pref = 0; 163 for (int32 i = 0; i < column->fAreas.CountItems(); i++) { 164 BSize prefSize = column->fAreas.ItemAt(i)->Item()->PreferredSize(); 165 if (prefSize.width > 0) { 166 nAreas++; 167 pref += prefSize.width; 168 } 169 double negPen = column->fAreas.ItemAt(i)->ShrinkPenalties().height; 170 if (negPen > 0) 171 weight += negPen; 172 } 173 if (nAreas == 0) { 174 pref = 0; 175 weight = 1; 176 } else { 177 pref /= nAreas; 178 weight /= nAreas; 179 } 180 return pref; 181 } 182 183 184 void 185 RowColumnManager::_UpdateConstraints(Row* row) 186 { 187 double weight; 188 double prefSize = _PreferredHeight(row, weight); 189 if (prefSize >= 0) { 190 if (row->fPrefSizeConstraint == NULL) { 191 row->fPrefSizeConstraint = fLinearSpec->AddConstraint(1, 192 row->fBottom, -1, row->fTop, kEQ, prefSize, weight, weight); 193 } else { 194 row->fPrefSizeConstraint->SetRightSide(prefSize); 195 row->fPrefSizeConstraint->SetPenaltyNeg(weight); 196 row->fPrefSizeConstraint->SetPenaltyPos(weight); 197 } 198 } else { 199 delete row->fPrefSizeConstraint; 200 row->fPrefSizeConstraint = NULL; 201 } 202 } 203 204 205 void 206 RowColumnManager::_UpdateConstraints(Column* column) 207 { 208 double weight; 209 double prefSize = _PreferredWidth(column, weight); 210 if (prefSize >= 0) { 211 if (column->fPrefSizeConstraint == NULL) { 212 column->fPrefSizeConstraint = fLinearSpec->AddConstraint(1, 213 column->fRight, -1, column->fLeft, kEQ, prefSize, weight, 214 weight); 215 } else { 216 column->fPrefSizeConstraint->SetRightSide(prefSize); 217 column->fPrefSizeConstraint->SetPenaltyNeg(weight); 218 column->fPrefSizeConstraint->SetPenaltyPos(weight); 219 } 220 } else { 221 delete column->fPrefSizeConstraint; 222 column->fPrefSizeConstraint = NULL; 223 } 224 } 225 226 227 } // end BALM namespace 228 229