Introduce SharedSolver class to improve BALMLayout's friend feature.

This commit is contained in:
Alex Wilson 2012-01-23 13:12:26 +13:00
parent 708a298e22
commit 419fe0b8ae
9 changed files with 452 additions and 113 deletions

View File

@ -17,6 +17,10 @@
class BView;
class BLayoutItem;
namespace BPrivate {
class SharedSolver;
};
namespace BALM {
@ -157,6 +161,7 @@ private:
template <class T>
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<XTab> fLeft;
BReference<XTab> fRight;

View File

@ -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);

View File

@ -15,6 +15,7 @@
#include <ControlLook.h>
#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<XTab> 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<YTab> 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<LinearSpec*>(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)
{

View File

@ -14,6 +14,7 @@ SharedLibrary libalm.so :
Column.cpp
Row.cpp
RowColumnManager.cpp
SharedSolver.cpp
Tab.cpp
:
liblinprog.a be $(TARGET_LIBSTDC++)

View File

@ -0,0 +1,247 @@
/*
* Copyright 2012, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "SharedSolver.h"
#include <ALMLayout.h>
#include <ObjectList.h>
using LinearProgramming::LinearSpec;
struct LayoutOperation {
LayoutOperation(BObjectList<BALMLayout>* 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<BALMLayout>* fLayouts;
VariableList fVariables;
};
struct SharedSolver::MinSizeValidator : LayoutOperation {
MinSizeValidator(BObjectList<BALMLayout>* 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<BALMLayout>* 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<LinearSpec*>(&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;
}
}

View File

@ -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 <LayoutContext.h>
#include <ObjectList.h>
#include <Referenceable.h>
#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<BALM::BALMLayout> fLayouts;
LinearSpec fLinearSpec;
ResultType fMinResult;
ResultType fMaxResult;
ResultType fLayoutResult;
};
};
using BPrivate::SharedSolver;
#endif

View File

@ -15,7 +15,7 @@
#include "LayoutOptimizer.h"
//#define DEBUG_ACTIVE_SOLVER
// #define DEBUG_ACTIVE_SOLVER
#ifdef DEBUG_ACTIVE_SOLVER
#include <stdio.h>
@ -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)
{

View File

@ -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);

View File

@ -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)
{