playing with constraint based layouting

This commit is contained in:
Uwe Rathmann 2019-08-30 13:13:32 +02:00
parent bebdd80c9e
commit 35b98e4b69
14 changed files with 2478 additions and 0 deletions

View File

@ -0,0 +1,256 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "AnchorBox.h"
#include "Solver.h"
#include "Constraint.h"
#include "Variable.h"
#include "Expression.h"
#include <QskLayoutConstraint.h>
#include <QskEvent.h>
#include <QskQuick.h>
#include <vector>
static inline Qt::Orientation qskOrientation( int edge )
{
return ( edge <= Qt::AnchorRight ) ? Qt::Horizontal : Qt::Vertical;
}
namespace
{
class Geometry
{
public:
Expression expressionAt( int anchorPoint )
{
switch( anchorPoint )
{
case Qt::AnchorLeft:
return Term( left );
case Qt::AnchorHorizontalCenter:
return centerH();
case Qt::AnchorRight:
return Term( right );
case Qt::AnchorTop:
return Term( top );
case Qt::AnchorVerticalCenter:
return centerV();
case Qt::AnchorBottom:
return Term( bottom );
}
return Expression();
}
Expression length( Qt::Orientation orientation )
{
return ( orientation == Qt::Horizontal ) ? width() : height();
}
QRectF rect() const
{
return QRectF( left.value(), top.value(),
right.value() - left.value(), bottom.value() - top.value() );
}
Expression width() const { return right - left; }
Expression height() const { return bottom - top; }
Expression centerH() const { return left + 0.5 * width(); }
Expression centerV() const { return top + 0.5 * height(); }
Variable left, right, top, bottom;
};
class Anchor
{
public:
QQuickItem* item1 = nullptr;
Qt::AnchorPoint edge1;
QQuickItem* item2 = nullptr;
Qt::AnchorPoint edge2;
};
}
class AnchorBox::PrivateData
{
public:
void setupSolver( int type, Solver& );
QMap< QQuickItem*, Geometry > geometries;
QVector< Anchor > anchors;
};
void AnchorBox::PrivateData::setupSolver( int type, Solver& solver )
{
for ( const auto& anchor : anchors )
{
auto& r1 = geometries[ anchor.item1 ];
auto& r2 = geometries[ anchor.item2 ];
solver.addConstraint( r1.expressionAt( anchor.edge1 )
== r2.expressionAt( anchor.edge2 ) );
#if 1
if ( type < 0 )
{
const auto s1 = 1.0;
const auto s2 = 1.0;
const auto o = qskOrientation( anchor.edge1 );
Constraint c( r1.length( o ) * s1 == r2.length( o ) * s2, Strength::medium );
solver.addConstraint( c );
}
#endif
}
for ( auto it = geometries.begin(); it != geometries.end(); ++it )
{
const auto item = it.key();
auto& r = it.value();
if ( type < 0 || type == Qt::MinimumSize )
{
const auto minSize = QskLayoutConstraint::sizeHint( item, Qt::MinimumSize );
solver.addConstraint( r.right >= r.left + minSize.width() );
solver.addConstraint( r.bottom >= r.top + minSize.height() );
}
if ( type < 0 || type == Qt::PreferredSize )
{
const auto prefSize = QskLayoutConstraint::sizeHint( item, Qt::PreferredSize );
Constraint c1( r.right == r.left + prefSize.width(), Strength::strong );
solver.addConstraint( c1 );
Constraint c2( r.bottom == r.top + prefSize.height(), Strength::strong );
solver.addConstraint( c2 );
}
if ( type < 0 || type == Qt::MaximumSize )
{
const auto maxSize = QskLayoutConstraint::sizeHint( item, Qt::MaximumSize );
if ( maxSize.width() < QskLayoutConstraint::unlimited )
solver.addConstraint( r.right <= r.left + maxSize.width() );
if ( maxSize.height() < QskLayoutConstraint::unlimited )
solver.addConstraint( r.bottom <= r.top + maxSize.height() );
}
}
}
AnchorBox::AnchorBox( QQuickItem* parent )
: QskControl( parent )
, m_data( new PrivateData )
{
(void)m_data->geometries[ this ];
}
AnchorBox::~AnchorBox()
{
}
void AnchorBox::addAnchor( QQuickItem* item,
Qt::AnchorPoint edge1, Qt::AnchorPoint edge2 )
{
addAnchor( item, edge1, this, edge2 );
}
void AnchorBox::addAnchor( QQuickItem* item1, Qt::AnchorPoint edge1,
QQuickItem* item2, Qt::AnchorPoint edge2 )
{
if ( item1 == item2 || item1 == nullptr || item2 == nullptr )
return;
if ( item1 != this )
{
if ( item1->parent() == nullptr )
item1->setParent( this );
if ( item1->parentItem() != this )
item1->setParentItem( this );
}
if ( item2 != this )
{
if ( item2->parent() == nullptr )
item2->setParent( this );
if ( item2->parentItem() != this )
item2->setParentItem( this );
}
(void)m_data->geometries[ item1 ];
(void)m_data->geometries[ item2 ];
Anchor anchor;
anchor.item1 = item1;
anchor.edge1 = edge1;
anchor.item2 = item2;
anchor.edge2 = edge2;
m_data->anchors += anchor;
}
QSizeF AnchorBox::boxHint( Qt::SizeHint which )
{
Solver solver;
m_data->setupSolver( which, solver );
solver.updateVariables();
auto& r0 = m_data->geometries[ this ];
return QSizeF( r0.rect().size() );
}
void AnchorBox::setItemGeometries( const QRectF& rect )
{
Solver solver;
m_data->setupSolver( -1, solver );
auto& r0 = m_data->geometries[ this ];
solver.addConstraint( r0.left == rect.left() );
solver.addConstraint( r0.right == rect.right() );
solver.addConstraint( r0.top == rect.top() );
solver.addConstraint( r0.bottom == rect.bottom() );
solver.updateVariables();
const auto& geometries = m_data->geometries;
for ( auto it = geometries.begin(); it != geometries.end(); ++it )
qskSetItemGeometry( it.key(), it.value().rect() );
#if 0
qDebug() << "=== Rect:" << rect;
for ( auto it = geometries.begin(); it != geometries.end(); ++it )
qDebug() << it.key()->objectName() << it.value().rect();
#endif
}
void AnchorBox::geometryChangeEvent( QskGeometryChangeEvent* event )
{
Inherited::geometryChangeEvent( event );
if ( event->isResized() )
polish();
}
void AnchorBox::updateLayout()
{
if ( !maybeUnresized() )
setItemGeometries( layoutRect() );
}
#include "moc_AnchorBox.cpp"

