xref: /haiku/src/libs/alm/RowColumnManager.cpp (revision 1c09002cbee8e797a0f8bbfc5678dfadd39ee1a7)
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 		area->fRow = row;
45 	}
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 		area->fColumn = column;
53 	}
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 = _FindRowFor(area);
65 	if (row) {
66 		row->fAreas.RemoveItem(area);
67 		if (row->fAreas.CountItems() == 0) {
68 			fRows.RemoveItem(row);
69 			delete row;
70 		} else
71 			_UpdateConstraints(row);
72 	}
73 
74 	Column* column = _FindColumnFor(area);
75 	if (column) {
76 		column->fAreas.RemoveItem(area);
77 		if (column->fAreas.CountItems() == 0) {
78 			fColumns.RemoveItem(column);
79 			delete column;
80 		} else
81 			_UpdateConstraints(column);
82 	}
83 }
84 
85 
86 void
87 RowColumnManager::UpdateConstraints()
88 {
89 	for (int32 i = 0; i < fRows.CountItems(); i++)
90 		_UpdateConstraints(fRows.ItemAt(i));
91 	for (int32 i = 0; i < fColumns.CountItems(); i++)
92 		_UpdateConstraints(fColumns.ItemAt(i));
93 }
94 
95 
96 void
97 RowColumnManager::TabsChanged(Area* area)
98 {
99 	RemoveArea(area);
100 	AddArea(area);
101 }
102 
103 
104 Row*
105 RowColumnManager::_FindRowFor(Area* area)
106 {
107 	for (int32 i = 0; i < fRows.CountItems(); i++) {
108 		Row* row = fRows.ItemAt(i);
109 		if (row->fTop == area->Top() && row->fBottom == area->Bottom())
110 			return row;
111 	}
112 	return NULL;
113 }
114 
115 
116 Column*
117 RowColumnManager::_FindColumnFor(Area* area)
118 {
119 	for (int32 i = 0; i < fColumns.CountItems(); i++) {
120 		Column* column = fColumns.ItemAt(i);
121 		if (column->fLeft == area->Left() && column->fRight == area->Right())
122 			return column;
123 	}
124 	return NULL;
125 }
126 
127 
128 double
129 RowColumnManager::_PreferredHeight(Row* row, double& weight)
130 {
131 	weight = 0;
132 	int nAreas = 0;
133 	double pref = 0;
134 	for (int32 i = 0; i < row->fAreas.CountItems(); i++) {
135 		BSize prefSize = row->fAreas.ItemAt(i)->Item()->PreferredSize();
136 		if (prefSize.height > 0) {
137 			nAreas++;
138 			pref += prefSize.height;
139 		}
140 		double negPen = row->fAreas.ItemAt(i)->ShrinkPenalties().height;
141 		if (negPen > 0)
142 			weight += negPen;
143 	}
144 	if (nAreas == 0) {
145 		pref = 0;
146 		weight = 1;
147 	} else {
148 		pref /= nAreas;
149 		weight /= nAreas;
150 	}
151 	return pref;
152 }
153 
154 
155 double
156 RowColumnManager::_PreferredWidth(Column* column, double& weight)
157 {
158 	weight = 0;
159 	int nAreas = 0;
160 	double pref = 0;
161 	for (int32 i = 0; i < column->fAreas.CountItems(); i++) {
162 		BSize prefSize = column->fAreas.ItemAt(i)->Item()->PreferredSize();
163 		if (prefSize.width > 0) {
164 			nAreas++;
165 			pref += prefSize.width;
166 		}
167 		double negPen = column->fAreas.ItemAt(i)->ShrinkPenalties().height;
168 		if (negPen > 0)
169 			weight += negPen;
170 	}
171 	if (nAreas == 0) {
172 		pref = 0;
173 		weight = 1;
174 	} else {
175 		pref /= nAreas;
176 		weight /= nAreas;
177 	}
178 	return pref;
179 }
180 
181 
182 void
183 RowColumnManager::_UpdateConstraints(Row* row)
184 {
185 	double weight;
186 	double prefSize = _PreferredHeight(row, weight);
187 	if (prefSize >= 0) {
188 		if (row->fPrefSizeConstraint == NULL) {
189 			row->fPrefSizeConstraint = fLinearSpec->AddConstraint(1,
190 			row->fBottom, -1, row->fTop, kEQ, prefSize, weight, weight);
191 		} else {
192 			row->fPrefSizeConstraint->SetRightSide(prefSize);
193 			row->fPrefSizeConstraint->SetPenaltyNeg(weight);
194 			row->fPrefSizeConstraint->SetPenaltyPos(weight);
195 		}
196 	} else {
197 		delete row->fPrefSizeConstraint;
198 		row->fPrefSizeConstraint = NULL;
199 	}
200 }
201 
202 
203 void
204 RowColumnManager::_UpdateConstraints(Column* column)
205 {
206 	double weight;
207 	double prefSize = _PreferredWidth(column, weight);
208 	if (prefSize >= 0) {
209 		if (column->fPrefSizeConstraint == NULL) {
210 			column->fPrefSizeConstraint = fLinearSpec->AddConstraint(1,
211 				column->fRight, -1, column->fLeft, kEQ, prefSize, weight,
212 				weight);
213 		} else {
214 			column->fPrefSizeConstraint->SetRightSide(prefSize);
215 			column->fPrefSizeConstraint->SetPenaltyNeg(weight);
216 			column->fPrefSizeConstraint->SetPenaltyPos(weight);
217 		}
218 	} else {
219 		delete column->fPrefSizeConstraint;
220 		column->fPrefSizeConstraint = NULL;
221 	}
222 }
223 
224 
225 } // end BALM namespace
226 
227