diff --git a/headers/libs/alm/ALMLayout.h b/headers/libs/alm/ALMLayout.h index 91771561ad..5a52da2c68 100644 --- a/headers/libs/alm/ALMLayout.h +++ b/headers/libs/alm/ALMLayout.h @@ -17,6 +17,10 @@ class BView; class BLayoutItem; +namespace BPrivate { + class SharedSolver; +}; + namespace BALM { @@ -157,6 +161,7 @@ private: template friend class TabAddTransaction; + friend class BPrivate::SharedSolver; friend class XTab; friend class YTab; @@ -165,6 +170,8 @@ private: float InsetForTab(XTab* tab) const; float InsetForTab(YTab* tab) const; + void UpdateConstraints(BLayoutContext* context); + void _RemoveSelfFromTab(XTab* tab); void _RemoveSelfFromTab(YTab* tab); bool _HasTabInLayout(XTab* tab); @@ -174,15 +181,7 @@ private: BLayoutItem* _LayoutItemToAdd(BView* view); - void _UpdateAreaConstraints(); - - BSize _CalculateMinSize(); - BSize _CalculateMaxSize(); - BSize _CalculatePreferredSize(); - - bool _TrySolve(); - - LinearProgramming::LinearSpec* fSolver; + BPrivate::SharedSolver* fSolver; BReference fLeft; BReference fRight; diff --git a/headers/libs/linprog/LinearSpec.h b/headers/libs/linprog/LinearSpec.h index e6c15f85cb..b6e0fac067 100644 --- a/headers/libs/linprog/LinearSpec.h +++ b/headers/libs/linprog/LinearSpec.h @@ -55,6 +55,9 @@ public: virtual BSize MinSize(Variable* width, Variable* height) = 0; virtual BSize MaxSize(Variable* width, Variable* height) = 0; + virtual ResultType FindMins(const VariableList* variables) = 0; + virtual ResultType FindMaxs(const VariableList* variables) = 0; + protected: LinearSpec* fLinearSpec; }; @@ -122,6 +125,9 @@ public: BSize MinSize(Variable* width, Variable* height); BSize MaxSize(Variable* width, Variable* height); + ResultType FindMins(const VariableList* variables); + ResultType FindMaxs(const VariableList* variables); + ResultType Solve(); bool Save(const char* fileName); diff --git a/src/libs/alm/ALMLayout.cpp b/src/libs/alm/ALMLayout.cpp index df5a12cc6f..eb8988b9eb 100644 --- a/src/libs/alm/ALMLayout.cpp +++ b/src/libs/alm/ALMLayout.cpp @@ -15,6 +15,7 @@ #include #include "RowColumnManager.h" +#include "SharedSolver.h" #include "ViewLayoutItem.h" @@ -133,9 +134,10 @@ BALMLayout::BALMLayout(float hSpacing, float vSpacing, BALMLayout* friendLayout) fVSpacing(BControlLook::ComposeSpacing(vSpacing)), fBadLayoutPolicy(new DefaultPolicy()) { - fSolver = friendLayout ? friendLayout->Solver() : new LinearSpec(); + fSolver = friendLayout ? friendLayout->fSolver : new SharedSolver(); fSolver->AcquireReference(); - fRowColumnManager = new RowColumnManager(fSolver); + fSolver->RegisterLayout(this); + fRowColumnManager = new RowColumnManager(Solver()); fLeft = AddXTab(); fRight = AddXTab(); @@ -159,6 +161,8 @@ BALMLayout::~BALMLayout() { delete fRowColumnManager; delete fBadLayoutPolicy; + + fSolver->LayoutLeaving(this); fSolver->ReleaseReference(); } @@ -174,7 +178,7 @@ BALMLayout::AddXTab() BReference tab(new(std::nothrow) XTab(this), true); if (!tab) return NULL; - if (!fSolver->AddVariable(tab)) + if (!Solver()->AddVariable(tab)) return NULL; fXTabList.AddItem(tab); @@ -213,7 +217,7 @@ BALMLayout::AddYTab() BReference tab(new(std::nothrow) YTab(this), true); if (tab.Get() == NULL) return NULL; - if (!fSolver->AddVariable(tab)) + if (!Solver()->AddVariable(tab)) return NULL; fYTabList.AddItem(tab); @@ -307,7 +311,7 @@ BALMLayout::AddRow(YTab* _top, YTab* _bottom) top = AddYTab(); if (_bottom == NULL) bottom = AddYTab(); - return new(std::nothrow) Row(fSolver, top, bottom); + return new(std::nothrow) Row(Solver(), top, bottom); } @@ -327,7 +331,7 @@ BALMLayout::AddColumn(XTab* _left, XTab* _right) left = AddXTab(); if (_right == NULL) right = AddXTab(); - return new(std::nothrow) Column(fSolver, left, right); + return new(std::nothrow) Column(Solver(), left, right); } @@ -598,7 +602,7 @@ BALMLayout::AddItem(BLayoutItem* item, XTab* left, YTab* top, XTab* _right, return NULL; } - area->_Init(fSolver, left, top, right, bottom, fRowColumnManager); + area->_Init(Solver(), left, top, right, bottom, fRowColumnManager); fRowColumnManager->AddArea(area); leftTabAdd.Commit(); @@ -618,7 +622,7 @@ BALMLayout::AddItem(BLayoutItem* item, Row* row, Column* column) if (!area) return NULL; - area->_Init(fSolver, row, column, fRowColumnManager); + area->_Init(Solver(), row, column, fRowColumnManager); fRowColumnManager->AddArea(area); return area; @@ -817,8 +821,7 @@ BALMLayout::GetBadLayoutPolicy() const BSize BALMLayout::BaseMinSize() { - if (fMinSize == kUnsetSize) - fMinSize = _CalculateMinSize(); + fSolver->ValidateMinSize(); return fMinSize; } @@ -829,8 +832,7 @@ BALMLayout::BaseMinSize() BSize BALMLayout::BaseMaxSize() { - if (fMaxSize == kUnsetSize) - fMaxSize = _CalculateMaxSize(); + fSolver->ValidateMaxSize(); return fMaxSize; } @@ -841,9 +843,8 @@ BALMLayout::BaseMaxSize() BSize BALMLayout::BasePreferredSize() { - if (fPreferredSize == kUnsetSize) - fPreferredSize = _CalculatePreferredSize(); - return fPreferredSize; + fSolver->ValidateMinSize(); + return fMinSize; } @@ -870,6 +871,8 @@ BALMLayout::LayoutInvalidated(bool children) fMinSize = kUnsetSize; fMaxSize = kUnsetSize; fPreferredSize = kUnsetSize; + + fSolver->Invalidate(children); } @@ -899,26 +902,18 @@ BALMLayout::ItemRemoved(BLayoutItem* item, int32 fromIndex) void BALMLayout::DoLayout() { - _UpdateAreaConstraints(); - - // Enforced absolute positions of Right and Bottom - BRect area(LayoutArea()); - BSize size(area.Size()); - Right()->SetRange(size.width, size.width); - Bottom()->SetRange(size.height, size.height); - - _TrySolve(); + fSolver->ValidateLayout(LayoutContext()); // set the calculated positions and sizes for every area for (int32 i = 0; i < CountItems(); i++) - AreaFor(ItemAt(i))->_DoLayout(area.LeftTop()); + AreaFor(ItemAt(i))->_DoLayout(LayoutArea().LeftTop()); } LinearSpec* BALMLayout::Solver() const { - return const_cast(fSolver); + return fSolver->Solver(); } @@ -1015,6 +1010,21 @@ BALMLayout::InsetForTab(YTab* tab) const } +void +BALMLayout::UpdateConstraints(BLayoutContext* context) +{ + for (int i = 0; i < CountItems(); i++) + AreaFor(ItemAt(i))->InvalidateSizeConstraints(); + fRowColumnManager->UpdateConstraints(); + + if (context) { + BSize size(LayoutArea().Size()); + Right()->SetRange(size.width, size.width); + Bottom()->SetRange(size.height, size.height); + } +} + + void BALMLayout::_RemoveSelfFromTab(XTab* tab) { tab->LayoutLeaving(this); } void BALMLayout::_RemoveSelfFromTab(YTab* tab) { tab->LayoutLeaving(this); } @@ -1034,83 +1044,6 @@ BALMLayout::_LayoutItemToAdd(BView* view) } -/** - * Caculates the miminum size. - */ -BSize -BALMLayout::_CalculateMinSize() -{ - _UpdateAreaConstraints(); - - Right()->SetRange(0, 20000); - Bottom()->SetRange(0, 20000); - - BSize min(fSolver->MinSize(Right(), Bottom())); - ResultType result = fSolver->Result(); - if (result != kUnbounded && result != kOptimal) - fBadLayoutPolicy->OnBadLayout(this); - return min; -} - - -/** - * Caculates the maximum size. - */ -BSize -BALMLayout::_CalculateMaxSize() -{ - _UpdateAreaConstraints(); - - Right()->SetRange(0, 20000); - Bottom()->SetRange(0, 20000); - - BSize max(fSolver->MaxSize(Right(), Bottom())); - ResultType result = fSolver->Result(); - if (result != kUnbounded && result != kOptimal) - fBadLayoutPolicy->OnBadLayout(this); - return max; -} - - -/** - * Caculates the preferred size. - */ -BSize -BALMLayout::_CalculatePreferredSize() -{ - _UpdateAreaConstraints(); - - Right()->SetRange(0, 20000); - Bottom()->SetRange(0, 20000); - - _TrySolve(); - - return BSize(Right()->Value() - Left()->Value(), - Bottom()->Value() - Top()->Value()); -} - - -bool -BALMLayout::_TrySolve() -{ - fSolver->Solve(); - - if (fSolver->Result() != kOptimal) { - return fBadLayoutPolicy->OnBadLayout(this); - } - return true; -} - - -void -BALMLayout::_UpdateAreaConstraints() -{ - for (int i = 0; i < CountItems(); i++) - AreaFor(ItemAt(i))->InvalidateSizeConstraints(); - fRowColumnManager->UpdateConstraints(); -} - - status_t BALMLayout::Perform(perform_code d, void* arg) { diff --git a/src/libs/alm/Jamfile b/src/libs/alm/Jamfile index 8bab90053e..9ec1d339ab 100644 --- a/src/libs/alm/Jamfile +++ b/src/libs/alm/Jamfile @@ -14,6 +14,7 @@ SharedLibrary libalm.so : Column.cpp Row.cpp RowColumnManager.cpp + SharedSolver.cpp Tab.cpp : liblinprog.a be $(TARGET_LIBSTDC++) diff --git a/src/libs/alm/SharedSolver.cpp b/src/libs/alm/SharedSolver.cpp new file mode 100644 index 0000000000..62caa9390d --- /dev/null +++ b/src/libs/alm/SharedSolver.cpp @@ -0,0 +1,247 @@ +/* + * Copyright 2012, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "SharedSolver.h" + +#include +#include + + +using LinearProgramming::LinearSpec; + + +struct LayoutOperation { + LayoutOperation(BObjectList* layouts) + : + fLayouts(layouts), + fVariables(layouts->CountItems() * 2) + { + } + + virtual ~LayoutOperation() + { + } + + void Validate(SharedSolver* solver) + { + for (int32 i = fLayouts->CountItems() - 1; i >= 0; i--) { + BALMLayout* layout = fLayouts->ItemAt(i); + layout->Right()->SetRange(0, 20000); + layout->Bottom()->SetRange(0, 20000); + + fVariables.AddItem(layout->Right()); + fVariables.AddItem(layout->Bottom()); + } + + CallSolverMethod(solver->Solver(), &fVariables); + + for (int32 i = fLayouts->CountItems() - 1; i >= 0; i--) + Finalize(fLayouts->ItemAt(i), solver); + } + + virtual void CallSolverMethod(LinearSpec* spec, VariableList* vars) = 0; + virtual void Finalize(BALMLayout* layout, SharedSolver* solver) = 0; + +private: + BObjectList* fLayouts; + VariableList fVariables; +}; + + +struct SharedSolver::MinSizeValidator : LayoutOperation { + MinSizeValidator(BObjectList* layouts) + : + LayoutOperation(layouts) + { + } + + void CallSolverMethod(LinearSpec* spec, VariableList* vars) + { + spec->FindMins(vars); + } + + void Finalize(BALMLayout* layout, SharedSolver* solver) + { + solver->SetMinSize(layout, BSize(layout->Right()->Value(), + layout->Bottom()->Value())); + } +}; + + +struct SharedSolver::MaxSizeValidator : LayoutOperation { + MaxSizeValidator(BObjectList* layouts) + : + LayoutOperation(layouts) + { + } + + void CallSolverMethod(LinearSpec* spec, VariableList* vars) + { + spec->FindMaxs(vars); + } + + void Finalize(BALMLayout* layout, SharedSolver* solver) + { + solver->SetMaxSize(layout, BSize(layout->Right()->Value(), + layout->Bottom()->Value())); + } +}; + + +SharedSolver::SharedSolver() + : + fConstraintsValid(false), + fMinValid(false), + fMaxValid(false), + fLayoutValid(false), + fLayoutContext(NULL) +{ +} + + +SharedSolver::~SharedSolver() +{ + if (fLayouts.CountItems() > 0) + debugger("SharedSolver deleted while still in use!"); + + _SetContext(NULL); +} + + +LinearSpec* +SharedSolver::Solver() const +{ + return const_cast(&fLinearSpec); +} + + +void +SharedSolver::Invalidate(bool children) +{ + if (!fConstraintsValid && !fMaxValid && !fMinValid && !fLayoutValid) + return; + + fConstraintsValid = false; + fMinValid = false; + fMaxValid = false; + fLayoutValid = false; + + _SetContext(NULL); + + for (int32 i = fLayouts.CountItems() - 1; i >= 0; i--) + fLayouts.ItemAt(i)->InvalidateLayout(children); +} + + +void +SharedSolver::RegisterLayout(BALMLayout* layout) +{ + fLayouts.AddItem(layout); + Invalidate(false); +} + + +void +SharedSolver::LayoutLeaving(BALMLayout* layout) +{ + fLayouts.RemoveItem(layout); + Invalidate(false); +} + + +void +SharedSolver::ValidateMinSize() +{ + if (fMinValid) + return; + + _ValidateConstraints(); + + MinSizeValidator validator(&fLayouts); + validator.Validate(this); + + fMinResult = fLinearSpec.Result(); + + fMinValid = true; + fLayoutValid = false; +} + + +void +SharedSolver::ValidateMaxSize() +{ + if (fMaxValid) + return; + + _ValidateConstraints(); + + MaxSizeValidator validator(&fLayouts); + validator.Validate(this); + + fMaxResult = fLinearSpec.Result(); + + fMaxValid = true; + fLayoutValid = false; +} + + +void +SharedSolver::ValidateLayout(BLayoutContext* context) +{ + if (fLayoutValid && fLayoutContext == context) + return; + + fConstraintsValid = false; + _SetContext(context); + _ValidateConstraints(); + fLayoutResult = fLinearSpec.Solve(); + + fLayoutValid = true; +} + + +void +SharedSolver::SetMaxSize(BALMLayout* layout, const BSize& max) +{ + layout->fMaxSize = max; +} + + +void +SharedSolver::SetMinSize(BALMLayout* layout, const BSize& min) +{ + layout->fMinSize = min; +} + + +void +SharedSolver::LayoutContextLeft(BLayoutContext* context) +{ + _SetContext(NULL); +} + + +void +SharedSolver::_SetContext(BLayoutContext* context) +{ + if (fLayoutContext) + fLayoutContext->RemoveListener(this); + fLayoutContext = context; + if (fLayoutContext) + fLayoutContext->AddListener(this); +} + + +void +SharedSolver::_ValidateConstraints() +{ + if (!fConstraintsValid) { + for (int32 i = fLayouts.CountItems() - 1; i >= 0; i--) { + fLayouts.ItemAt(i)->UpdateConstraints(fLayoutContext); + } + fConstraintsValid = true; + } +} diff --git a/src/libs/alm/SharedSolver.h b/src/libs/alm/SharedSolver.h new file mode 100644 index 0000000000..d57576aa8f --- /dev/null +++ b/src/libs/alm/SharedSolver.h @@ -0,0 +1,82 @@ +/* + * Copyright 2012, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _SHARED_SOLVER_H +#define _SHARED_SOLVER_H + + +#include +#include +#include + +#include "LinearSpec.h" + + +namespace BALM { + class BALMLayout; +}; + + + +namespace BPrivate { + + +class SharedSolver : BLayoutContextListener, public BReferenceable { +public: + SharedSolver(); + ~SharedSolver(); + + void Invalidate(bool children); + + LinearSpec* Solver() const; + ResultType Result(); + + void RegisterLayout(BALM::BALMLayout* layout); + void LayoutLeaving(BALM::BALMLayout* layout); + + void ValidateMinSize(); + void ValidateMaxSize(); + void ValidateLayout(BLayoutContext* context); +private: + struct MinSizeValidator; + struct MaxSizeValidator; + + friend struct MinSizeValidator; + friend struct MaxSizeValidator; + + void SetMaxSize(BALM::BALMLayout* layout, + const BSize& max); + void SetMinSize(BALM::BALMLayout* layout, + const BSize& min); + + virtual void LayoutContextLeft(BLayoutContext* context); + + void _UpdateConstraints(); + void _SetContext(BLayoutContext* context); + bool _IsMinSet(); + bool _IsMaxSet(); + void _ValidateConstraints(); + + bool fConstraintsValid; + bool fMinValid; + bool fMaxValid; + bool fLayoutValid; + + BLayoutContext* fLayoutContext; + BObjectList fLayouts; + LinearSpec fLinearSpec; + + ResultType fMinResult; + ResultType fMaxResult; + ResultType fLayoutResult; +}; + + +}; + + +using BPrivate::SharedSolver; + + +#endif diff --git a/src/libs/linprog/ActiveSetSolver.cpp b/src/libs/linprog/ActiveSetSolver.cpp index efd739c3f8..250d0b075d 100644 --- a/src/libs/linprog/ActiveSetSolver.cpp +++ b/src/libs/linprog/ActiveSetSolver.cpp @@ -15,7 +15,7 @@ #include "LayoutOptimizer.h" -//#define DEBUG_ACTIVE_SOLVER +// #define DEBUG_ACTIVE_SOLVER #ifdef DEBUG_ACTIVE_SOLVER #include @@ -579,6 +579,59 @@ ActiveSetSolver::MaxSize(Variable* width, Variable* height) } +ResultType +ActiveSetSolver::FindMaxs(const VariableList* variables) +{ + ConstraintList softConstraints; + _RemoveSoftConstraint(softConstraints); + + const double kHugeValue = 32000; + ConstraintList maxConstraints; + for (int32 i = variables->CountItems() - 1; i >= 0; i--) { + maxConstraints.AddItem(fLinearSpec->AddConstraint(1, + variables->ItemAt(i), kEQ, kHugeValue, 5, 5)); + } + + ResultType result = Solve(); + + for (int32 i = maxConstraints.CountItems() - 1; i >= 0; i--) + fLinearSpec->RemoveConstraint(maxConstraints.ItemAt(i)); + + _AddSoftConstraint(softConstraints); + + if (result != kOptimal) + TRACE("Could not solve the layout specification (%d). ", result); + + return result; +} + + +ResultType +ActiveSetSolver::FindMins(const VariableList* variables) +{ + ConstraintList softConstraints; + _RemoveSoftConstraint(softConstraints); + + ConstraintList minConstraints; + for (int32 i = variables->CountItems() - 1; i >= 0; i--) { + minConstraints.AddItem(fLinearSpec->AddConstraint(1, + variables->ItemAt(i), kEQ, 0, 5, 5)); + } + + ResultType result = Solve(); + + for (int32 i = minConstraints.CountItems() - 1; i >= 0; i--) + fLinearSpec->RemoveConstraint(minConstraints.ItemAt(i)); + + _AddSoftConstraint(softConstraints); + + if (result != kOptimal) + TRACE("Could not solve the layout specification (%d). ", result); + + return result; +} + + void ActiveSetSolver::_RemoveSoftConstraint(ConstraintList& list) { diff --git a/src/libs/linprog/ActiveSetSolver.h b/src/libs/linprog/ActiveSetSolver.h index 2bd453af1b..4a5118666a 100644 --- a/src/libs/linprog/ActiveSetSolver.h +++ b/src/libs/linprog/ActiveSetSolver.h @@ -74,6 +74,9 @@ public: BSize MinSize(Variable* width, Variable* height); BSize MaxSize(Variable* width, Variable* height); + ResultType FindMaxs(const VariableList* variables); + ResultType FindMins(const VariableList* variables); + public: void _RemoveSoftConstraint(ConstraintList& list); void _AddSoftConstraint(const ConstraintList& list); diff --git a/src/libs/linprog/LinearSpec.cpp b/src/libs/linprog/LinearSpec.cpp index 6361880573..09b4d71d4d 100644 --- a/src/libs/linprog/LinearSpec.cpp +++ b/src/libs/linprog/LinearSpec.cpp @@ -496,6 +496,21 @@ LinearSpec::MaxSize(Variable* width, Variable* height) } + +ResultType +LinearSpec::FindMins(const VariableList* variables) +{ + return fSolver->FindMins(variables); +} + + +ResultType +LinearSpec::FindMaxs(const VariableList* variables) +{ + return fSolver->FindMaxs(variables); +} + + bool LinearSpec::_CheckSummandList(SummandList* list) {