View File

@ -0,0 +1,38 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#ifndef ANCHOR_BOX_H
#define ANCHOR_BOX_H
#include "QskControl.h"
class AnchorBox : public QskControl
{
Q_OBJECT
using Inherited = QskControl;
public:
AnchorBox( QQuickItem* parent = nullptr );
~AnchorBox() override;
void addAnchor( QQuickItem*, Qt::AnchorPoint, Qt::AnchorPoint );
void addAnchor( QQuickItem*, Qt::AnchorPoint, QQuickItem*, Qt::AnchorPoint );
QSizeF boxHint( Qt::SizeHint );
protected:
void geometryChangeEvent( QskGeometryChangeEvent* ) override;
void updateLayout() override;
private:
void setItemGeometries( const QRectF& );
class PrivateData;
std::unique_ptr< PrivateData > m_data;
};
#endif

View File

@ -0,0 +1,285 @@
#include "Constraint.h"
#include "Expression.h"
#include <map>
static Expression reduce( const Expression& expr )
{
std::map< Variable, double > vars;
for ( auto term : expr.terms() )
vars[ term.variable() ] += term.coefficient();
const std::vector< Term > terms( vars.begin(), vars.end() );
return Expression( terms, expr.constant() );
}
class Constraint::Data
{
public:
Data( const Expression& expr, RelationalOperator op, double strength )
: expression( reduce( expr ) )
, strength( Strength::clip( strength ) )
, op( op )
{
}
Expression expression;
double strength;
RelationalOperator op;
};
Constraint::Constraint( const Expression& expr, RelationalOperator op, double strength )
: m_data( std::make_shared< Data >( expr, op, strength ) )
{
}
Constraint::Constraint( const Constraint& other, double strength )
: Constraint( other.expression(), other.oper(), strength )
{
}
Constraint::~Constraint()
{
}
const Expression& Constraint::expression() const
{
return m_data->expression;
}
RelationalOperator Constraint::oper() const
{
return m_data->op;
}
double Constraint::strength() const
{
return m_data->strength;
}
Constraint operator==( const Expression& first, const Expression& second )
{
return Constraint( first - second, OP_EQ );
}
Constraint operator==( const Expression& expression, const Term& term )
{
return expression == Expression( term );
}
Constraint operator==( const Expression& expression, const Variable& variable )
{
return expression == Term( variable );
}
Constraint operator==( const Expression& expression, double constant )
{
return expression == Expression( constant );
}
Constraint operator<=( const Expression& first, const Expression& second )
{
return Constraint( first - second, OP_LE );
}
Constraint operator<=( const Expression& expression, const Term& term )
{
return expression <= Expression( term );
}
Constraint operator<=( const Expression& expression, const Variable& variable )
{
return expression <= Term( variable );
}
Constraint operator<=( const Expression& expression, double constant )
{
return expression <= Expression( constant );
}
Constraint operator>=( const Expression& first, const Expression& second )
{
return Constraint( first - second, OP_GE );
}
Constraint operator>=( const Expression& expression, const Term& term )
{
return expression >= Expression( term );
}
Constraint operator>=( const Expression& expression, const Variable& variable )
{
return expression >= Term( variable );
}
Constraint operator>=( const Expression& expression, double constant )
{
return expression >= Expression( constant );
}
Constraint operator==( const Term& term, const Expression& expression )
{
return expression == term;
}
Constraint operator==( const Term& first, const Term& second )
{
return Expression( first ) == second;
}
Constraint operator==( const Term& term, const Variable& variable )
{
return Expression( term ) == variable;
}
Constraint operator==( const Term& term, double constant )
{
return Expression( term ) == constant;
}
Constraint operator<=( const Term& term, const Expression& expression )
{
return expression >= term;
}
Constraint operator<=( const Term& first, const Term& second )
{
return Expression( first ) <= second;
}
Constraint operator<=( const Term& term, const Variable& variable )
{
return Expression( term ) <= variable;
}
Constraint operator<=( const Term& term, double constant )
{
return Expression( term ) <= constant;
}
Constraint operator>=( const Term& term, const Expression& expression )
{
return expression <= term;
}
Constraint operator>=( const Term& first, const Term& second )
{
return Expression( first ) >= second;
}
Constraint operator>=( const Term& term, const Variable& variable )
{
return Expression( term ) >= variable;
}
Constraint operator>=( const Term& term, double constant )
{
return Expression( term ) >= constant;
}
Constraint operator==( const Variable& variable, const Expression& expression )
{
return expression == variable;
}
Constraint operator==( const Variable& variable, const Term& term )
{
return term == variable;
}
Constraint operator==( const Variable& first, const Variable& second )
{
return Term( first ) == second;
}
Constraint operator==( const Variable& variable, double constant )
{
return Term( variable ) == constant;
}
Constraint operator<=( const Variable& variable, const Expression& expression )
{
return expression >= variable;
}
Constraint operator<=( const Variable& variable, const Term& term )
{
return term >= variable;
}
Constraint operator<=( const Variable& first, const Variable& second )
{
return Term( first ) <= second;
}
Constraint operator<=( const Variable& variable, double constant )
{
return Term( variable ) <= constant;
}
Constraint operator>=( const Variable& variable, const Expression& expression )
{
return expression <= variable;
}
Constraint operator>=( const Variable& variable, const Term& term )
{
return term <= variable;
}
Constraint operator>=( const Variable& first, const Variable& second )
{
return Term( first ) >= second;
}
Constraint operator>=( const Variable& variable, double constant )
{
return Term( variable ) >= constant;
}
Constraint operator==( double constant, const Expression& expression )
{
return expression == constant;
}
Constraint operator==( double constant, const Term& term )
{
return term == constant;
}
Constraint operator==( double constant, const Variable& variable )
{
return variable == constant;
}
Constraint operator<=( double constant, const Expression& expression )
{
return expression >= constant;
}
Constraint operator<=( double constant, const Term& term )
{
return term >= constant;
}
Constraint operator<=( double constant, const Variable& variable )
{
return variable >= constant;
}
Constraint operator>=( double constant, const Expression& expression )
{
return expression <= constant;
}
Constraint operator>=( double constant, const Term& term )
{
return term <= constant;
}
Constraint operator>=( double constant, const Variable& variable )
{
return variable <= constant;
}

