2 * Copyright 2012, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
7 #include "SharedSolver.h"
11 #include <ALMLayout.h>
12 #include <AutoDeleter.h>
13 #include <ObjectList.h>
15 #include "RowColumnManager.h"
18 using LinearProgramming::LinearSpec
;
23 type_code kConstraintsTypeCode
= 'cnst';
24 const char* kConstraintsField
= "SharedSolver:constraints";
29 struct SharedSolver::MinSizeValidator
{
30 inline void CallSolverMethod(LinearSpec
* spec
, VariableList
* vars
)
35 inline void Finalize(BALMLayout
* layout
, SharedSolver
* solver
,
36 ResultType solveResult
)
38 if (solveResult
== LinearProgramming::kUnbounded
) {
39 solver
->SetMinSize(layout
, BSize(0, 0));
41 solver
->SetMinSize(layout
, BSize(ceilf(layout
->Right()->Value()),
42 ceilf(layout
->Bottom()->Value())));
48 struct SharedSolver::MaxSizeValidator
{
49 inline void CallSolverMethod(LinearSpec
* spec
, VariableList
* vars
)
54 inline void Finalize(BALMLayout
* layout
, SharedSolver
* solver
,
55 ResultType solveResult
)
57 if (solveResult
== LinearProgramming::kUnbounded
) {
58 solver
->SetMaxSize(layout
,
59 BSize(B_SIZE_UNLIMITED
, B_SIZE_UNLIMITED
));
61 solver
->SetMaxSize(layout
, BSize(floorf(layout
->Right()->Value()),
62 floorf(layout
->Bottom()->Value())));
68 struct SharedSolver::PreferredSizeValidator
{
69 inline void CallSolverMethod(LinearSpec
* spec
, VariableList
* vars
)
74 inline void Finalize(BALMLayout
* layout
, SharedSolver
* solver
,
75 ResultType solveResult
)
77 float width
= layout
->Right()->Value() - layout
->Left()->Value();
78 float height
= layout
->Bottom()->Value() - layout
->Top()->Value();
79 solver
->SetPreferredSize(layout
, BSize(width
, height
));
84 SharedSolver::SharedSolver()
86 fConstraintsValid(false),
89 fPreferredValid(false),
96 SharedSolver::SharedSolver(BMessage
* archive
)
99 fConstraintsValid(false),
102 fPreferredValid(false),
109 SharedSolver::~SharedSolver()
111 if (fLayouts
.CountItems() > 0)
112 debugger("SharedSolver deleted while still in use!");
119 SharedSolver::Solver() const
121 return const_cast<LinearSpec
*>(&fLinearSpec
);
126 SharedSolver::Invalidate(bool children
)
128 if (!fConstraintsValid
&& !fMaxValid
&& !fMinValid
&& !fLayoutValid
)
131 fConstraintsValid
= false;
134 fPreferredValid
= false;
135 fLayoutValid
= false;
139 for (int32 i
= fLayouts
.CountItems() - 1; i
>= 0; i
--)
140 fLayouts
.ItemAt(i
)->InvalidateLayout(children
);
145 SharedSolver::RegisterLayout(BALMLayout
* layout
)
147 fLayouts
.AddItem(layout
);
153 SharedSolver::LayoutLeaving(const BALMLayout
* layout
)
155 fLayouts
.RemoveItem(const_cast<BALMLayout
*>(layout
));
161 SharedSolver::ValidateMinSize()
163 _Validate
<MinSizeValidator
>(fMinValid
, fMinResult
);
169 SharedSolver::ValidateMaxSize()
171 _Validate
<MaxSizeValidator
>(fMaxValid
, fMaxResult
);
177 SharedSolver::ValidatePreferredSize()
179 _Validate
<PreferredSizeValidator
>(fPreferredValid
, fPreferredResult
);
180 return fPreferredResult
;
185 SharedSolver::ValidateLayout(BLayoutContext
* context
)
187 if (fLayoutValid
&& fLayoutContext
== context
)
188 return fLayoutResult
;
190 _SetContext(context
);
191 _ValidateConstraints();
193 for (int32 i
= fLayouts
.CountItems() - 1; i
>= 0; i
--) {
194 BALMLayout
* layout
= fLayouts
.ItemAt(i
);
195 BSize
size(layout
->LayoutArea().Size());
196 layout
->Right()->SetRange(size
.width
, size
.width
);
197 layout
->Bottom()->SetRange(size
.height
, size
.height
);
200 fLayoutResult
= fLinearSpec
.Solve();
202 return fLayoutResult
;
207 SharedSolver::Archive(BMessage
* archive
, bool deep
) const
209 return BArchivable::Archive(archive
, deep
);
214 SharedSolver::AllArchived(BMessage
* archive
) const
217 for each archived layout:
218 add it to our archive
219 add constraints created by areas and column manager to a set
220 add range constraints on the left/top/right/bottom tabs to the same set
221 for each constraint in the linear spec:
222 if it is not in the set above:
225 BArchiver
archiver(archive
);
226 std::set
<const Constraint
*> autoConstraints
;
227 for (int32 i
= fLayouts
.CountItems() - 1; i
>= 0; i
--) {
228 BALMLayout
* layout
= fLayouts
.ItemAt(i
);
229 if (!archiver
.IsArchived(layout
))
232 for (int32 j
= layout
->CountItems() - 1; j
>= 0; j
--)
233 _AddConstraintsToSet(layout
->AreaAt(j
), autoConstraints
);
235 for (int32 j
= layout
->fRowColumnManager
->fRows
.CountItems() - 1;
237 Row
* row
= layout
->fRowColumnManager
->fRows
.ItemAt(j
);
238 autoConstraints
.insert(row
->fPrefSizeConstraint
);
241 for (int32 j
= layout
->fRowColumnManager
->fColumns
.CountItems() - 1;
243 Column
* column
= layout
->fRowColumnManager
->fColumns
.ItemAt(j
);
244 autoConstraints
.insert(column
->fPrefSizeConstraint
);
247 Variable
* corners
[] = {layout
->fLeft
, layout
->fTop
, layout
->fRight
,
250 for (int32 j
= 0; j
< 4; j
++) {
251 const Constraint
* min
;
252 const Constraint
* max
;
253 fLinearSpec
.GetRangeConstraints(corners
[j
], &min
, &max
);
255 autoConstraints
.insert(min
);
257 autoConstraints
.insert(max
);
262 const ConstraintList
& constraints
= fLinearSpec
.Constraints();
263 for (int32 i
= constraints
.CountItems() - 1; i
>= 0 && err
== B_OK
; i
--) {
264 Constraint
* constraint
= constraints
.ItemAt(i
);
265 if (autoConstraints
.find(constraint
) == autoConstraints
.end())
266 err
= _AddConstraintToArchive(constraint
, archive
);
273 SharedSolver::AllUnarchived(const BMessage
* archive
)
276 archive
->GetInfo(kConstraintsField
, NULL
, &count
);
279 BUnarchiver
unarchiver(archive
);
280 for (int32 i
= 0; i
< count
&& err
== B_OK
; i
++) {
281 const void* constraintData
;
283 err
= archive
->FindData(kConstraintsField
, kConstraintsTypeCode
,
284 i
, &constraintData
, &numBytes
);
288 err
= _InstantiateConstraint(constraintData
, numBytes
, unarchiver
);
295 SharedSolver::_AddConstraintsToSet(Area
* area
,
296 std::set
<const Constraint
*>& constraints
)
298 if (area
->fMinContentWidth
)
299 constraints
.insert(area
->fMinContentWidth
);
300 if (area
->fMaxContentWidth
)
301 constraints
.insert(area
->fMaxContentWidth
);
302 if (area
->fMinContentHeight
)
303 constraints
.insert(area
->fMinContentHeight
);
304 if (area
->fMaxContentHeight
)
305 constraints
.insert(area
->fMaxContentHeight
);
306 if (area
->fContentAspectRatioC
)
307 constraints
.insert(area
->fContentAspectRatioC
);
312 SharedSolver::_AddConstraintToArchive(Constraint
* constraint
,
316 * int32: summandCount
318 * double: coefficient
326 // TODO: check Read/Write calls
327 BArchiver
archiver(archive
);
329 SummandList
* leftSide
= constraint
->LeftSide();
330 int32 summandCount
= leftSide
->CountItems();
331 buffer
.Write(&summandCount
, sizeof(summandCount
));
333 for (int32 i
= 0; i
< summandCount
; i
++) {
334 Summand
* summand
= leftSide
->ItemAt(i
);
335 Variable
* var
= summand
->Var();
336 BArchivable
* varArchivable
= dynamic_cast<BArchivable
*>(var
);
337 if (!varArchivable
|| !archiver
.IsArchived(varArchivable
))
338 return B_NAME_NOT_FOUND
;
341 archiver
.GetTokenForArchivable(varArchivable
, token
);
342 buffer
.Write(&token
, sizeof(token
));
344 double coefficient
= summand
->Coeff();
345 buffer
.Write(&coefficient
, sizeof(coefficient
));
348 int32 op
= constraint
->Op();
349 buffer
.Write(&op
, sizeof(op
));
351 double rightSide
= constraint
->RightSide();
352 buffer
.Write(&rightSide
, sizeof(rightSide
));
353 double penaltyNeg
= constraint
->PenaltyNeg();
354 buffer
.Write(&penaltyNeg
, sizeof(penaltyNeg
));
355 double penaltyPos
= constraint
->PenaltyPos();
356 buffer
.Write(&penaltyPos
, sizeof(penaltyPos
));
358 return archive
->AddData(kConstraintsField
, kConstraintsTypeCode
,
359 buffer
.Buffer(), buffer
.BufferLength(), false);
364 SharedSolver::_InstantiateConstraint(const void* rawData
, ssize_t numBytes
,
365 BUnarchiver
& unarchiver
)
368 * int32: summandCount
370 * double: coefficient
378 // TODO: check Read/Write calls
379 BMemoryIO
buffer(rawData
, numBytes
);
381 buffer
.Read((void*)&summandCount
, sizeof(summandCount
));
383 SummandList
* summandList
= new SummandList(20, true);
384 ObjectDeleter
<SummandList
> deleter(summandList
);
386 for (int32 i
= 0; i
< summandCount
; i
++) {
388 buffer
.Read((void*)&token
, sizeof(token
));
390 BArchivable
* varArchivable
;
391 err
= unarchiver
.GetObject(token
, varArchivable
);
394 Variable
* var
= dynamic_cast<Variable
*>(varArchivable
);
398 fLinearSpec
.AddVariable(var
);
401 buffer
.Read(&coefficient
, sizeof(coefficient
));
403 summandList
->AddItem(new Summand(coefficient
, var
));
407 buffer
.Read(&op
, sizeof(op
));
410 buffer
.Read(&rightSide
, sizeof(rightSide
));
412 buffer
.Read(&penaltyNeg
, sizeof(penaltyNeg
));
414 buffer
.Read(&penaltyPos
, sizeof(penaltyPos
));
419 if (fLinearSpec
.AddConstraint(summandList
, (OperatorType
)op
, rightSide
,
420 penaltyNeg
, penaltyPos
) != NULL
) {
430 SharedSolver::SetMaxSize(BALMLayout
* layout
, const BSize
& max
)
432 layout
->fMaxSize
= max
;
437 SharedSolver::SetMinSize(BALMLayout
* layout
, const BSize
& min
)
439 layout
->fMinSize
= min
;
444 SharedSolver::SetPreferredSize(BALMLayout
* layout
, const BSize
& preferred
)
446 layout
->fPreferredSize
= preferred
;
451 SharedSolver::LayoutContextLeft(BLayoutContext
* context
)
453 fLayoutContext
= NULL
;
458 SharedSolver::_SetContext(BLayoutContext
* context
)
461 fLayoutContext
->RemoveListener(this);
462 fLayoutContext
= context
;
464 fLayoutContext
->AddListener(this);
469 SharedSolver::_ValidateConstraints()
471 if (!fConstraintsValid
) {
472 for (int32 i
= fLayouts
.CountItems() - 1; i
>= 0; i
--) {
473 fLayouts
.ItemAt(i
)->UpdateConstraints(fLayoutContext
);
475 fConstraintsValid
= true;
480 template <class Validator
>
482 SharedSolver::_Validate(bool& isValid
, ResultType
& result
)
487 _ValidateConstraints();
489 VariableList
variables(fLayouts
.CountItems() * 2);
492 for (int32 i
= fLayouts
.CountItems() - 1; i
>= 0; i
--) {
493 BALMLayout
* layout
= fLayouts
.ItemAt(i
);
494 layout
->Right()->SetRange(0, 20000);
495 layout
->Bottom()->SetRange(0, 20000);
497 variables
.AddItem(layout
->Right());
498 variables
.AddItem(layout
->Bottom());
501 validator
.CallSolverMethod(&fLinearSpec
, &variables
);
502 result
= fLinearSpec
.Result();
504 for (int32 i
= fLayouts
.CountItems() - 1; i
>= 0; i
--)
505 validator
.Finalize(fLayouts
.ItemAt(i
), this, result
);
508 fLayoutValid
= false;
513 SharedSolver::Instantiate(BMessage
* archive
)
515 if (validate_instantiation(archive
, "BPrivate::SharedSolver"))
516 return new SharedSolver(archive
);