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 14using namespace LinearProgramming; 15 16 17namespace BALM { 18 19 20RowColumnManager::RowColumnManager(LinearSpec* spec) 21 : 22 fLinearSpec(spec) 23{ 24 25} 26 27 28RowColumnManager::~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 38void 39RowColumnManager::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 62void 63RowColumnManager::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 89void 90RowColumnManager::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 99void 100RowColumnManager::TabsChanged(Area* area) 101{ 102 RemoveArea(area); 103 AddArea(area); 104} 105 106 107Row* 108RowColumnManager::_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 120Column* 121RowColumnManager::_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 133double 134RowColumnManager::_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 160double 161RowColumnManager::_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 188void 189RowColumnManager::_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 210void 211RowColumnManager::_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