View File

@ -0,0 +1,117 @@
#pragma once
#include "Strength.h"
#include <memory>
class Expression;
class Variable;
class Term;
enum RelationalOperator { OP_LE, OP_GE, OP_EQ };
class Constraint
{
public:
Constraint() = default;
Constraint( const Expression&, RelationalOperator,
double strength = Strength::required );
Constraint( const Constraint&, double strength );
~Constraint();
const Expression& expression() const;
RelationalOperator oper() const;
double strength() const;
bool operator!() const { return !m_data; }
private:
class Data;
std::shared_ptr< Data > m_data;
friend bool operator<( const Constraint&, const Constraint& );
friend bool operator==( const Constraint&, const Constraint& );
friend bool operator!=( const Constraint&, const Constraint& );
};
inline bool operator<( const Constraint& lhs, const Constraint& rhs )
{
return lhs.m_data < rhs.m_data;
}
inline bool operator==( const Constraint& lhs, const Constraint& rhs )
{
return lhs.m_data == rhs.m_data;
}
inline bool operator!=( const Constraint& lhs, const Constraint& rhs )
{
return lhs.m_data != rhs.m_data;
}
inline Constraint operator|( const Constraint& constraint, double strength )
{
return Constraint( constraint, strength );
}
inline Constraint operator|( double strength, const Constraint& constraint )
{
return constraint | strength;
}
extern Constraint operator==( const Expression&, const Expression& );
extern Constraint operator<=( const Expression&, const Expression& );
extern Constraint operator>=( const Expression&, const Expression& );
extern Constraint operator==( const Expression&, const Term& );
extern Constraint operator<=( const Expression&, const Term& );
extern Constraint operator>=( const Expression&, const Term& );
extern Constraint operator==( const Term&, const Expression& );
extern Constraint operator<=( const Term&, const Expression& );
extern Constraint operator>=( const Term&, const Expression& );
extern Constraint operator==( const Expression&, const Variable& );
extern Constraint operator<=( const Expression&, const Variable& );
extern Constraint operator>=( const Expression&, const Variable& );
extern Constraint operator==( const Variable&, const Expression& );
extern Constraint operator<=( const Variable&, const Expression& );
extern Constraint operator>=( const Variable&, const Expression& );
extern Constraint operator==( const Expression&, double );
extern Constraint operator<=( const Expression&, double );
extern Constraint operator>=( const Expression&, double );
extern Constraint operator==( double, const Expression& );
extern Constraint operator<=( double, const Expression& );
extern Constraint operator>=( double, const Expression& );
extern Constraint operator==( const Term&, const Term& );
extern Constraint operator<=( const Term&, const Term& );
extern Constraint operator>=( const Term&, const Term& );
extern Constraint operator==( const Term&, const Variable& );
extern Constraint operator<=( const Term&, const Variable& );
extern Constraint operator>=( const Term&, const Variable& );
extern Constraint operator==( const Variable&, const Term& );
extern Constraint operator<=( const Variable&, const Term& );
extern Constraint operator>=( const Variable&, const Term& );
extern Constraint operator==( const Term&, double );
extern Constraint operator<=( const Term&, double );
extern Constraint operator>=( const Term&, double );
extern Constraint operator==( double, const Term& );
extern Constraint operator<=( double, const Term& );
extern Constraint operator>=( double, const Term& );
extern Constraint operator==( const Variable&, const Variable& );
extern Constraint operator<=( const Variable&, const Variable& );
extern Constraint operator>=( const Variable&, const Variable& );
extern Constraint operator==( const Variable&, double );
extern Constraint operator<=( const Variable&, double );
extern Constraint operator>=( const Variable&, double );
extern Constraint operator==( double, const Variable& );
extern Constraint operator<=( double, const Variable& );
extern Constraint operator>=( double, const Variable& );

