xref: /haiku/src/libs/alm/RowColumnManager.cpp (revision 1b6bc2675fe3691538c8764ab016593f3b06ca53)
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