xref: /haiku/src/libs/alm/RowColumnManager.cpp (revision 002f37b0cca92e4cf72857c72ac95db5a8b09615)
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 
20 RowColumnManager::RowColumnManager(LinearSpec* spec)
21 	:
22 	fLinearSpec(spec)
23 {
24 
25 }
26 
27 
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
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
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
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
100 RowColumnManager::TabsChanged(Area* area)
101 {
102 	RemoveArea(area);
103 	AddArea(area);
104 }
105 
106 
107 Row*
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*
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
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
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
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
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