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
RowColumnManager(LinearSpec * spec)20 RowColumnManager::RowColumnManager(LinearSpec* spec)
21 :
22 fLinearSpec(spec)
23 {
24
25 }
26
27
~RowColumnManager()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
AddArea(Area * area)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
RemoveArea(Area * area)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
UpdateConstraints()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
TabsChanged(Area * area)100 RowColumnManager::TabsChanged(Area* area)
101 {
102 RemoveArea(area);
103 AddArea(area);
104 }
105
106
107 Row*
_FindRowFor(Area * area)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*
_FindColumnFor(Area * area)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
_PreferredHeight(Row * row,double & weight)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
_PreferredWidth(Column * column,double & weight)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
_UpdateConstraints(Row * row)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
_UpdateConstraints(Column * column)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