View File

@ -0,0 +1,226 @@
#include "Expression.h"
#include "Term.h"
Expression::Expression( double constant )
: m_constant( constant )
{
}
Expression::Expression( const Term& term, double constant )
: m_terms( 1, term )
, m_constant( constant )
{
}
Expression::Expression( const std::vector< Term >&& terms, double constant )
: m_terms( std::move( terms ) )
, m_constant( constant )
{
}
Expression::Expression( const std::vector< Term >& terms, double constant )
: m_terms( terms )
, m_constant( constant )
{
}
double Expression::value() const
{
double result = m_constant;
for ( const auto& term : m_terms )
result += term.value();
return result;
}
Expression operator*( const Expression& expression, double coefficient )
{
std::vector< Term > terms;
terms.reserve( expression.terms().size() );
for ( const auto& term : expression.terms() )
terms.push_back( term * coefficient );
return Expression( std::move( terms ), expression.constant() * coefficient );
}
Expression operator/( const Expression& expression, double denominator )
{
return expression * ( 1.0 / denominator );
}
Expression operator-( const Expression& expression )
{
return expression * -1.0;
}
Expression operator*( double coefficient, const Expression& expression )
{
return expression * coefficient;
}
Expression operator+( const Expression& first, const Expression& second )
{
std::vector< Term > terms;
terms.reserve( first.terms().size() + second.terms().size() );
terms.insert( terms.begin(), first.terms().begin(), first.terms().end() );
terms.insert( terms.end(), second.terms().begin(), second.terms().end() );
return Expression( std::move( terms ), first.constant() + second.constant() );
}
Expression operator+( const Expression& expression, const Term& term )
{
std::vector< Term > terms;
terms.reserve( expression.terms().size() + 1 );
terms.insert( terms.begin(), expression.terms().begin(), expression.terms().end() );
terms.push_back( term );
return Expression( std::move( terms ), expression.constant() );
}
Expression operator+( const Expression& expression, const Variable& variable )
{
return expression + Term( variable );
}
Expression operator+( const Expression& expression, double constant )
{
return Expression( expression.terms(), expression.constant() + constant );
}
Expression operator-( const Expression& first, const Expression& second )
{
return first + -second;
}
Expression operator-( const Expression& expression, const Term& term )
{
return expression + -term;
}
Expression operator-( const Expression& expression, const Variable& variable )
{
return expression + -variable;
}
Expression operator-( const Expression& expression, double constant )
{
return expression + -constant;
}
Expression operator+( const Term& term, const Expression& expression )
{
return expression + term;
}
Expression operator+( const Term& first, const Term& second )
{
std::vector< Term > terms;
terms.reserve( 2 );
terms.push_back( first );
terms.push_back( second );
return Expression( std::move( terms ) );
}
Expression operator+( const Term& term, const Variable& variable )
{
return term + Term( variable );
}
Expression operator+( const Term& term, double constant )
{
return Expression( term, constant );
}
Expression operator-( const Term& term, const Expression& expression )
{
return -expression + term;
}
Expression operator-( const Term& first, const Term& second )
{
return first + -second;
}
Expression operator-( const Term& term, const Variable& variable )
{
return term + -variable;
}
Expression operator-( const Term& term, double constant )
{
return term + -constant;
}
Expression operator+( const Variable& variable, const Expression& expression )
{
return expression + variable;
}
Expression operator+( const Variable& variable, const Term& term )
{
return term + variable;
}
Expression operator+( const Variable& first, const Variable& second )
{
return Term( first ) + second;
}
Expression operator+( const Variable& variable, double constant )
{
return Term( variable ) + constant;
}
Expression operator-( const Variable& variable, const Expression& expression )
{
return variable + -expression;
}
Expression operator-( const Variable& variable, const Term& term )
{
return variable + -term;
}
Expression operator-( const Variable& first, const Variable& second )
{
return first + -second;
}
Expression operator-( const Variable& variable, double constant )
{
return variable + -constant;
}
Expression operator+( double constant, const Expression& expression )
{
return expression + constant;
}
Expression operator+( double constant, const Term& term )
{
return term + constant;
}
Expression operator+( double constant, const Variable& variable )
{
return variable + constant;
}
Expression operator-( double constant, const Expression& expression )
{
return -expression + constant;
}
Expression operator-( double constant, const Term& term )
{
return -term + constant;
}
Expression operator-( double constant, const Variable& variable )
{
return -variable + constant;
}

