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