--- a/src/hbcore/layouts/hbanchorlayout.cpp Fri Jun 11 13:58:22 2010 +0300
+++ b/src/hbcore/layouts/hbanchorlayout.cpp Wed Jun 23 18:33:25 2010 +0300
@@ -29,64 +29,76 @@
#include "hbanchorlayoutengine_p.h"
#include <QLayout>
+#include <QDebug>
#include "hblayoututils_p.h"
+
//Uncomment next define in order to get more debug prints.
//Similar define exists also in the engine side.
//#define HBANCHORLAYOUT_DEBUG
-#include <QDebug>
+#ifdef HBANCHORLAYOUT_DEBUG
+#ifndef Q_WS_S60
+#include "hbspaceritem_p.h"
+#endif
+#endif
/*!
- @stable
- @hbcore
\class HbAnchorLayout
- \brief HbAnchorLayout manages geometries of its child items with anchors that
+ \brief HbAnchorLayout manages geometries of its child items with anchors
that connect the layout items with each other.
- The anchors have a start edge, an end edge and a value. The start and
- end edges are defined by (layout item, edge) pairs. See setAnchor() for
- more details.
+ It also allows layout items to be missing and can fix anchor attachments.
+ Here are some simple rules how anchor fixation can be created (the example
+ is only for horizontal direction - the same needs to be done for portrait as well).
- If anchors set allow ambiguos positioning of items, then layout tries to set items size as
+ If anchors set allow ambiguos positioning of items, then layout tries to set items size as
close to preferred as possible.
- Example code:
- \snippet{anchorlayoutsample.cpp,1}
+ \image html hbmeshlayout1.png
+
+ From the image above, we have decided that the green node is always present. This
+ means that all the other nodes in the horizontal graph can be optional.
+
+ \image html hbmeshlayout2.png
+
+ Then, we create the anchors starting from the non-optional node and point towards
+ the edges of the layout. The mesh layout definition in the WidgetML would look like:
+
+ \code
- The picture below illustrates the anchors defined by the above example code.
+ <meshitem src="green_item" srcEdge="LEFT" dst="blue_item" dstEdge="RIGHT" />
+ <meshitem src="blue_item" srcEdge="LEFT" dst="" dstEdge="LEFT" />
+ <meshitem src="green_item" srcEdge="RIGHT" dst="red_item" dstEdge="LEFT" />
+ <meshitem src="red_item" srcEdge="RIGHT" dst="yellow_item" dstEdge="LEFT" />
+ <meshitem src="yellow_item" srcEdge="RIGHT" dst="" dstEdge="RIGHT" />
+
+ \endcode
- \image html hbanchorlayout.png
+ As mentioned, the green node needs be present always. In practice, this means that the
+ parent widget, which owns this anchor layout, needs to have a child widget with item
+ name "green_item". \c HbStyle::setItemName for more details.
+
+ If an optional node is missing, the anchors pointing to the node are
+ changed to point to the node after (=towards the parent layout) the missing one - this
+ is called "fixing the mesh".
+
+ \image html hbmeshlayout3.png
+
+ In the picture above, the blue and yellow items are missing. The anchor is fixed by removing
+ the anchor definitions starting from the missing nodes.
+
+ \stable
*/
/*!
- \enum Hb::Edge
+ \enum HbAnchorLayout::Edge
This enum defines the edges of a layout item.
*/
-/*!
- \var HbAnchorLayout::Left
- Left edge.
-*/
-
-/*!
- \var HbAnchorLayout::Top
- Top edge.
-*/
-
-/*!
- \var HbAnchorLayout::Right
- Right edge.
-*/
-
-/*!
- \var HbAnchorLayout::Bottom
- Bottom edge.
-*/
-
-/*!
+/*
\enum EdgeType
\internal
*/
@@ -95,6 +107,112 @@
Vertical
};
+/*
+ Type for mapping from layout item to node identifier.
+ \internal
+*/
+typedef QMap<QGraphicsLayoutItem*, QString> HbMeshItemMap;
+typedef HbMeshItemMap::iterator HbMeshItemMapIterator;
+typedef HbMeshItemMap::const_iterator HbMeshItemMapConstIterator;
+
+
+/*
+ Result of findEndItem.
+*/
+struct HbMeshEndItemResult
+{
+ QGraphicsLayoutItem *mItem;
+ HbAnchorLayout::Edge mEdge;
+ qreal mValue;
+};
+
+class HbAnchorLayoutPrivate
+{
+public:
+ Q_DECLARE_PUBLIC( HbAnchorLayout )
+
+ HbAnchorLayoutPrivate();
+ ~HbAnchorLayoutPrivate();
+
+ void addItemIfNeeded(QGraphicsLayoutItem *item);
+
+ static EdgeType edgeType( HbAnchorLayout::Edge edge );
+ void setItemGeometries();
+ void updateAnchorsAndItems();
+
+ void createEquations( EdgeType type );
+
+ int getEdgeIndex(QGraphicsLayoutItem *item, Hb::Edge edge);
+
+ bool findEndItem(
+ QList<HbMeshEndItemResult> &resultList,
+ const HbAnchor *anchor,
+ QStringList &ids) const;
+ void resolveAnchors();
+ void removeItemIfNeeded( QGraphicsLayoutItem *item );
+
+ bool setAnchor( HbAnchor *anchor );
+
+ void setSizeProp( SizeProperty *v, QGraphicsLayoutItem *item, EdgeType type );
+ GraphVertex *createCenterEdge( EdgeType type, QGraphicsLayoutItem *item, Hb::Edge edge );
+ void defineNextGeometry( const int itemIndexStart, const int itemIndexEnd, const int anchorIndex, const int definedItemIndex );
+
+
+ QSizeF sizeHint(Qt::SizeHint which);
+
+public:
+ HbAnchorLayout * q_ptr;
+
+ bool mEquationsDirty; // if true, we needed to re-create the equations (e.g. when new anchor is set)
+ bool mValid; // result of the calculations. false, if the equations cannot be solved.
+ bool mInvalidateCalled; // set true in ::invalidate() and cleared after geometry is set in ::setGeometry
+ bool mWrongAnchors;
+
+ QList<HbAnchor*> mAllAnchors; // anchors that are set by user
+ QList<HbAnchor*> mResolvedDynamicAnchors; // references to generated anchors
+ QList<HbAnchor*> mResolvedStaticAnchors; // references to anchors, that remains the same after resolving
+ QList<HbAnchor*> mResolvedAnchors; // anchors that are passed to engine
+
+ // mesh layout data
+ QList<QGraphicsLayoutItem*> mItems; // for addItem
+ QList<QGraphicsLayoutItem*> mActualItems; // layouted items
+ HbMeshItemMap mMeshMap;
+
+ QRectF mUsedRect;
+
+ // new items
+
+ QList<GraphEdge*> mEdgesVertical;
+ QList<GraphEdge*> mEdgesHorizontal;
+ QList<GraphVertex*> mVerticesVertical;
+ QList<GraphVertex*> mVerticesHorizontal;
+
+ QList<Expression*> mEquationsHorizontal;
+ QList<Expression*> mEquationsVertical;
+ VariableSet mVariablesHorizontal;
+ VariableSet mVariablesVertical;
+
+ Variable *mLayoutVarH;
+ Variable *mLayoutVarV;
+
+ QVector< bool > mAnchorsVisited;
+ QVector< bool > mGeometryDefinedH;
+ QVector< bool > mGeometryDefinedV;
+ typedef struct {
+ qreal x1, y1, x2, y2;
+ } ItemGeometry;
+
+ QVector< ItemGeometry > mItemsGeometry;
+
+ Solution mSolutionHorizontal;
+ Solution mSolutionVertical;
+
+};
+
+
+
+
+
/*!
\internal
@@ -111,8 +229,10 @@
HbAnchor::HbAnchor(const HbAnchor &anchor)
: mStartItem(anchor.mStartItem),
mStartEdge(anchor.mStartEdge),
+ mStartId(anchor.mStartId),
mEndItem(anchor.mEndItem),
mEndEdge(anchor.mEndEdge),
+ mEndId(anchor.mEndId),
mValue(anchor.mValue)
{
}
@@ -135,8 +255,10 @@
{
if (this != &anchor) {
mStartItem = anchor.mStartItem;
+ mStartId = anchor.mStartId;
mStartEdge = anchor.mStartEdge;
mEndItem = anchor.mEndItem;
+ mEndId = anchor.mEndId;
mEndEdge = anchor.mEndEdge;
mValue = anchor.mValue;
}
@@ -144,85 +266,38 @@
}
-class HbAnchorLayoutPrivate
-{
-public:
- Q_DECLARE_PUBLIC( HbAnchorLayout )
-
- HbAnchorLayoutPrivate();
- ~HbAnchorLayoutPrivate();
-
- void addItemIfNeeded( QGraphicsLayoutItem *item );
- EdgeType edgeType( const Hb::Edge edge ) const;
- HbAnchor* getAnchor( QGraphicsLayoutItem *startItem,
- Hb::Edge startEdge,
- QGraphicsLayoutItem *endItem,
- Hb::Edge endEdge );
-
- void setItemGeometries();
-
- void createEquations( EdgeType type );
- void setSizeProp( SizeProperty *v, QGraphicsLayoutItem *item, EdgeType type );
- GraphVertex *createCenterEdge( EdgeType type, QGraphicsLayoutItem *item, Hb::Edge edge );
- void defineNextGeometry( const int itemIndexStart, const int itemIndexEnd,
- const int anchorIndex, const int definedItemIndex );
-
- QSizeF sizeHint( Qt::SizeHint which );
-
-public:
- HbAnchorLayout * q_ptr;
- QList<QGraphicsLayoutItem*> mItems;
- QList<HbAnchor*> mAnchors;
- bool mEquationsDirty; // if true, we needed to re-create the equations (e.g. when new anchor is set)
- bool mValid; // result of the calculations. false, if the equations cannot be solved.
- bool mWrongAnchors; // need to recreate anchors, these ones are unsolvable with any layout geometry
- bool mInvalidateCalled; // set true in ::invalidate() and cleared after geometry is set in ::setGeometry
- QRectF mUsedRect;
-
- QList<GraphEdge*> mEdgesVertical;
- QList<GraphEdge*> mEdgesHorizontal;
- QList<GraphVertex*> mVerticesVertical;
- QList<GraphVertex*> mVerticesHorizontal;
-
- QList<Expression*> mEquationsHorizontal;
- QList<Expression*> mEquationsVertical;
- VariableSet mVariablesHorizontal;
- VariableSet mVariablesVertical;
-
- Variable *mLayoutVarH;
- Variable *mLayoutVarV;
-
- QVector<bool> mAnchorsVisited;
- QVector< bool > mGeometryDefinedH;
- QVector< bool > mGeometryDefinedV;
- typedef struct {
- qreal x1, y1, x2, y2;
- } ItemGeometry;
-
- QVector< ItemGeometry > mItemsGeometry;
-
- Solution mSolutionHorizontal;
- Solution mSolutionVertical;
-};
/*!
\internal
*/
-HbAnchorLayoutPrivate::HbAnchorLayoutPrivate() :
- mEquationsDirty( false ), mValid( true ), mWrongAnchors( false ), mInvalidateCalled(false),
- mLayoutVarH( 0 ), mLayoutVarV( 0 )
+QList<HbAnchor*> HbAnchorLayoutDebug::getAnchors( HbAnchorLayout* layout )
+{
+ layout->d_ptr->resolveAnchors();
+ return layout->d_ptr->mResolvedAnchors;
+}
+
+QList<HbAnchor*> HbAnchorLayoutDebug::getOriginalAnchors( HbAnchorLayout* layout )
+{
+ return layout->d_ptr->mAllAnchors;
+}
+
+/*
+ \class HbAnchorLayoutPrivate
+ \internal
+*/
+HbAnchorLayoutPrivate::HbAnchorLayoutPrivate() : mEquationsDirty(false), mValid(true), mInvalidateCalled( false ), mWrongAnchors( false ),
+ mUsedRect( 0, 0, 0, 0 ), mLayoutVarH( 0 ), mLayoutVarV( 0 )
+
{
}
-/*!
+/*
\internal
*/
HbAnchorLayoutPrivate::~HbAnchorLayoutPrivate()
{
- qDeleteAll( mAnchors );
-
qDeleteAll( mEdgesVertical );
qDeleteAll( mEdgesHorizontal );
@@ -231,58 +306,312 @@
qDeleteAll( mEquationsHorizontal );
qDeleteAll( mEquationsVertical );
+
+ qDeleteAll( mAllAnchors );
+ qDeleteAll( mResolvedDynamicAnchors );
}
-/*!
+/*
\internal
*/
-void HbAnchorLayoutPrivate::addItemIfNeeded( QGraphicsLayoutItem *item )
-{
- Q_Q(HbAnchorLayout);
- if ( item != q && !mItems.contains(item) ) {
- HbLayoutUtils::addChildItem(q, item);
-
- mItems.append( item );
- }
-}
-
-/*!
- \internal
-*/
-EdgeType HbAnchorLayoutPrivate::edgeType( const Hb::Edge edge ) const
+EdgeType HbAnchorLayoutPrivate::edgeType( HbAnchorLayout::Edge edge )
{
EdgeType type( Horizontal );
- if ( edge == Hb::TopEdge || edge == Hb::BottomEdge || edge == Hb::CenterVEdge) {
+ if( edge == Hb::TopEdge || edge == Hb::BottomEdge || edge == Hb::CenterVEdge ) {
type = Vertical;
}
return type;
}
-/*!
+#ifdef HBANCHORLAYOUT_DEBUG
+/*
+ Returns string representation of value in \c Edge enumeration.
+ \internal
+*/
+static QString edgeAsText(HbAnchorLayout::Edge edge)
+{
+ QString result;
+ switch (edge) {
+ case Hb::LeftEdge:
+ result = "LEFT";
+ break;
+
+ case Hb::RightEdge:
+ result = "RIGHT";
+ break;
+
+ case Hb::CenterHEdge:
+ result = "CENTERH";
+ break;
+
+ case Hb::TopEdge:
+ result = "TOP";
+ break;
+
+ case Hb::BottomEdge:
+ result = "BOTTOM";
+ break;
+
+ case Hb::CenterVEdge:
+ result = "CENTERV";
+ break;
+
+ default:
+ result = "<UNDEFINED>";
+ break;
+ }
+
+ return result;
+}
+
+static QString itemAsText(QGraphicsLayoutItem* item, QGraphicsLayout *layout)
+{
+ QString result = "<emtpy>";
+ if ( item ) {
+ result = (item == layout) ? "HbAnchorLayout" : "<unknown>";
+ QGraphicsItem *gItem = item->graphicsItem();
+ if (gItem) {
+ if (gItem->isWidget()) {
+ result = static_cast<QGraphicsWidget*>(gItem)->metaObject()->className();
+ }
+#ifndef Q_WS_S60
+ } else {
+ HbSpacerItem *spacer = dynamic_cast<HbSpacerItem *>(item);
+ if ( spacer ) {
+ result = "HbSpacerItem";
+ }
+#endif
+ }
+ }
+ return result;
+}
+
+#endif // HBANCHORLAYOUT_DEBUG
+
+/*
\internal
*/
-HbAnchor* HbAnchorLayoutPrivate::getAnchor(
- QGraphicsLayoutItem *startItem,
- Hb::Edge startEdge,
- QGraphicsLayoutItem *endItem,
- Hb::Edge endEdge )
+void HbAnchorLayoutPrivate::updateAnchorsAndItems()
{
- for ( int i = mAnchors.count()-1 ; i >= 0; i-- ) {
- HbAnchor* anchor = mAnchors.at(i);
- if ( anchor->mStartItem == startItem &&
- anchor->mStartEdge == startEdge &&
- anchor->mEndItem == endItem &&
- anchor->mEndEdge == endEdge ) {
- return anchor;
+ Q_Q(HbAnchorLayout);
+ resolveAnchors();
+
+#ifdef HBANCHORLAYOUT_DEBUG
+ QGraphicsWidget* w = HbLayoutUtils::parentWidget( q );
+ if ( w ) {
+ qDebug() << "MeshLayout: Mesh anchors for" << w->metaObject()->className();
+ }
+ const QString parentId =
+ mMeshMap.contains(q) ? mMeshMap.value(q) : QString();
+ qDebug() << "-- -- resolved";
+ qDebug() << "-- count: " << mResolvedAnchors.size() << ", parent: " << parentId;
+ foreach (const HbAnchor *item, mResolvedAnchors) {
+ const QString itemTemplate("-- (%1 [%2], %3) - (%4 [%5], %6) = %7");
+ qDebug() <<
+ itemTemplate
+ .arg(item->mStartId)
+ .arg(itemAsText(item->mStartItem, q))
+ .arg(edgeAsText(item->mStartEdge))
+ .arg(item->mEndId)
+ .arg(itemAsText(item->mEndItem, q))
+ .arg(edgeAsText(item->mEndEdge))
+ .arg(item->mValue).toAscii().data();
+ }
+ qDebug() << "-- -- all";
+ qDebug() << "-- count: " << mAllAnchors.size() << ", parent: " << parentId;
+ foreach (const HbAnchor *item, mAllAnchors) {
+ const QString itemTemplate("-- (%1 [%2], %3) - (%4 [%5], %6) = %7");
+ qDebug() <<
+ itemTemplate
+ .arg(item->mStartId)
+ .arg(itemAsText(item->mStartItem, q))
+ .arg(edgeAsText(item->mStartEdge))
+ .arg(item->mEndId)
+ .arg(itemAsText(item->mEndItem, q))
+ .arg(edgeAsText(item->mEndEdge))
+ .arg(item->mValue).toAscii().data();
+ }
+ qDebug() << "-- ";
+#endif // HBANCHORLAYOUT_DEBUG
+
+ // HbAnchorLayout will only touch items that have anchors defined.
+ mActualItems.clear();
+ for (QList<HbAnchor*>::const_iterator it = mResolvedAnchors.constBegin();
+ it != mResolvedAnchors.constEnd();
+ ++it) {
+
+ const HbAnchor* item = *it;
+
+ if (item->mStartItem != q && !mActualItems.contains(item->mStartItem)) {
+ mActualItems.append(item->mStartItem);
+ }
+ if (item->mEndItem != q && !mActualItems.contains(item->mEndItem)) {
+ mActualItems.append(item->mEndItem);
}
}
- return 0;
+
+}
+
+
+void HbAnchorLayoutPrivate::setSizeProp( SizeProperty *v, QGraphicsLayoutItem *item, EdgeType type )
+{
+ if( type == Vertical ) {
+ const QSizePolicy::Policy verticalPolicy = item->sizePolicy().verticalPolicy();
+
+ if ( verticalPolicy & QSizePolicy::ShrinkFlag ) {
+ v->min = item->minimumHeight();
+ } else {
+ v->min = item->preferredHeight();
+ }
+
+ if ( verticalPolicy & (QSizePolicy::GrowFlag | QSizePolicy::ExpandFlag) ) {
+ v->max = item->maximumHeight();
+ } else {
+ v->max = item->preferredHeight();
+ }
+
+ v->pref = qBound( v->min, item->preferredHeight(), v->max );
+
+ v->flags |= (v->min == v->max) ? SizeProperty::FlagFixed : 0;
+ v->flags |= (verticalPolicy & QSizePolicy::ExpandFlag) ? SizeProperty::FlagExpanding : 0;
+
+ if( verticalPolicy & QSizePolicy::IgnoreFlag ) {
+ v->pref = v->min;
+ v->flags |= SizeProperty::FlagExpanding;
+ }
+ } else {
+ const QSizePolicy::Policy horizontalPolicy = item->sizePolicy().horizontalPolicy();
+
+ if ( horizontalPolicy & QSizePolicy::ShrinkFlag ) {
+ v->min = item->minimumWidth();
+ } else {
+ v->min = item->preferredWidth();
+ }
+
+ if ( horizontalPolicy & (QSizePolicy::GrowFlag | QSizePolicy::ExpandFlag) ) {
+ v->max = item->maximumWidth();
+ } else {
+ v->max = item->preferredWidth();
+ }
+
+ v->pref = qBound( v->min, item->preferredWidth(), v->max );
+
+ v->flags |= (v->min == v->max) ? SizeProperty::FlagFixed : 0;
+ v->flags |= (horizontalPolicy & QSizePolicy::ExpandFlag) ? SizeProperty::FlagExpanding : 0;
+
+ if( horizontalPolicy & QSizePolicy::IgnoreFlag ) {
+ v->pref = v->min;
+ v->flags |= SizeProperty::FlagExpanding;
+ }
+ }
}
-void HbAnchorLayoutPrivate::defineNextGeometry(
- const int itemIndexStart,
- const int itemIndexEnd,
- const int anchorIndex,
+
+GraphVertex *HbAnchorLayoutPrivate::createCenterEdge( EdgeType type, QGraphicsLayoutItem *item, Hb::Edge edge )
+{
+ GraphVertex *middle;
+ GraphVertex *start = 0;
+ GraphVertex *end = 0;
+
+ QList<GraphEdge*> *edges = &mEdgesHorizontal;
+ QList<GraphVertex*> *vertices = &mVerticesHorizontal;
+
+ if( type == Vertical ) {
+ if( edge != Hb::CenterVEdge ) {
+ qWarning() << "HbAnchorLayout: something wrong " << __LINE__;
+ return 0;
+ }
+
+ edges = &mEdgesVertical;
+ vertices = &mVerticesVertical;
+
+ for( int j = 0; j < vertices->size(); j++ ) {
+ GraphVertex *current = vertices->at(j);
+ if( current->itemRef == item ) {
+ if( current->itemSide == Hb::TopEdge ) {
+ start = current;
+ } else if( current->itemSide == Hb::BottomEdge ) {
+ end = current;
+ }
+ }
+ }
+ } else {
+ if( edge != Hb::CenterHEdge ) {
+ qWarning() << "HbAnchorLayout: something wrong " << __LINE__;
+ return 0;
+ }
+
+ for( int j = 0; j < vertices->size(); j++ ) {
+ GraphVertex *current = vertices->at(j);
+ if( current->itemRef == item ) {
+ if( current->itemSide == Hb::LeftEdge ) {
+ start = current;
+ } else if( current->itemSide == Hb::RightEdge ) {
+ end = current;
+ }
+ }
+ }
+ }
+
+ if( !( start && end ) ) {
+ qWarning() << "HbAnchorLayout: something wrong " << __LINE__;
+ return 0;
+ }
+
+ GraphEdge *oldEdge = 0;
+
+ for( int i = 0; i < edges->size(); i++ ) {
+ oldEdge = edges->at(i);
+ if( ( oldEdge->ref == item ) && ( oldEdge->startVertex == start ) && ( oldEdge->endVertex == end ) ){
+ break;
+ }
+ }
+
+ if( !oldEdge ) {
+ qWarning() << "HbAnchorLayout: something wrong " << __LINE__;
+ return 0;
+ }
+
+ middle = new GraphVertex();
+ middle->itemRef = ( void* )item;
+ middle->itemSide = edge;
+ middle->special = false;
+
+ GraphEdge *newEdge1 = new GraphEdge();
+ GraphEdge *newEdge2 = new GraphEdge();
+
+ newEdge1->startVertex = start;
+ newEdge1->endVertex = middle;
+ newEdge1->ref = ( void* )item;
+
+ newEdge1->expr->plusExpression( oldEdge->expr );
+ newEdge1->expr->multiply( 0.5 );
+
+
+ newEdge2->startVertex = middle;
+ newEdge2->endVertex = end;
+ newEdge2->ref = ( void* )item;
+ newEdge2->expr->plusExpression( oldEdge->expr );
+ newEdge2->expr->multiply( 0.5 );
+
+
+ middle->edges.append( newEdge1 );
+ start->edges.append( newEdge1 );
+ middle->edges.append( newEdge2 );
+ end->edges.append( newEdge2 );
+
+ edges->append( newEdge1 );
+ edges->append( newEdge2 );
+ vertices->append( middle );
+
+
+ return middle;
+}
+
+void HbAnchorLayoutPrivate::defineNextGeometry(
+ const int itemIndexStart,
+ const int itemIndexEnd,
+ const int anchorIndex,
const int definedItemIndex )
{
ItemGeometry *knownItemGeom, *unKnownItemGeom;
@@ -290,7 +619,7 @@
int sign;
qreal itemSize;
bool isHorizontal;
- HbAnchor *anchor = mAnchors.at( anchorIndex );
+ HbAnchor *anchor = mResolvedAnchors.at( anchorIndex );
qreal leftPoint(0), rightPoint(0), sourcePoint(0), dstPointLeft(0);
mAnchorsVisited[ anchorIndex ] = true;
@@ -310,12 +639,10 @@
if( isHorizontal ) {
mGeometryDefinedH[itemIndexEnd] = true;
- itemSize = mSolutionHorizontal.value(
- mVariablesHorizontal.findVariable( mItems.at(itemIndexEnd) ) );
+ itemSize = mSolutionHorizontal.value( mVariablesHorizontal.findVariable( mActualItems.at(itemIndexEnd) ) );
} else {
mGeometryDefinedV[itemIndexEnd] = true;
- itemSize = mSolutionVertical.value(
- mVariablesVertical.findVariable( mItems.at(itemIndexEnd) ) );
+ itemSize = mSolutionVertical.value( mVariablesVertical.findVariable( mActualItems.at(itemIndexEnd) ) );
}
sign = 1;
@@ -328,12 +655,10 @@
if( isHorizontal ) {
mGeometryDefinedH[itemIndexStart] = true;
- itemSize = mSolutionHorizontal.value(
- mVariablesHorizontal.findVariable( mItems.at(itemIndexStart) ) );
+ itemSize = mSolutionHorizontal.value( mVariablesHorizontal.findVariable( mActualItems.at(itemIndexStart) ) );
} else {
mGeometryDefinedV[itemIndexStart] = true;
- itemSize = mSolutionVertical.value(
- mVariablesVertical.findVariable( mItems.at(itemIndexStart) ) );
+ itemSize = mSolutionVertical.value( mVariablesVertical.findVariable( mActualItems.at(itemIndexStart) ) );
}
sign = -1;
@@ -401,7 +726,8 @@
}
-/*!
+
+/*
\internal
*/
void HbAnchorLayoutPrivate::setItemGeometries()
@@ -409,16 +735,18 @@
Q_Q(HbAnchorLayout);
const QRectF newRect = q->geometry();
- if( mWrongAnchors || ( mItems.isEmpty() ) ) {
+ if( mWrongAnchors || ( mActualItems.isEmpty() ) ) {
return;
}
- if ( (newRect != mUsedRect) || mInvalidateCalled ) {
+ if( (newRect != mUsedRect) || mInvalidateCalled ) {
+ mInvalidateCalled = false;
mUsedRect = newRect;
if ( mEquationsDirty ) {
+ updateAnchorsAndItems();
createEquations( Horizontal );
createEquations( Vertical );
mEquationsDirty = false;
@@ -498,25 +826,27 @@
mGeometryDefinedV[i] = false;
}
- int layoutIndex = mItems.size();
+ int layoutIndex = mActualItems.size();
- mItemsGeometry[ layoutIndex ].x1 = 0;
- mItemsGeometry[ layoutIndex ].x2 = newRect.width();
- mItemsGeometry[ layoutIndex ].y1 = 0;
- mItemsGeometry[ layoutIndex ].y2 = newRect.height();
+ mItemsGeometry[ layoutIndex ].x1 = 0;//newRect.left();
+ mItemsGeometry[ layoutIndex ].x2 = newRect.width();//newRect.right();
+ mItemsGeometry[ layoutIndex ].y1 = 0;//newRect.top();
+ mItemsGeometry[ layoutIndex ].y2 = newRect.height();//newRect.bottom();
+ mGeometryDefinedH[ layoutIndex ] = true;
+ mGeometryDefinedV[ layoutIndex ] = true;
for( int i = 0; i < mAnchorsVisited.size(); i++ ) {
- HbAnchor *anchor = mAnchors.at(i);
+ HbAnchor *anchor = mResolvedAnchors.at(i);
if( ( anchor->mStartItem != q ) && ( anchor->mEndItem != q ) ) {
continue;
}
- int startIndex = mItems.indexOf( anchor->mStartItem ); // returns -1 if not found => this is layout
- int endIndex = mItems.indexOf( anchor->mEndItem );
+ int startIndex = mActualItems.indexOf( anchor->mStartItem ); // returns -1 if not found => this is layout
+ int endIndex = mActualItems.indexOf( anchor->mEndItem );
mAnchorsVisited[i] = true; // Temporary overkill, if both anchors connected to layout. Must be restricted on setAnchor() level
@@ -555,10 +885,10 @@
if( mAnchorsVisited.at(i) ) {
continue;
}
- HbAnchor *anchor = mAnchors.at(i);
+ HbAnchor *anchor = mResolvedAnchors.at(i);
- startIndex = mItems.indexOf( anchor->mStartItem );
- endIndex = mItems.indexOf( anchor->mEndItem );
+ startIndex = mActualItems.indexOf( anchor->mStartItem );
+ endIndex = mActualItems.indexOf( anchor->mEndItem );
#ifdef HBANCHORLAYOUT_DEBUG
qDebug() << "startIndex:" << startIndex << " endIndex" << endIndex;
#endif //HBANCHORLAYOUT_DEBUG
@@ -580,9 +910,16 @@
}
}
+#ifdef HBANCHORLAYOUT_DEBUG
+ QGraphicsWidget* w = HbLayoutUtils::parentWidget( q );
+ if ( w ) {
+ qDebug() << "Items of " << w->metaObject()->className();
+ }
+#endif
+
Qt::LayoutDirection layoutDir = HbLayoutUtils::visualDirection(q);
- for( int i = 0; i < layoutIndex; i++ ) {
+ for( int i = 0; i < mActualItems.size(); i++ ) {
QRectF geom;
ItemGeometry calcGeom = mItemsGeometry.at(i);
if( mGeometryDefinedH.at(i) ) {
@@ -590,197 +927,28 @@
geom.setRight( mUsedRect.left() + calcGeom.x2 );
} else {
geom.setLeft( mUsedRect.left() );
- geom.setRight( mUsedRect.left() + mItems.at(i)->preferredWidth() );
+ geom.setRight( mUsedRect.left() + mActualItems.at(i)->preferredWidth() );
}
if( mGeometryDefinedV.at(i) ) {
geom.setTop( mUsedRect.top() + calcGeom.y1 );
geom.setBottom( mUsedRect.top() + calcGeom.y2 );
} else {
geom.setTop( mUsedRect.top() );
- geom.setBottom( mUsedRect.top() + mItems.at(i)->preferredHeight() );
+ geom.setBottom( mUsedRect.top() + mActualItems.at(i)->preferredHeight() );
}
- HbLayoutUtils::visualRect(layoutDir, geom, newRect);
+ HbLayoutUtils::visualRect( layoutDir, geom, newRect );
#ifdef HBANCHORLAYOUT_DEBUG
qDebug( "Item %d: (%lf, %lf) : (%lf %lf)", i, calcGeom.x1, calcGeom.y1, calcGeom.x2, calcGeom.y2 );
+ // qDebug() << "Item " << i << "(" << ((QGraphicsWidget*)mActualItems.at(i))->metaObject()->className() << ")" << " geom " << geom;
#endif // HBANCHORLAYOUT_DEBUG
-
- mItems.at(i)->setGeometry( geom );
+ mActualItems.at(i)->setGeometry( geom );
}
}
}
}
-void HbAnchorLayoutPrivate::setSizeProp( SizeProperty *v, QGraphicsLayoutItem *item, EdgeType type )
-{
- if( type == Vertical ) {
- const QSizePolicy::Policy verticalPolicy = item->sizePolicy().verticalPolicy();
-
- if ( verticalPolicy & QSizePolicy::ShrinkFlag ) {
- v->min = item->minimumHeight();
- } else {
- v->min = item->preferredHeight();
- }
-
- if ( verticalPolicy & (QSizePolicy::GrowFlag | QSizePolicy::ExpandFlag) ) {
- v->max = item->maximumHeight();
- } else {
- v->max = item->preferredHeight();
- }
-
- v->pref = qBound( v->min, item->preferredHeight(), v->max );
-
- v->flags |= (v->min == v->max) ? SizeProperty::FlagFixed : 0;
- v->flags |= (verticalPolicy & QSizePolicy::ExpandFlag) ? SizeProperty::FlagExpanding : 0;
-
- if( verticalPolicy & QSizePolicy::IgnoreFlag ) {
- v->pref = v->min;
- v->flags |= SizeProperty::FlagExpanding;
- }
- } else {
- const QSizePolicy::Policy horizontalPolicy = item->sizePolicy().horizontalPolicy();
-
- if ( horizontalPolicy & QSizePolicy::ShrinkFlag ) {
- v->min = item->minimumWidth();
- } else {
- v->min = item->preferredWidth();
- }
-
- if ( horizontalPolicy & (QSizePolicy::GrowFlag | QSizePolicy::ExpandFlag) ) {
- v->max = item->maximumWidth();
- } else {
- v->max = item->preferredWidth();
- }
-
- v->pref = qBound( v->min, item->preferredWidth(), v->max );
-
- v->flags |= (v->min == v->max) ? SizeProperty::FlagFixed : 0;
- v->flags |= (horizontalPolicy & QSizePolicy::ExpandFlag) ? SizeProperty::FlagExpanding : 0;
-
- if( horizontalPolicy & QSizePolicy::IgnoreFlag ) {
- v->pref = v->min;
- v->flags |= SizeProperty::FlagExpanding;
- }
- }
-}
-
-
-GraphVertex *HbAnchorLayoutPrivate::createCenterEdge(
- EdgeType type, QGraphicsLayoutItem *item, Hb::Edge edge )
-{
- GraphVertex *middle;
- GraphVertex *start = 0;
- GraphVertex *end = 0;
-
- QList<GraphEdge*> *edges = &mEdgesHorizontal;
- QList<GraphVertex*> *vertices = &mVerticesHorizontal;
-
- if( type == Vertical ) {
- if( edge != Hb::CenterVEdge ) {
-#ifdef HBANCHORLAYOUT_DEBUG
- qDebug() << "something wrong " << __LINE__;
-#endif //HBANCHORLAYOUT_DEBUG
- return 0;
- }
-
- edges = &mEdgesVertical;
- vertices = &mVerticesVertical;
-
- for( int j = 0; j < vertices->size(); j++ ) {
- GraphVertex *current = vertices->at(j);
- if( current->itemRef == item ) {
- if( current->itemSide == Hb::TopEdge ) {
- start = current;
- } else if( current->itemSide == Hb::BottomEdge ) {
- end = current;
- }
- }
- }
- } else {
- if( edge != Hb::CenterHEdge ) {
-#ifdef HBANCHORLAYOUT_DEBUG
- qDebug() << "something wrong " << __LINE__;
-#endif //HBANCHORLAYOUT_DEBUG
- return 0;
- }
-
- for( int j = 0; j < vertices->size(); j++ ) {
- GraphVertex *current = vertices->at(j);
- if( current->itemRef == item ) {
- if( current->itemSide == Hb::LeftEdge ) {
- start = current;
- } else if( current->itemSide == Hb::RightEdge ) {
- end = current;
- }
- }
- }
- }
-
- if( !( start && end ) ) {
-#ifdef HBANCHORLAYOUT_DEBUG
- qDebug() << "something wrong " << __LINE__;
-#endif //HBANCHORLAYOUT_DEBUG
- return 0;
- }
-
- GraphEdge *oldEdge = 0;
-
- for( int i = 0; i < edges->size(); i++ ) {
- oldEdge = edges->at(i);
- if( oldEdge->ref == item ) {
- if( ( oldEdge->startVertex == start ) && ( oldEdge->endVertex == end ) ){
-/* edges->removeOne( oldEdge );
- start->edges.removeOne( oldEdge );
- end->edges.removeOne( oldEdge );*/
- break;
- }
- }
- }
-
- if( !oldEdge ) {
-#ifdef HBANCHORLAYOUT_DEBUG
- qDebug() << "something wrong " << __LINE__;
-#endif //HBANCHORLAYOUT_DEBUG
- return 0;
- }
-
- middle = new GraphVertex();
- middle->itemRef = ( void* )item;
- middle->itemSide = edge;
- middle->special = false;
-
- GraphEdge *newEdge1 = new GraphEdge();
- GraphEdge *newEdge2 = new GraphEdge();
-
- newEdge1->startVertex = start;
- newEdge1->endVertex = middle;
- newEdge1->ref = ( void* )item;
-
- newEdge1->expr->plusExpression( oldEdge->expr );
- newEdge1->expr->multiply( 0.5 );
-
-
- newEdge2->startVertex = middle;
- newEdge2->endVertex = end;
- newEdge2->ref = ( void* )item;
- newEdge2->expr->plusExpression( oldEdge->expr );
- newEdge2->expr->multiply( 0.5 );
-
-
- middle->edges.append( newEdge1 );
- start->edges.append( newEdge1 );
- middle->edges.append( newEdge2 );
- end->edges.append( newEdge2 );
-
- edges->append( newEdge1 );
- edges->append( newEdge2 );
- vertices->append( middle );
-
-
- return middle;
-}
-
/*!
\internal
*/
@@ -845,8 +1013,8 @@
}
- for ( int i = 0; i < mItems.count(); i++ ) {
- QGraphicsLayoutItem *item = mItems.at( i );
+ for ( int i = 0; i < mActualItems.count(); i++ ) {
+ QGraphicsLayoutItem *item = mActualItems.at( i );
itemStart = new GraphVertex();
itemEnd = new GraphVertex();
newEdge = new GraphEdge();
@@ -891,16 +1059,16 @@
v1->sizeProp.flags = SizeProperty::FlagFixed;
- for( int i = 0; i < mAnchors.count(); i++) {
- HbAnchor* anchor = mAnchors.at(i);
+ for( int i = 0; i < mResolvedAnchors.count(); i++) {
+ HbAnchor* anchor = mResolvedAnchors.at(i);
if ( edgeType( anchor->mStartEdge ) == type ) {
itemStart = 0;
itemEnd = 0;
for( int j = 0; j < vertices->size(); j++ ) {
- if( ( vertices->at(j)->itemRef == anchor->mStartItem ) &&
+ if( ( vertices->at(j)->itemRef == anchor->mStartItem ) &&
( vertices->at(j)->itemSide == anchor->mStartEdge ) ) {
itemStart = vertices->at(j);
- } else if( ( vertices->at(j)->itemRef == anchor->mEndItem ) &&
+ } else if( ( vertices->at(j)->itemRef == anchor->mEndItem ) &&
( vertices->at(j)->itemSide == anchor->mEndEdge ) ) {
itemEnd = vertices->at(j);
}
@@ -913,6 +1081,19 @@
itemEnd = createCenterEdge( type, anchor->mEndItem, anchor->mEndEdge );
}
+ if( !itemStart ){
+ qWarning() << "HbAnchorLayout: internal error, line " << __LINE__;
+ mWrongAnchors = true;
+ AnchorLayoutEngine::instance()->cleanUp( layoutStart, layoutMiddle, layoutEnd, edges, vertices, el );
+ return;
+ }
+ if( !itemEnd ) {
+ qWarning() << "HbAnchorLayout: internal error, line " << __LINE__;
+ mWrongAnchors = true;
+ AnchorLayoutEngine::instance()->cleanUp( layoutStart, layoutMiddle, layoutEnd, edges, vertices, el );
+ return;
+ }
+
newEdge = new GraphEdge();
itemStart->edges.append( newEdge );
itemEnd->edges.append( newEdge );
@@ -965,11 +1146,10 @@
if( ! AnchorLayoutEngine::instance()->processItems( edges, vertices, vs, el ) ) {
mWrongAnchors = true;
- AnchorLayoutEngine::instance()->cleanUp(
- layoutStart, layoutMiddle, layoutEnd, edges, vertices, el );
-//#ifdef HBANCHORLAYOUT_DEBUG
- qDebug() << "FAIL line:" << __LINE__;
-//#endif //HBANCHORLAYOUT_DEBUG
+ AnchorLayoutEngine::instance()->cleanUp( layoutStart, layoutMiddle, layoutEnd, edges, vertices, el );
+#ifdef HBANCHORLAYOUT_DEBUG
+ qDebug() << "FAIL! " << __LINE__;
+#endif //HBANCHORLAYOUT_DEBUG
return;
}
@@ -1000,16 +1180,16 @@
layoutVar->sizeProp.pref = 100;
layoutVar->sizeProp.flags = 0;
- AnchorLayoutEngine::instance()->attachToLayout(
+ AnchorLayoutEngine::instance()->attachToLayout(
layoutStart, layoutMiddle, layoutEnd, layoutVar, el );
- AnchorLayoutEngine::instance()->cleanUp(
+ AnchorLayoutEngine::instance()->cleanUp(
layoutStart, layoutMiddle, layoutEnd, edges, vertices, el );
- mAnchorsVisited.resize( mAnchors.size() * sizeof( bool ) );
- mGeometryDefinedH.resize( mItems.size() * sizeof( bool ) );
- mGeometryDefinedV.resize( mItems.size() * sizeof( bool ) );
- mItemsGeometry.resize( ( mItems.size() + 1 ) * sizeof( ItemGeometry ) );
+ mAnchorsVisited.resize( mResolvedAnchors.size() * sizeof( bool ) );
+ mGeometryDefinedH.resize( ( mActualItems.size() + 1 ) * sizeof( bool ) );
+ mGeometryDefinedV.resize( ( mActualItems.size() + 1 ) * sizeof( bool ) );
+ mItemsGeometry.resize( ( mActualItems.size() + 1 ) * sizeof( ItemGeometry ) );
if( type == Vertical ) {
mLayoutVarV = layoutVar;
@@ -1019,15 +1199,231 @@
}
}
+/*
+ Finds new end item for problematic anchor.
-/*!
- \internal
+ Follows the anchor that have the same start edge
+ as the problematic anchor.
+
+ Invariant:
+ \a ids must be the exactly same in return. It is the array
+ which nodes have already been visited - so in order to avoid
+ infinite recursion, don't visit already visited.
+*/
+bool HbAnchorLayoutPrivate::findEndItem(
+ QList<HbMeshEndItemResult> &resultList,
+ const HbAnchor *problem,
+ QStringList &ids) const
+{
+ HbMeshEndItemResult result;
+ bool found = false;
+
+ for (QList<HbAnchor*>::const_iterator it = mAllAnchors.constBegin();
+ it != mAllAnchors.constEnd();
+ ++it) {
+
+ const HbAnchor* currentItem = *it;
+
+ if (!currentItem->mStartId.isNull() &&
+ currentItem->mStartId == problem->mEndId &&
+ currentItem->mStartEdge == problem->mStartEdge &&
+ !ids.contains(currentItem->mStartId)) {
+
+ qreal currentSpacing = currentItem->mValue;
+
+ QGraphicsLayoutItem *item = currentItem->mEndItem;
+
+
+ if (item) {
+ found = true;
+ result.mEdge = currentItem->mEndEdge;
+ result.mItem = item;
+ result.mValue = currentSpacing;
+ resultList.append( result );
+ } else {
+ ids.append(currentItem->mStartId);
+ found |= findEndItem(resultList, currentItem, ids);
+ ids.takeLast();
+ }
+ /*
+ if (found) {
+ // We have found an end item. There can be multiple end items,
+ // but (for now) the first one is selected.
+ return true;
+ }*/
+ }
+ }
+
+ return found;
+}
+
+/*
+ Resolves anchors to be used in anchor layout calculations.
+
+ For each anchor x with start id, start edge, end id, end edge:
+
+ If there is layout items corresponding to both start id and end id,
+ anchor is used automatically.
+ If there is layout item corresponding to start id, then we try to
+ "fix" anchor by looking for a path of anchors (same direction, with spacing defined)
+ from anchor x's end id as starting point to such end id that has layout item.
+ If found, anchor is fixed by replacing end id with found end id.
+
+ So direction of anchors affect this resolution process, but not in the
+ anchor layout calculations.
+
+ \sa findEndItem
*/
-QList<HbAnchor*> HbAnchorLayoutDebug::getAnchors( HbAnchorLayout* layout )
+void HbAnchorLayoutPrivate::resolveAnchors()
+{
+ HbAnchor *item;
+
+ qDeleteAll( mResolvedDynamicAnchors );
+ mResolvedDynamicAnchors.clear();
+ mResolvedStaticAnchors.clear();
+
+ for ( int i = 0; i < mAllAnchors.size(); i++ ) {
+
+ HbAnchor *anchor = mAllAnchors.at(i);
+
+ if( ( anchor->mStartItem ) && ( anchor->mEndItem ) ) {
+ mResolvedStaticAnchors.append( anchor );
+ continue;
+ }
+
+ if (anchor->mStartItem && !anchor->mEndId.isNull()) {
+ QList<HbMeshEndItemResult> resultList;
+
+ QStringList ids;
+ ids.append(anchor->mStartId);
+
+ if (findEndItem(resultList, anchor, ids)) {
+ for( int j = 0; j < resultList.size(); j++ ) {
+ item = new HbAnchor();
+ item->mStartItem = anchor->mStartItem;
+ item->mStartId = anchor->mStartId;
+ item->mStartEdge = anchor->mStartEdge;
+ item->mEndEdge = resultList.at(j).mEdge;
+ item->mEndItem = resultList.at(j).mItem;
+ item->mValue = resultList.at(j).mValue;
+ mResolvedDynamicAnchors.append(item);
+ }
+ }
+ } else {
+ // Nothing needed.
+ }
+ }
+
+ mResolvedAnchors = mResolvedDynamicAnchors + mResolvedStaticAnchors;
+}
+
+bool HbAnchorLayoutPrivate::setAnchor( HbAnchor *anchor )
{
- return layout->d_ptr->mAnchors;
+ // This method is called from HbAnchorLayout::setAnchor.
+
+ if (HbAnchorLayoutPrivate::edgeType(anchor->mStartEdge) !=
+ HbAnchorLayoutPrivate::edgeType(anchor->mEndEdge)) {
+ qWarning() << "HbAnchorLayout::setAnchor : You can't connect different type of edges";
+ return false;
+ }
+
+ if ( ( anchor->mStartId.isNull() && ( anchor->mStartItem == 0 ) ) ||
+ ( anchor->mEndId.isNull() && ( anchor->mEndItem == 0 ) ) ){
+ qWarning() << "HbAnchorLayout::setAnchor : Both ids must be valid";
+ return false;
+ }
+
+ if ( ( anchor->mStartId == anchor->mEndId ) && ( ( anchor->mStartItem == anchor->mEndItem ) ) &&
+ ( anchor->mStartEdge == anchor->mEndEdge ) ) {
+ qWarning() << "HbAnchorLayout::setAnchor : You cannot set anchor between the same edge";
+ return false;
+ }
+
+ bool modified = false;
+
+ const int count = mAllAnchors.size();
+ for (int i = 0; i < count; ++i) {
+ HbAnchor *item = mAllAnchors.at(i);
+
+
+ bool idConditionStartStart = ( !item->mStartId.isNull() ) && ( item->mStartId == anchor->mStartId );
+ bool idConditionEndEnd = ( !item->mEndId.isNull() ) && ( item->mEndId == anchor->mEndId );
+ bool idConditionStartEnd = ( !item->mStartId.isNull() ) && ( item->mStartId == anchor->mEndId );
+ bool idConditionEndStart = ( !item->mEndId.isNull() ) && ( item->mEndId == anchor->mStartId );
+
+ bool itemConditionStartStart = ( item->mStartItem != 0 ) && ( item->mStartItem == anchor->mStartItem );
+ bool itemConditionEndEnd = ( item->mEndItem != 0 ) && ( item->mEndItem == anchor->mEndItem );
+ bool itemConditionStartEnd = ( item->mStartItem != 0 ) && ( item->mStartItem == anchor->mEndItem );
+ bool itemConditionEndStart = ( item->mEndItem != 0 ) && ( item->mEndItem == anchor->mStartItem );
+
+ bool edgeConditionStartStart = item->mStartEdge == anchor->mStartEdge;
+ bool edgeConditionEndEnd = item->mEndEdge == anchor->mEndEdge;
+ bool edgeConditionStartEnd = item->mStartEdge == anchor->mEndEdge;
+ bool edgeConditionEndStart = item->mEndEdge == anchor->mStartEdge;
+
+
+ if((idConditionStartStart || itemConditionStartStart) &&
+ (idConditionEndEnd || itemConditionEndEnd) &&
+ (edgeConditionStartStart) &&
+ (edgeConditionEndEnd) ){
+ modified = true;
+ item->mValue = anchor->mValue;
+ delete anchor;
+ break;
+ } else if( (idConditionStartEnd || itemConditionStartEnd) &&
+ (idConditionEndStart || itemConditionEndStart) &&
+ (edgeConditionStartEnd) &&
+ (edgeConditionEndStart) ){
+ modified = true;
+ item->mValue = -anchor->mValue;
+ delete anchor;
+ break;
+ }
+ }
+
+ if (!modified) {
+ if( anchor->mStartItem != 0 ){
+ anchor->mStartId = mMeshMap.value( anchor->mStartItem );
+ } else if( ! anchor->mStartId.isNull() ) {
+ anchor->mStartItem = mMeshMap.key( anchor->mStartId );
+ }
+
+ if( anchor->mEndItem != 0 ){
+ anchor->mEndId = mMeshMap.value( anchor->mEndItem );
+ } else if( ! anchor->mEndId.isNull() ) {
+ anchor->mEndItem = mMeshMap.key( anchor->mEndId );
+ }
+
+ addItemIfNeeded( anchor->mStartItem );
+ addItemIfNeeded( anchor->mEndItem );
+
+ mAllAnchors.append(anchor);
+ }
+
+ return true;
}
+void HbAnchorLayoutPrivate::removeItemIfNeeded( QGraphicsLayoutItem *item )
+{
+ Q_Q( HbAnchorLayout );
+
+ if( ( item == 0 ) || ( item == q ) ) {
+ return;
+ }
+
+ for ( int i = 0; i < mAllAnchors.size(); i++ ) {
+ HbAnchor *anchor = mAllAnchors.at(i);
+ if ( ( anchor->mStartItem == item ) || ( anchor->mEndItem == item ) ) {
+ return;
+ }
+ }
+
+ item->setParentLayoutItem( 0 );
+ mItems.removeAt(q->indexOf( item ));
+}
+
+
+
/*!
Constructor.
*/
@@ -1062,6 +1458,7 @@
delete d_ptr;
}
+
/*!
Creates an anchor, or updates an existing one, between the edges described by
(\a startItem, \a startEdge) and (\a endItem, \a endEdge).
@@ -1071,9 +1468,9 @@
That is, it is not allowed to connect e.g. top edge of an item to the
left edge of another one. Also there are horizontal and vertical center edges.
- The distance between the two edges is defined by \a value.
- If \a value is positive the end edge is to the right or below the start edge.
- If \a value is negative the end edge is to the left or above the start edge.
+ The distance between the two edges is defined by \a length.
+ If \a length is positive the end edge is to the right or below the start edge.
+ If \a length is negative the end edge is to the left or above the start edge.
Anchors can be created between the parent layout and a child layout item,
or between two child layout items, or even between two edges of the same
@@ -1092,48 +1489,95 @@
\param startEdge source edge.
\param endItem target item.
\param endEdge target edge.
- \param value spacing (in pixels).
+ \param length spacing (in pixels).
\return true if anchor was successfully added, false otherwise
*/
-bool HbAnchorLayout::setAnchor( QGraphicsLayoutItem *startItem,
- Hb::Edge startEdge,
- QGraphicsLayoutItem *endItem,
- Hb::Edge endEdge,
- qreal value )
+bool HbAnchorLayout::setAnchor( QGraphicsLayoutItem *startItem, Edge startEdge, QGraphicsLayoutItem *endItem, Edge endEdge, qreal length )
{
Q_D( HbAnchorLayout );
- if ( d->edgeType(startEdge) != d->edgeType(endEdge) ) {
- qWarning() << "HbAnchorLayout::setAnchor : You can't connect different type of edges";
- return false;
- }
- if ( !startItem || !endItem ) {
- qWarning() << "HbAnchorLayout::setAnchor : One of the items is NULL";
- return false;
+ HbAnchor *anchor = new HbAnchor();
+ anchor->mStartItem = startItem;
+ anchor->mStartEdge = startEdge;
+ anchor->mEndItem = endItem;
+ anchor->mEndEdge = endEdge;
+ anchor->mValue = length;
+
+ if (d->setAnchor(anchor)) {
+ invalidate();
+ return true;
}
- if ( ( startItem == endItem ) && ( startEdge == endEdge ) ) {
- qWarning() << "HbAnchorLayout::setAnchor : You cannot set anchor between the same edge";
- return false;
+ delete anchor;
+
+ return false;
+}
+
+/*!
+ Same as previous, but here it operates with node ids, instead of items itself.
+
+ \param startId start id.
+ \param startEdge start edge.
+ \param endId end id.
+ \param endEdge end edge.
+ \param length spacing value for all edges starting from (\a startId, \a startEdge).
+ \return true if success, false otherwise.
+*/
+bool HbAnchorLayout::setAnchor( const QString& startId, Edge startEdge, const QString& endId, Edge endEdge, qreal length )
+{
+ Q_D( HbAnchorLayout );
+
+ HbAnchor *anchor = new HbAnchor();
+ anchor->mStartId = startId;
+ anchor->mStartEdge = startEdge;
+ anchor->mEndId = endId;
+ anchor->mEndEdge = endEdge;
+ anchor->mValue = length;
+
+ if (d->setAnchor(anchor)) {
+ invalidate();
+ return true;
}
- d->addItemIfNeeded(startItem);
- d->addItemIfNeeded(endItem);
+ delete anchor;
- HbAnchor* anchor = d->getAnchor(startItem, startEdge, endItem, endEdge);
- HbAnchor* anchor2 = d->getAnchor(endItem, endEdge, startItem, startEdge);
+ return false;
+}
+
+
+/*!
+ Removes anchor (\a startId, \a startEdge, \a endNodeId, \a endEdge).
- if ( anchor ) {
- anchor->mValue = value;
- } else if ( anchor2 ) {
- anchor2->mValue = -value;
- } else {
- anchor = new HbAnchor(startItem, startEdge, endItem, endEdge, value);
- d->mAnchors.append(anchor);
+ \param startId start id.
+ \param startEdge start edge.
+ \param endId end id.
+ \param endEdge end edge.
+ \return true if success, false otherwise.
+*/
+bool HbAnchorLayout::removeAnchor( const QString& startNodeId, Edge startEdge, const QString& endNodeId, Edge endEdge )
+{
+ Q_D( HbAnchorLayout );
+ bool modified = false;
+
+ for (int i = d->mAllAnchors.size() - 1; i >= 0; --i) {
+ HbAnchor* anchor = d->mAllAnchors[i];
+ if( ( anchor->mStartId == startNodeId && anchor->mStartEdge == startEdge &&
+ anchor->mEndId == endNodeId && anchor->mEndEdge == endEdge ) ||
+ ( anchor->mStartId == endNodeId && anchor->mStartEdge == endEdge &&
+ anchor->mEndId == startNodeId && anchor->mEndEdge == startEdge ) ){
+ delete d->mAllAnchors.takeAt(i);
+ modified = true;
+ break;
+ }
}
- invalidate();
- return true;
+ if (modified) {
+ d->removeItemIfNeeded( d->mMeshMap.key( startNodeId ) );
+ d->removeItemIfNeeded( d->mMeshMap.key( endNodeId ) );
+ invalidate();
+ return true;
+ }
+ return false;
}
/*!
@@ -1150,95 +1594,284 @@
\param edge2 second edge.
\return true if anchor was successfully removed, false otherwise
*/
-bool HbAnchorLayout::removeAnchor( QGraphicsLayoutItem *item1,
- Hb::Edge edge1,
- QGraphicsLayoutItem *item2,
- Hb::Edge edge2 )
+bool HbAnchorLayout::removeAnchor( QGraphicsLayoutItem *startItem, Edge startEdge, QGraphicsLayoutItem *endItem, Edge endEdge )
+{
+ Q_D( HbAnchorLayout );
+ bool modified = false;
+
+ for (int i = d->mAllAnchors.size() - 1; i >= 0; --i) {
+ HbAnchor* anchor = d->mAllAnchors[i];
+ if( ( anchor->mStartItem == startItem && anchor->mStartEdge == startEdge &&
+ anchor->mEndItem == endItem && anchor->mEndEdge == endEdge ) ||
+ ( anchor->mStartItem == endItem && anchor->mStartEdge == endEdge &&
+ anchor->mEndItem == startItem && anchor->mEndEdge == startEdge ) ){
+ delete d->mAllAnchors.takeAt(i);
+ modified = true;
+ break;
+ }
+ }
+
+ if (modified) {
+ d->removeItemIfNeeded( startItem );
+ d->removeItemIfNeeded( endItem );
+ invalidate();
+ return true;
+ }
+ return false;
+}
+
+
+
+/*!
+ Removes all anchors starting or ending to \a nodeId.
+ Same is done with associated item
+
+ \param id id to be removed.
+ \return true if success, false otherwise.
+*/
+bool HbAnchorLayout::removeNodeId( const QString& nodeId )
{
Q_D( HbAnchorLayout );
- HbAnchor *anchor = d->getAnchor( item1, edge1, item2, edge2 );
- if( !anchor ) {
- anchor = d->getAnchor( item2, edge2, item1, edge1 );
- }
- if ( anchor ) {
- d->mAnchors.removeAll( anchor );
+ bool modified = false;
+
+ // if association, do removal
+
+ for (int i = d->mAllAnchors.size() - 1; i >= 0; --i) {
+ HbAnchor *anchor = d->mAllAnchors.at(i);
+ if (anchor->mStartId == nodeId || anchor->mEndId == nodeId) {
+ QGraphicsLayoutItem *startItem = anchor->mStartItem;
+ QGraphicsLayoutItem *endItem = anchor->mEndItem;
- // Remove non-anchored items
- bool startFound = false;
- bool endFound = false;
- for ( int i = d->mAnchors.count() - 1; i >= 0; i-- ) {
- if ( d->mAnchors.at(i)->mStartItem == item1 ||
- d->mAnchors.at(i)->mEndItem == item1 ) {
- startFound = true;
- }
- if ( d->mAnchors.at(i)->mStartItem == item2 ||
- d->mAnchors.at(i)->mEndItem == item2 ) {
- endFound = true;
- }
+ delete d->mAllAnchors.takeAt(i);
+ d->removeItemIfNeeded( startItem );
+ d->removeItemIfNeeded( endItem );
+
+ modified = true;
}
- if ( !startFound && item1 != this ) {
- item1->setParentLayoutItem( 0 );
- d->mItems.removeAt(indexOf(item1));
- }
- if ( !endFound && item2 != this) {
- item2->setParentLayoutItem( 0 );
- d->mItems.removeAt(indexOf(item2));
- }
- delete anchor;
+ }
+
+ removeMapping( nodeId );
+
+ if (modified) {
invalidate();
return true;
- } else {
- return false;
+ }
+ return false;
+}
+
+/*!
+ Clears all anchors.
+ Note that this does not affect on mappings.
+*/
+void HbAnchorLayout::removeAnchors()
+{
+ Q_D( HbAnchorLayout );
+
+ if( d->mAllAnchors.size() ) {
+ qDeleteAll( d->mResolvedDynamicAnchors );
+ qDeleteAll( d->mAllAnchors );
+ d->mResolvedDynamicAnchors.clear();
+ d->mResolvedStaticAnchors.clear();
+ d->mResolvedAnchors.clear();
+ d->mAllAnchors.clear();
+ invalidate();
}
}
/*!
- From QGraphicsLayoutItem.
- Sets the geometry of all the child items of this layout.
-
- In case the layout is not valid geometry will not be set
- to any of the child items.
-
- \param rect rectangle for this layout.
- \sa isValid
+ Sets identifier for \a item.
+ \param item layout item.
+ \param nodeId new id corresponding to \a item.
+ \return true if success, false otherwise.
*/
-void HbAnchorLayout::setGeometry(const QRectF &rect)
+bool HbAnchorLayout::setMapping( QGraphicsLayoutItem *item, const QString& nodeId )
{
Q_D( HbAnchorLayout );
- QGraphicsLayout::setGeometry(rect);
- d->setItemGeometries();
- d->mInvalidateCalled = false;
+ bool modified = false;
+
+ if ( !nodeId.isNull() && ( item != 0 ) ) {
+
+ for( int i = 0; i < d->mAllAnchors.size(); i++ ) {
+ HbAnchor *anchor = d->mAllAnchors.at(i);
+ if( anchor->mStartItem == item ) {
+ anchor->mStartId = nodeId;
+ modified = true;
+ } else if( anchor->mStartId == nodeId ) {
+ anchor->mStartItem = item;
+ modified = true;
+ }
+
+ if( anchor->mEndItem == item ) {
+ anchor->mEndId = nodeId;
+ modified = true;
+ } else if( anchor->mEndId == nodeId ) {
+ anchor->mEndItem = item;
+ modified = true;
+ }
+
+ }
+
+ // Remove previous item -> id.
+ HbMeshItemMapIterator it = d->mMeshMap.begin();
+ while ( it != d->mMeshMap.end() ) {
+ if ( it.value() == nodeId ) {
+ it = d->mMeshMap.erase( it );
+ } else {
+ ++it;
+ }
+ }
+ d->addItemIfNeeded( item );
+ d->mMeshMap.insert( item, nodeId );
+ } else {
+ return false;
+ }
+
+ if( modified ){
+ invalidate();
+ }
+ return true;
+}
+
+/*!
+ Resets mapping for \a item. All anchors are updated after that.
+
+ item <=> "someId" ----> item <=> null
+
+ \param item layout item.
+ \return true if success, false otherwise.
+*/
+bool HbAnchorLayout::removeMapping( QGraphicsLayoutItem *item )
+{
+ Q_D( HbAnchorLayout );
+
+ bool modified = false;
+
+ if( ! item ) {
+ return false;
+ }
+
+ for( int i = 0; i < d->mAllAnchors.size(); i++ ) {
+ HbAnchor *anchor = d->mAllAnchors.at(i);
+
+ if( anchor->mStartItem == item ) {
+ anchor->mStartId = QString();
+ modified = true;
+ }
+
+ if( anchor->mEndItem == item ) {
+ anchor->mEndId = QString();
+ modified = true;
+ }
+ }
+
+
+ d->mMeshMap.remove(item);
+
+ if( modified ){
+ invalidate();
+ }
+ return true;
}
/*!
- From QGraphicsLayoutItem.
- Removes the item at index, \a index, without destroying it.
+ Resets mapping for \a nodeId. All anchors are updated after that.
+
+ item <=> "nodeId" ----> 0 <=> "nodeId"
- Removes all the anchors connected to the removed item.
-
- \param index index of item to be removed.
+ \param nodeId node id
+ \return true if success, false otherwise.
*/
-void HbAnchorLayout::removeAt(int index)
+bool HbAnchorLayout::removeMapping( const QString& nodeId )
{
Q_D( HbAnchorLayout );
- if ( index < 0 || index > d->mItems.count()-1 ) {
+
+ bool modified = false;
+
+ if( nodeId.isNull() ) {
+ return false;
+ }
+
+ for( int i = 0; i < d->mAllAnchors.size(); i++ ) {
+ HbAnchor *anchor = d->mAllAnchors.at(i);
+
+ if( anchor->mStartId == nodeId ) {
+ anchor->mStartItem = 0;
+ modified = true;
+ }
+
+ if( anchor->mEndId == nodeId ) {
+ anchor->mEndItem = 0;
+ modified = true;
+ }
+ }
+
+
+ HbMeshItemMapIterator it = d->mMeshMap.begin();
+ while ( it != d->mMeshMap.end() ) {
+ if ( it.value() == nodeId ) {
+ it = d->mMeshMap.erase( it );
+ } else {
+ ++it;
+ }
+ }
+
+ if( modified ){
+ invalidate();
+ }
+ return true;
+}
+
+
+/*!
+ Clears all item id mappings.
+*/
+void HbAnchorLayout::removeMappings()
+{
+ Q_D( HbAnchorLayout );
+ d->mMeshMap.clear();
+
+ for( int i = 0; i < d->mAllAnchors.size(); i++ ) {
+ HbAnchor *anchor = d->mAllAnchors.at(i);
+
+ if( !anchor->mStartId.isNull() ) {
+ anchor->mStartItem = 0;
+ }
+
+ if( !anchor->mEndId.isNull() ) {
+ anchor->mEndItem = 0;
+ }
+
+ }
+}
+
+/*!
+ Adds \a item.
+
+ \param item item to be added.
+ \param id id of this item.
+*/
+void HbAnchorLayoutPrivate::addItemIfNeeded(QGraphicsLayoutItem *item)
+{
+ Q_Q(HbAnchorLayout);
+
+ if (!item) {
+ //qWarning() << "HbAnchorLayout::addItemIfNeeded : item is NULL";
return;
}
- QGraphicsLayoutItem *item = itemAt( index );
- if ( item ) {
- for ( int i = d->mAnchors.count() - 1; i >= 0; i-- ) {
- if ( d->mAnchors.at(i)->mStartItem == item ||
- d->mAnchors.at(i)->mEndItem == item ) {
- d->mAnchors.removeAt(i);
- }
- }
- item->setParentLayoutItem( 0 );
- d->mItems.removeAt(index);
+ if (item == q) {
+ //qWarning() << "HbAnchorLayout::addItemIfNeeded : layout cannot be added";
+ return;
}
- invalidate();
+ if (mItems.contains(item)) {
+ //qWarning() << "HbAnchorLayout::addItemIfNeeded : item is already in layout";
+ return;
+ }
+
+ HbLayoutUtils::addChildItem(q, item);
+ mItems.append(item);
}
/*!
@@ -1247,35 +1880,12 @@
\param item item to be removed.
*/
-void HbAnchorLayout::removeItem(QGraphicsLayoutItem* item)
+void HbAnchorLayout::removeItem(QGraphicsLayoutItem *item)
{
removeAt(indexOf(item));
}
/*!
- From QGraphicsLayoutItem.
- Returns the count of the child items in anchor layout.
- \return amount of items in this layout.
-*/
-int HbAnchorLayout::count() const
-{
- Q_D( const HbAnchorLayout );
- return d->mItems.count();
-}
-
-/*!
- From QGraphicsLayoutItem.
- Returns a pointer to the item at an index \a index.
- \param index position of desired item.
- \return item at specified index.
-*/
-QGraphicsLayoutItem *HbAnchorLayout::itemAt(int index) const
-{
- Q_D( const HbAnchorLayout );
- return d->mItems.value(index);
-}
-
-/*!
Returns the index of given layout \a item, or -1 if not found.
\param item item to look for.
\return index of item or -1 if not found.
@@ -1283,8 +1893,8 @@
int HbAnchorLayout::indexOf(const QGraphicsLayoutItem* item) const
{
Q_D( const HbAnchorLayout );
- for ( int i=0; i< d->mItems.count(); i++) {
- if ( d->mItems.at(i) == item ) {
+ for (int i=0; i < d->mItems.count(); i++) {
+ if (d->mItems.at(i) == item) {
return i;
}
}
@@ -1303,14 +1913,117 @@
return ( d->mValid && ( ! d->mWrongAnchors ) );
}
+
/*!
- From QGraphicsLayoutItem.
+ Returns node id for given item, or default constructed string if no mapping exist.
+ \param item item to check.
+ \return node id for given item.
+*/
+QString HbAnchorLayout::nodeId( QGraphicsLayoutItem *item ) const
+{
+ Q_D( const HbAnchorLayout );
+ if( d->mMeshMap.contains( item ) ) {
+ return d->mMeshMap.value( item );
+ }
+ return QString();
+}
+
+/*!
+ Returns list of node ids that are mentioned in anchors list.
+ \return list of node ids.
+*/
+QStringList HbAnchorLayout::nodeIds() const
+{
+ Q_D( const HbAnchorLayout );
+ QStringList list;
+ int c = d->mAllAnchors.count();
+ while (c--) {
+ QString id = d->mAllAnchors.at(c)->mStartId;
+ if (!list.contains(id) && !id.isNull()) {
+ list.append(id);
+ }
+ id = d->mAllAnchors.at(c)->mEndId;
+ if (!list.contains(id) && !id.isNull()) {
+ list.append(id);
+ }
+ }
+ return list;
+}
+
+/*!
+ Returns item reference for given node id, or zero if no mapping exist.
+ \param nodeId node id to check.
+ \return item reference for given item.
+*/
+QGraphicsLayoutItem *HbAnchorLayout::itemByNodeId( const QString& nodeId ) const
+{
+ Q_D( const HbAnchorLayout );
+ return d->mMeshMap.key( nodeId );
+}
+
+
+/*!
+ \reimp
+*/
+void HbAnchorLayout::removeAt(int index)
+{
+ Q_D( HbAnchorLayout );
+ if ( index < 0 || index > d->mItems.count()-1 ) {
+ return;
+ }
+ QGraphicsLayoutItem *item = itemAt( index );
+ if ( item ) {
+ for ( int i = d->mAllAnchors.count() - 1; i >= 0; i-- ) {
+ if ( ( ( d->mAllAnchors.at(i)->mStartItem == item ) && ( d->mAllAnchors.at(i)->mStartId.isNull() ) ) ||
+ ( ( d->mAllAnchors.at(i)->mEndItem == item ) && ( d->mAllAnchors.at(i)->mEndId.isNull() ) ) ) {
+ delete d->mAllAnchors.takeAt(i);
+ }
+ }
+
+ removeMapping( d->mMeshMap.value(item) );
+ item->setParentLayoutItem( 0 );
+ d->mItems.removeAt( index );
+ }
+
+ invalidate();
+}
+
+/*!
+ \reimp
+*/
+void HbAnchorLayout::setGeometry(const QRectF &rect)
+{
+ Q_D( HbAnchorLayout );
+ QGraphicsLayout::setGeometry(rect);
+ d->setItemGeometries();
+}
+
+/*!
+ \reimp
+*/
+int HbAnchorLayout::count() const
+{
+ Q_D( const HbAnchorLayout );
+ return d->mItems.count();
+}
+
+/*!
+ \reimp
+*/
+QGraphicsLayoutItem *HbAnchorLayout::itemAt(int index) const
+{
+ Q_D( const HbAnchorLayout );
+ return d->mItems.value(index);
+}
+
+/*!
+ \reimp
*/
void HbAnchorLayout::invalidate()
{
Q_D( HbAnchorLayout );
+ d->mInvalidateCalled = true;
d->mWrongAnchors = false;
- d->mInvalidateCalled = true;
d->mEquationsDirty = true;
QGraphicsLayout::invalidate();
}
@@ -1322,9 +2035,8 @@
{
QGraphicsLayout::widgetEvent(e);
}
-
/*!
- From QGraphicsLayoutItem. If size hint for certain set of items cannot be defined,
+ From QGraphicsLayoutItem. If size hint for certain set of items cannot be defined,
then it returns default size hint (0/100/1000)
\param which desired size hint.
\param constraint optional constraint.
@@ -1338,15 +2050,15 @@
return const_cast<HbAnchorLayoutPrivate*>(d)->sizeHint( which );
}
-QSizeF HbAnchorLayoutPrivate::sizeHint( Qt::SizeHint which )
+QSizeF HbAnchorLayoutPrivate::sizeHint(Qt::SizeHint which)
{
if ( mEquationsDirty ) {
- mEquationsDirty = false;
+ updateAnchorsAndItems();
createEquations( Horizontal );
createEquations( Vertical );
+ mEquationsDirty = false;
}
-
if( mLayoutVarH && mLayoutVarV ) {
QSizeF res;
@@ -1386,4 +2098,3 @@
}
}
}
-