View File

@ -0,0 +1,68 @@
#pragma once
#include <vector>
#include "Term.h"
class Expression
{
public:
Expression( double constant = 0.0 );
Expression( const Term&, double constant = 0.0 );
Expression( const std::vector< Term >&, double constant = 0.0 );
Expression( const std::vector< Term >&&, double constant = 0.0 );
const std::vector< Term >& terms() const { return m_terms; }
double constant() const { return m_constant; }
double value() const;
private:
std::vector< Term > m_terms;
double m_constant;
};
extern Expression operator-( const Expression& );
extern Expression operator+( const Expression&, const Expression& );
extern Expression operator-( const Expression&, const Expression& );
extern Expression operator+( const Expression&, const Term& );
extern Expression operator-( const Expression&, const Term& );
extern Expression operator+( const Term&, const Expression&);
extern Expression operator-( const Term&, const Expression&);
extern Expression operator+( const Expression&, const Variable& );
extern Expression operator-( const Expression&, const Variable& );
extern Expression operator-( const Variable&, const Expression&);
extern Expression operator+( const Variable&, const Expression&);
extern Expression operator*( const Expression&, double );
extern Expression operator/( const Expression&, double );
extern Expression operator+( const Expression&, double );
extern Expression operator-( const Expression&, double );
extern Expression operator*( double, const Expression&);
extern Expression operator+( double, const Expression&);
extern Expression operator-( double, const Expression&);
extern Expression operator+( const Term&, const Term& );
extern Expression operator-( const Term&, const Term& );
extern Expression operator+( const Term&, const Variable& );
extern Expression operator-( const Term&, const Variable& );
extern Expression operator-( const Variable&, const Term&);
extern Expression operator+( const Variable&, const Term&);
extern Expression operator+( const Term&, double );
extern Expression operator-( const Term&, double );
extern Expression operator+( double, const Term&);
extern Expression operator-( double, const Term&);
extern Expression operator+( const Variable&, const Variable& );
extern Expression operator-( const Variable&, const Variable& );
extern Expression operator+( const Variable&, double );
extern Expression operator-( const Variable&, double );
extern Expression operator+( double, const Variable& );
extern Expression operator-( double, const Variable& );

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
#pragma once
#include <qglobal.h>
#include <memory>
class Variable;
class Constraint;
class SimplexSolver;
class Solver
{
public:
Solver();
~Solver();
void addConstraint( const Constraint& );
void removeConstraint( const Constraint& );
bool hasConstraint( const Constraint& ) const;
void addEditVariable( const Variable&, double strength );
void removeEditVariable( const Variable& );
bool hasEditVariable( const Variable& ) const;
void suggestValue( const Variable&, double value );
void updateVariables();
void reset();
private:
Q_DISABLE_COPY( Solver )
std::unique_ptr< SimplexSolver > m_solver;
};

View File

@ -0,0 +1,26 @@
#pragma once
#include <algorithm>
namespace Strength
{
inline double create( double a, double b, double c, double w = 1.0 )
{
double result = 0.0;
result += std::max( 0.0, std::min( 1000.0, a * w ) ) * 1000000.0;
result += std::max( 0.0, std::min( 1000.0, b * w ) ) * 1000.0;
result += std::max( 0.0, std::min( 1000.0, c * w ) );
return result;
}
const double required = create( 1000.0, 1000.0, 1000.0 );
const double strong = create( 1.0, 0.0, 0.0 );
const double medium = create( 0.0, 1.0, 0.0 );
const double weak = create( 0.0, 0.0, 1.0 );
inline double clip( double value )
{
return std::max( 0.0, std::min( required, value ) );
}
}

81
playground/anchors/Term.h Normal file
View File

@ -0,0 +1,81 @@
#pragma once
#include <utility>
#include "Variable.h"
class Term
{
public:
Term( const Variable& variable, double coefficient = 1.0 )
: m_variable( variable )
, m_coefficient( coefficient )
{
}
// to facilitate efficient map -> vector copies
Term( const std::pair< const Variable, double >& pair )
: m_variable( pair.first )
, m_coefficient( pair.second )
{
}
const Variable& variable() const
{
return m_variable;
}
double coefficient() const
{
return m_coefficient;
}
double value() const
{
return m_coefficient * m_variable.value();
}
private:
Variable m_variable;
double m_coefficient;
};
inline Term operator*( const Variable& variable, double coefficient )
{
return Term( variable, coefficient );
}
inline Term operator/( const Variable& variable, double denominator )
{
return variable * ( 1.0 / denominator );
}
inline Term operator-( const Variable& variable )
{
return variable * -1.0;
}
inline Term operator*( const Term& term, double coefficient )
{
return Term( term.variable(), term.coefficient() * coefficient );
}
inline Term operator/( const Term& term, double denominator )
{
return term * ( 1.0 / denominator );
}
inline Term operator-( const Term& term )
{
return term * -1.0;
}
inline Term operator*( double coefficient, const Term& term )
{
return term * coefficient;
}
inline Term operator*( double coefficient, const Variable& variable )
{
return variable * coefficient;
}

View File

@ -0,0 +1,46 @@
#pragma once
#include <memory>
class Variable
{
public:
Variable( double value = 0.0 )
: m_value( std::make_shared< double >(value) )
{
}
Variable( const Variable& v )
: m_value( v.m_value )
{
}
Variable& operator=( const Variable& v )
{
m_value = v.m_value;
return *this;
}
double value() const
{
return m_value ? *m_value : 0.0;
}
void setValue(double x)
{
*m_value = x;
}
bool equals( const Variable& other )
{
return m_value == other.m_value;
}
private:
std::shared_ptr< double > m_value;
friend bool operator<( const Variable& lhs, const Variable& rhs )
{
return lhs.m_value < rhs.m_value;
}
};

View File

@ -0,0 +1,21 @@
CONFIG += qskexample
HEADERS += \
Constraint.h \
Expression.h \
Solver.h \
Strength.h \
Term.h \
Variable.h
SOURCES += \
Expression.cpp \
Constraint.cpp \
Solver.cpp
HEADERS += \
AnchorBox.h
SOURCES += \
AnchorBox.cpp \
main.cpp

190
playground/anchors/main.cpp Normal file
View File

@ -0,0 +1,190 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "AnchorBox.h"
#include <SkinnyFont.h>
#include <SkinnyShortcut.h>
#include <QskControl.h>
#include <QskObjectCounter.h>
#include <QskWindow.h>
#include <QGuiApplication>
#include <QDebug>
class Rectangle : public QskControl
{
public:
Rectangle( const char* colorName, QQuickItem* parent = nullptr )
: QskControl( parent)
, m_colorName( colorName )
{
setObjectName( colorName );
initSizePolicy( QskSizePolicy::Preferred, QskSizePolicy::Preferred );
setMinimumSize( 10, 10 );
setPreferredSize( 100, 100 );
setMaximumSize( 1000, 1000 );
setBackgroundColor( colorName );
}
protected:
void geometryChangeEvent( QskGeometryChangeEvent* event ) override
{
QskControl::geometryChangeEvent( event );
#if 0
qDebug() << m_colorName << size();
#endif
}
private:
QByteArray m_colorName;
};
class MyBox : public AnchorBox
{
public:
MyBox( QQuickItem* parent = nullptr )
: AnchorBox( parent )
{
setObjectName( "Box" );
setup1();
}
void setup1();
void setup2();
void setup3();
protected:
virtual void geometryChangeEvent( QskGeometryChangeEvent* event ) override
{
AnchorBox::geometryChangeEvent( event );
#if 1
qDebug() << boxHint( Qt::MinimumSize );
qDebug() << boxHint( Qt::PreferredSize );
qDebug() << boxHint( Qt::MaximumSize );
#endif
}
};
void MyBox::setup1()
{
auto a = new Rectangle( "PaleVioletRed" );
auto b = new Rectangle( "DarkSeaGreen" );
auto c = new Rectangle( "SkyBlue" );
auto d = new Rectangle( "Coral" );
auto e = new Rectangle( "NavajoWhite" );
auto f = new Rectangle( "Peru" );
auto g = new Rectangle( "Olive" );
addAnchor( a, Qt::AnchorTop, Qt::AnchorTop );
addAnchor( b, Qt::AnchorTop, Qt::AnchorTop );
addAnchor( c, Qt::AnchorTop, a, Qt::AnchorBottom );
addAnchor( c, Qt::AnchorTop, b, Qt::AnchorBottom );
addAnchor( c, Qt::AnchorBottom, d, Qt::AnchorTop );
addAnchor( c, Qt::AnchorBottom, e, Qt::AnchorTop );
addAnchor( d, Qt::AnchorBottom, Qt::AnchorBottom );
addAnchor( e, Qt::AnchorBottom, Qt::AnchorBottom );
addAnchor( c, Qt::AnchorTop, f, Qt::AnchorTop );
addAnchor( c, Qt::AnchorVerticalCenter, f, Qt::AnchorBottom );
addAnchor( f, Qt::AnchorBottom, g, Qt::AnchorTop );
addAnchor( c, Qt::AnchorBottom, g, Qt::AnchorBottom );
// horizontal
addAnchor( a, Qt::AnchorLeft, Qt::AnchorLeft );
addAnchor( d, Qt::AnchorLeft, Qt::AnchorLeft );
addAnchor( a, Qt::AnchorRight, b, Qt::AnchorLeft );
addAnchor( a, Qt::AnchorRight, c, Qt::AnchorLeft );
addAnchor( c, Qt::AnchorRight, e, Qt::AnchorLeft );
addAnchor( b, Qt::AnchorRight, Qt::AnchorRight );
addAnchor( e, Qt::AnchorRight, Qt::AnchorRight );
addAnchor( d, Qt::AnchorRight, e, Qt::AnchorLeft );
addAnchor( f, Qt::AnchorLeft, Qt::AnchorLeft );
addAnchor( g, Qt::AnchorLeft, Qt::AnchorLeft );
addAnchor( f, Qt::AnchorRight, g, Qt::AnchorRight );
}
void MyBox::setup2()
{
auto a = new Rectangle( "PaleVioletRed" );
addAnchor( a, Qt::AnchorLeft, Qt::AnchorLeft );
addAnchor( a, Qt::AnchorTop, Qt::AnchorTop );
#if 0
auto b = new Rectangle( "DarkSeaGreen" );
addAnchor( a, Qt::AnchorRight, b, Qt::AnchorLeft );
addAnchor( b, Qt::AnchorRight, m_layout, Qt::AnchorRight );
#endif
#if 1
auto c = new Rectangle( "SkyBlue" );
addAnchor( a, Qt::AnchorBottom, c, Qt::AnchorTop );
addAnchor( a, Qt::AnchorRight, c, Qt::AnchorRight );
auto d = new Rectangle( "Coral" );
addAnchor( c, Qt::AnchorLeft, d, Qt::AnchorLeft );
addAnchor( c, Qt::AnchorBottom, d, Qt::AnchorTop );
addAnchor( d, Qt::AnchorRight, Qt::AnchorRight );
#endif
}
void MyBox::setup3()
{
auto a = new Rectangle( "PaleVioletRed" );
auto b = new Rectangle( "DarkSeaGreen" );
auto c = new Rectangle( "SkyBlue" );
auto d = new Rectangle( "Coral" );
addAnchor( a, Qt::AnchorTop, Qt::AnchorTop );
addAnchor( a, Qt::AnchorLeft, Qt::AnchorLeft );
addAnchor( a, Qt::AnchorRight, b, Qt::AnchorLeft );
addAnchor( b, Qt::AnchorRight, c, Qt::AnchorLeft );
addAnchor( c, Qt::AnchorRight, d, Qt::AnchorLeft );
addAnchor( d, Qt::AnchorRight, Qt::AnchorRight );
auto e = new Rectangle( "NavajoWhite" );
#if 1
e->setMinimumWidth( 100 );
#endif
addAnchor( a, Qt::AnchorBottom, e, Qt::AnchorTop );
addAnchor( c, Qt::AnchorRight, e, Qt::AnchorRight );
addAnchor( b, Qt::AnchorLeft, e, Qt::AnchorLeft );
}
int main( int argc, char* argv[] )
{
#ifdef ITEM_STATISTICS
QskObjectCounter counter( true );
#endif
QGuiApplication app( argc, argv );
SkinnyFont::init( &app );
SkinnyShortcut::enable( SkinnyShortcut::Quit | SkinnyShortcut::DebugShortcuts );
auto box = new MyBox();
QskWindow window;
window.addItem( box );
window.resize( 600, 600 );
window.show();
return app.exec();
}

View File

@ -1,6 +1,7 @@
TEMPLATE = subdirs
SUBDIRS += \
anchors \
dialogbuttons \
invoker \
inputpanel \