f139821d9217f81b2556cb6ea82552039dbee2da
[profile/ivi/qtdeclarative.git] / src / quick / items / qquickanchors.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickanchors_p_p.h"
43
44 #include "qquickitem.h"
45 #include "qquickitem_p.h"
46
47 #include <qdeclarativeinfo.h>
48
49 QT_BEGIN_NAMESPACE
50
51 //TODO: should we cache relationships, so we don't have to check each time (parent-child or sibling)?
52 //TODO: support non-parent, non-sibling (need to find lowest common ancestor)
53
54 static qreal hcenter(QQuickItem *item)
55 {
56     qreal width = item->width();
57     int iw = width;
58     if (iw % 2)
59         return (width + 1) / 2;
60     else
61         return width / 2;
62 }
63
64 static qreal vcenter(QQuickItem *item)
65 {
66     qreal height = item->height();
67     int ih = height;
68     if (ih % 2)
69         return (height + 1) / 2;
70     else
71         return height / 2;
72 }
73
74 //### const item?
75 //local position
76 static qreal position(QQuickItem *item, QQuickAnchorLine::AnchorLine anchorLine)
77 {
78     qreal ret = 0.0;
79     switch (anchorLine) {
80     case QQuickAnchorLine::Left:
81         ret = item->x();
82         break;
83     case QQuickAnchorLine::Right:
84         ret = item->x() + item->width();
85         break;
86     case QQuickAnchorLine::Top:
87         ret = item->y();
88         break;
89     case QQuickAnchorLine::Bottom:
90         ret = item->y() + item->height();
91         break;
92     case QQuickAnchorLine::HCenter:
93         ret = item->x() + hcenter(item);
94         break;
95     case QQuickAnchorLine::VCenter:
96         ret = item->y() + vcenter(item);
97         break;
98     case QQuickAnchorLine::Baseline:
99         ret = item->y() + item->baselineOffset();
100         break;
101     default:
102         break;
103     }
104
105     return ret;
106 }
107
108 //position when origin is 0,0
109 static qreal adjustedPosition(QQuickItem *item, QQuickAnchorLine::AnchorLine anchorLine)
110 {
111     qreal ret = 0.0;
112     switch (anchorLine) {
113     case QQuickAnchorLine::Left:
114         ret = 0.0;
115         break;
116     case QQuickAnchorLine::Right:
117         ret = item->width();
118         break;
119     case QQuickAnchorLine::Top:
120         ret = 0.0;
121         break;
122     case QQuickAnchorLine::Bottom:
123         ret = item->height();
124         break;
125     case QQuickAnchorLine::HCenter:
126         ret = hcenter(item);
127         break;
128     case QQuickAnchorLine::VCenter:
129         ret = vcenter(item);
130         break;
131     case QQuickAnchorLine::Baseline:
132         ret = item->baselineOffset();
133         break;
134     default:
135         break;
136     }
137
138     return ret;
139 }
140
141 QQuickAnchors::QQuickAnchors(QQuickItem *item, QObject *parent)
142 : QObject(*new QQuickAnchorsPrivate(item), parent)
143 {
144 }
145
146 QQuickAnchors::~QQuickAnchors()
147 {
148     Q_D(QQuickAnchors);
149     d->inDestructor = true;
150     d->remDepend(d->fill);
151     d->remDepend(d->centerIn);
152     d->remDepend(d->left.item);
153     d->remDepend(d->right.item);
154     d->remDepend(d->top.item);
155     d->remDepend(d->bottom.item);
156     d->remDepend(d->vCenter.item);
157     d->remDepend(d->hCenter.item);
158     d->remDepend(d->baseline.item);
159 }
160
161 void QQuickAnchorsPrivate::fillChanged()
162 {
163     Q_Q(QQuickAnchors);
164     if (!fill || !isItemComplete())
165         return;
166
167     if (updatingFill < 2) {
168         ++updatingFill;
169
170         qreal horizontalMargin = q->mirrored() ? rightMargin : leftMargin;
171
172         if (fill == item->parentItem()) {                         //child-parent
173             setItemPos(QPointF(horizontalMargin, topMargin));
174         } else if (fill->parentItem() == item->parentItem()) {   //siblings
175             setItemPos(QPointF(fill->x()+horizontalMargin, fill->y()+topMargin));
176         }
177         setItemSize(QSizeF(fill->width()-leftMargin-rightMargin, fill->height()-topMargin-bottomMargin));
178
179         --updatingFill;
180     } else {
181         // ### Make this certain :)
182         qmlInfo(item) << QQuickAnchors::tr("Possible anchor loop detected on fill.");
183     }
184
185 }
186
187 void QQuickAnchorsPrivate::centerInChanged()
188 {
189     Q_Q(QQuickAnchors);
190     if (!centerIn || fill || !isItemComplete())
191         return;
192
193     if (updatingCenterIn < 2) {
194         ++updatingCenterIn;
195
196         qreal effectiveHCenterOffset = q->mirrored() ? -hCenterOffset : hCenterOffset;
197         if (centerIn == item->parentItem()) {
198             QPointF p(hcenter(item->parentItem()) - hcenter(item) + effectiveHCenterOffset,
199                       vcenter(item->parentItem()) - vcenter(item) + vCenterOffset);
200             setItemPos(p);
201
202         } else if (centerIn->parentItem() == item->parentItem()) {
203             QPointF p(centerIn->x() + hcenter(centerIn) - hcenter(item) + effectiveHCenterOffset,
204                       centerIn->y() + vcenter(centerIn) - vcenter(item) + vCenterOffset);
205             setItemPos(p);
206         }
207
208         --updatingCenterIn;
209     } else {
210         // ### Make this certain :)
211         qmlInfo(item) << QQuickAnchors::tr("Possible anchor loop detected on centerIn.");
212     }
213 }
214
215 void QQuickAnchorsPrivate::clearItem(QQuickItem *item)
216 {
217     if (!item)
218         return;
219     if (fill == item)
220         fill = 0;
221     if (centerIn == item)
222         centerIn = 0;
223     if (left.item == item) {
224         left.item = 0;
225         usedAnchors &= ~QQuickAnchors::LeftAnchor;
226     }
227     if (right.item == item) {
228         right.item = 0;
229         usedAnchors &= ~QQuickAnchors::RightAnchor;
230     }
231     if (top.item == item) {
232         top.item = 0;
233         usedAnchors &= ~QQuickAnchors::TopAnchor;
234     }
235     if (bottom.item == item) {
236         bottom.item = 0;
237         usedAnchors &= ~QQuickAnchors::BottomAnchor;
238     }
239     if (vCenter.item == item) {
240         vCenter.item = 0;
241         usedAnchors &= ~QQuickAnchors::VCenterAnchor;
242     }
243     if (hCenter.item == item) {
244         hCenter.item = 0;
245         usedAnchors &= ~QQuickAnchors::HCenterAnchor;
246     }
247     if (baseline.item == item) {
248         baseline.item = 0;
249         usedAnchors &= ~QQuickAnchors::BaselineAnchor;
250     }
251 }
252
253 int QQuickAnchorsPrivate::calculateDependency(QQuickItem *controlItem)
254 {
255     QQuickItemPrivate::GeometryChangeTypes dependency = QQuickItemPrivate::NoChange;
256
257     if (!controlItem || inDestructor)
258         return dependency;
259
260     if (fill == controlItem) {
261         if ((controlItem == item->parentItem()))
262             dependency |= QQuickItemPrivate::SizeChange;
263         else    //sibling
264             dependency |= QQuickItemPrivate::GeometryChange;
265         return dependency;  //exit early
266     }
267
268     if (centerIn == controlItem) {
269         if ((controlItem == item->parentItem()))
270             dependency |= QQuickItemPrivate::SizeChange;
271         else    //sibling
272             dependency |= QQuickItemPrivate::GeometryChange;
273         return dependency;  //exit early
274     }
275
276     if ((usedAnchors & QQuickAnchors::LeftAnchor && left.item == controlItem) ||
277         (usedAnchors & QQuickAnchors::RightAnchor && right.item == controlItem) ||
278         (usedAnchors & QQuickAnchors::HCenterAnchor && hCenter.item == controlItem)) {
279         if ((controlItem == item->parentItem()))
280             dependency |= QQuickItemPrivate::WidthChange;
281         else    //sibling
282             dependency |= QFlags<QQuickItemPrivate::GeometryChangeType>(QQuickItemPrivate::XChange | QQuickItemPrivate::WidthChange);
283     }
284
285     if ((usedAnchors & QQuickAnchors::TopAnchor && top.item == controlItem) ||
286         (usedAnchors & QQuickAnchors::BottomAnchor && bottom.item == controlItem) ||
287         (usedAnchors & QQuickAnchors::VCenterAnchor && vCenter.item == controlItem) ||
288         (usedAnchors & QQuickAnchors::BaselineAnchor && baseline.item == controlItem)) {
289         if ((controlItem == item->parentItem()))
290             dependency |= QQuickItemPrivate::HeightChange;
291         else    //sibling
292             dependency |= QFlags<QQuickItemPrivate::GeometryChangeType>(QQuickItemPrivate::YChange | QQuickItemPrivate::HeightChange);
293     }
294
295     return dependency;
296 }
297
298 void QQuickAnchorsPrivate::addDepend(QQuickItem *item)
299 {
300     if (!item || !componentComplete)
301         return;
302
303     QQuickItemPrivate *p = QQuickItemPrivate::get(item);
304     p->updateOrAddGeometryChangeListener(this, QFlags<QQuickItemPrivate::GeometryChangeType>(calculateDependency(item)));
305 }
306
307 void QQuickAnchorsPrivate::remDepend(QQuickItem *item)
308 {
309     if (!item || !componentComplete)
310         return;
311
312     QQuickItemPrivate *p = QQuickItemPrivate::get(item);
313     p->updateOrRemoveGeometryChangeListener(this, QFlags<QQuickItemPrivate::GeometryChangeType>(calculateDependency(item)));
314 }
315
316 bool QQuickAnchors::mirrored()
317 {
318     Q_D(QQuickAnchors);
319     return QQuickItemPrivate::get(d->item)->effectiveLayoutMirror;
320 }
321
322 bool QQuickAnchorsPrivate::isItemComplete() const
323 {
324     return componentComplete;
325 }
326
327 void QQuickAnchors::classBegin()
328 {
329     Q_D(QQuickAnchors);
330     d->componentComplete = false;
331 }
332
333 void QQuickAnchors::componentComplete()
334 {
335     Q_D(QQuickAnchors);
336     d->componentComplete = true;
337 }
338
339 void QQuickAnchorsPrivate::setItemHeight(qreal v)
340 {
341     updatingMe = true;
342     item->setHeight(v);
343     updatingMe = false;
344 }
345
346 void QQuickAnchorsPrivate::setItemWidth(qreal v)
347 {
348     updatingMe = true;
349     item->setWidth(v);
350     updatingMe = false;
351 }
352
353 void QQuickAnchorsPrivate::setItemX(qreal v)
354 {
355     updatingMe = true;
356     item->setX(v);
357     updatingMe = false;
358 }
359
360 void QQuickAnchorsPrivate::setItemY(qreal v)
361 {
362     updatingMe = true;
363     item->setY(v);
364     updatingMe = false;
365 }
366
367 void QQuickAnchorsPrivate::setItemPos(const QPointF &v)
368 {
369     updatingMe = true;
370     item->setPos(v);
371     updatingMe = false;
372 }
373
374 void QQuickAnchorsPrivate::setItemSize(const QSizeF &v)
375 {
376     updatingMe = true;
377     item->setSize(v);
378     updatingMe = false;
379 }
380
381 void QQuickAnchorsPrivate::updateMe()
382 {
383     if (updatingMe) {
384         updatingMe = false;
385         return;
386     }
387
388     update();
389 }
390
391 void QQuickAnchorsPrivate::updateOnComplete()
392 {
393     //optimization to only set initial dependencies once, at completion time
394     QSet<QQuickItem *> dependencies;
395     dependencies << fill << centerIn
396                  << left.item << right.item << hCenter.item
397                  << top.item << bottom.item << vCenter.item << baseline.item;
398
399     foreach (QQuickItem *dependency, dependencies)
400         addDepend(dependency);
401
402     update();
403 }
404
405
406 void QQuickAnchorsPrivate::update()
407 {
408     fillChanged();
409     centerInChanged();
410     if (usedAnchors & QQuickAnchorLine::Horizontal_Mask)
411         updateHorizontalAnchors();
412     if (usedAnchors & QQuickAnchorLine::Vertical_Mask)
413         updateVerticalAnchors();
414 }
415
416 void QQuickAnchorsPrivate::itemGeometryChanged(QQuickItem *, const QRectF &newG, const QRectF &oldG)
417 {
418     fillChanged();
419     centerInChanged();
420     if ((usedAnchors & QQuickAnchorLine::Horizontal_Mask) && (newG.x() != oldG.x() || newG.width() != oldG.width()))
421         updateHorizontalAnchors();
422     if ((usedAnchors & QQuickAnchorLine::Vertical_Mask) && (newG.y() != oldG.y() || newG.height() != oldG.height()))
423         updateVerticalAnchors();
424 }
425
426 QQuickItem *QQuickAnchors::fill() const
427 {
428     Q_D(const QQuickAnchors);
429     return d->fill;
430 }
431
432 void QQuickAnchors::setFill(QQuickItem *f)
433 {
434     Q_D(QQuickAnchors);
435     if (d->fill == f)
436         return;
437
438     if (!f) {
439         QQuickItem *oldFill = d->fill;
440         d->fill = f;
441         d->remDepend(oldFill);
442         emit fillChanged();
443         return;
444     }
445     if (f != d->item->parentItem() && f->parentItem() != d->item->parentItem()){
446         qmlInfo(d->item) << tr("Cannot anchor to an item that isn't a parent or sibling.");
447         return;
448     }
449     QQuickItem *oldFill = d->fill;
450     d->fill = f;
451     d->remDepend(oldFill);
452     d->addDepend(d->fill);
453     emit fillChanged();
454     d->fillChanged();
455 }
456
457 void QQuickAnchors::resetFill()
458 {
459     setFill(0);
460 }
461
462 QQuickItem *QQuickAnchors::centerIn() const
463 {
464     Q_D(const QQuickAnchors);
465     return d->centerIn;
466 }
467
468 void QQuickAnchors::setCenterIn(QQuickItem* c)
469 {
470     Q_D(QQuickAnchors);
471     if (d->centerIn == c)
472         return;
473
474     if (!c) {
475         QQuickItem *oldCI = d->centerIn;
476         d->centerIn = c;
477         d->remDepend(oldCI);
478         emit centerInChanged();
479         return;
480     }
481     if (c != d->item->parentItem() && c->parentItem() != d->item->parentItem()){
482         qmlInfo(d->item) << tr("Cannot anchor to an item that isn't a parent or sibling.");
483         return;
484     }
485     QQuickItem *oldCI = d->centerIn;
486     d->centerIn = c;
487     d->remDepend(oldCI);
488     d->addDepend(d->centerIn);
489     emit centerInChanged();
490     d->centerInChanged();
491 }
492
493 void QQuickAnchors::resetCenterIn()
494 {
495     setCenterIn(0);
496 }
497
498 bool QQuickAnchorsPrivate::calcStretch(const QQuickAnchorLine &edge1,
499                                     const QQuickAnchorLine &edge2,
500                                     qreal offset1,
501                                     qreal offset2,
502                                     QQuickAnchorLine::AnchorLine line,
503                                     qreal &stretch)
504 {
505     bool edge1IsParent = (edge1.item == item->parentItem());
506     bool edge2IsParent = (edge2.item == item->parentItem());
507     bool edge1IsSibling = (edge1.item->parentItem() == item->parentItem());
508     bool edge2IsSibling = (edge2.item->parentItem() == item->parentItem());
509
510     bool invalid = false;
511     if ((edge2IsParent && edge1IsParent) || (edge2IsSibling && edge1IsSibling)) {
512         stretch = (position(edge2.item, edge2.anchorLine) + offset2)
513                     - (position(edge1.item, edge1.anchorLine) + offset1);
514     } else if (edge2IsParent && edge1IsSibling) {
515         stretch = (position(edge2.item, edge2.anchorLine) + offset2)
516                     - (position(item->parentItem(), line)
517                     + position(edge1.item, edge1.anchorLine) + offset1);
518     } else if (edge2IsSibling && edge1IsParent) {
519         stretch = (position(item->parentItem(), line) + position(edge2.item, edge2.anchorLine) + offset2)
520                     - (position(edge1.item, edge1.anchorLine) + offset1);
521     } else
522         invalid = true;
523
524     return invalid;
525 }
526
527 void QQuickAnchorsPrivate::updateVerticalAnchors()
528 {
529     if (fill || centerIn || !isItemComplete())
530         return;
531
532     if (updatingVerticalAnchor < 2) {
533         ++updatingVerticalAnchor;
534         if (usedAnchors & QQuickAnchors::TopAnchor) {
535             //Handle stretching
536             bool invalid = true;
537             qreal height = 0.0;
538             if (usedAnchors & QQuickAnchors::BottomAnchor) {
539                 invalid = calcStretch(top, bottom, topMargin, -bottomMargin, QQuickAnchorLine::Top, height);
540             } else if (usedAnchors & QQuickAnchors::VCenterAnchor) {
541                 invalid = calcStretch(top, vCenter, topMargin, vCenterOffset, QQuickAnchorLine::Top, height);
542                 height *= 2;
543             }
544             if (!invalid)
545                 setItemHeight(height);
546
547             //Handle top
548             if (top.item == item->parentItem()) {
549                 setItemY(adjustedPosition(top.item, top.anchorLine) + topMargin);
550             } else if (top.item->parentItem() == item->parentItem()) {
551                 setItemY(position(top.item, top.anchorLine) + topMargin);
552             }
553         } else if (usedAnchors & QQuickAnchors::BottomAnchor) {
554             //Handle stretching (top + bottom case is handled above)
555             if (usedAnchors & QQuickAnchors::VCenterAnchor) {
556                 qreal height = 0.0;
557                 bool invalid = calcStretch(vCenter, bottom, vCenterOffset, -bottomMargin,
558                                               QQuickAnchorLine::Top, height);
559                 if (!invalid)
560                     setItemHeight(height*2);
561             }
562
563             //Handle bottom
564             if (bottom.item == item->parentItem()) {
565                 setItemY(adjustedPosition(bottom.item, bottom.anchorLine) - item->height() - bottomMargin);
566             } else if (bottom.item->parentItem() == item->parentItem()) {
567                 setItemY(position(bottom.item, bottom.anchorLine) - item->height() - bottomMargin);
568             }
569         } else if (usedAnchors & QQuickAnchors::VCenterAnchor) {
570             //(stetching handled above)
571
572             //Handle vCenter
573             if (vCenter.item == item->parentItem()) {
574                 setItemY(adjustedPosition(vCenter.item, vCenter.anchorLine)
575                               - vcenter(item) + vCenterOffset);
576             } else if (vCenter.item->parentItem() == item->parentItem()) {
577                 setItemY(position(vCenter.item, vCenter.anchorLine) - vcenter(item) + vCenterOffset);
578             }
579         } else if (usedAnchors & QQuickAnchors::BaselineAnchor) {
580             //Handle baseline
581             if (baseline.item == item->parentItem()) {
582                 setItemY(adjustedPosition(baseline.item, baseline.anchorLine) - item->baselineOffset() + baselineOffset);
583             } else if (baseline.item->parentItem() == item->parentItem()) {
584                 setItemY(position(baseline.item, baseline.anchorLine) - item->baselineOffset() + baselineOffset);
585             }
586         }
587         --updatingVerticalAnchor;
588     } else {
589         // ### Make this certain :)
590         qmlInfo(item) << QQuickAnchors::tr("Possible anchor loop detected on vertical anchor.");
591     }
592 }
593
594 inline QQuickAnchorLine::AnchorLine reverseAnchorLine(QQuickAnchorLine::AnchorLine anchorLine)
595 {
596     if (anchorLine == QQuickAnchorLine::Left) {
597         return QQuickAnchorLine::Right;
598     } else if (anchorLine == QQuickAnchorLine::Right) {
599         return QQuickAnchorLine::Left;
600     } else {
601         return anchorLine;
602     }
603 }
604
605 void QQuickAnchorsPrivate::updateHorizontalAnchors()
606 {
607     Q_Q(QQuickAnchors);
608     if (fill || centerIn || !isItemComplete())
609         return;
610
611     if (updatingHorizontalAnchor < 3) {
612         ++updatingHorizontalAnchor;
613         qreal effectiveRightMargin, effectiveLeftMargin, effectiveHorizontalCenterOffset;
614         QQuickAnchorLine effectiveLeft, effectiveRight, effectiveHorizontalCenter;
615         QQuickAnchors::Anchor effectiveLeftAnchor, effectiveRightAnchor;
616         if (q->mirrored()) {
617             effectiveLeftAnchor = QQuickAnchors::RightAnchor;
618             effectiveRightAnchor = QQuickAnchors::LeftAnchor;
619             effectiveLeft.item = right.item;
620             effectiveLeft.anchorLine = reverseAnchorLine(right.anchorLine);
621             effectiveRight.item = left.item;
622             effectiveRight.anchorLine = reverseAnchorLine(left.anchorLine);
623             effectiveHorizontalCenter.item = hCenter.item;
624             effectiveHorizontalCenter.anchorLine = reverseAnchorLine(hCenter.anchorLine);
625             effectiveLeftMargin = rightMargin;
626             effectiveRightMargin = leftMargin;
627             effectiveHorizontalCenterOffset = -hCenterOffset;
628         } else {
629             effectiveLeftAnchor = QQuickAnchors::LeftAnchor;
630             effectiveRightAnchor = QQuickAnchors::RightAnchor;
631             effectiveLeft = left;
632             effectiveRight = right;
633             effectiveHorizontalCenter = hCenter;
634             effectiveLeftMargin = leftMargin;
635             effectiveRightMargin = rightMargin;
636             effectiveHorizontalCenterOffset = hCenterOffset;
637         }
638
639         if (usedAnchors & effectiveLeftAnchor) {
640             //Handle stretching
641             bool invalid = true;
642             qreal width = 0.0;
643             if (usedAnchors & effectiveRightAnchor) {
644                 invalid = calcStretch(effectiveLeft, effectiveRight, effectiveLeftMargin, -effectiveRightMargin, QQuickAnchorLine::Left, width);
645             } else if (usedAnchors & QQuickAnchors::HCenterAnchor) {
646                 invalid = calcStretch(effectiveLeft, effectiveHorizontalCenter, effectiveLeftMargin, effectiveHorizontalCenterOffset, QQuickAnchorLine::Left, width);
647                 width *= 2;
648             }
649             if (!invalid)
650                 setItemWidth(width);
651
652             //Handle left
653             if (effectiveLeft.item == item->parentItem()) {
654                 setItemX(adjustedPosition(effectiveLeft.item, effectiveLeft.anchorLine) + effectiveLeftMargin);
655             } else if (effectiveLeft.item->parentItem() == item->parentItem()) {
656                 setItemX(position(effectiveLeft.item, effectiveLeft.anchorLine) + effectiveLeftMargin);
657             }
658         } else if (usedAnchors & effectiveRightAnchor) {
659             //Handle stretching (left + right case is handled in updateLeftAnchor)
660             if (usedAnchors & QQuickAnchors::HCenterAnchor) {
661                 qreal width = 0.0;
662                 bool invalid = calcStretch(effectiveHorizontalCenter, effectiveRight, effectiveHorizontalCenterOffset, -effectiveRightMargin,
663                                               QQuickAnchorLine::Left, width);
664                 if (!invalid)
665                     setItemWidth(width*2);
666             }
667
668             //Handle right
669             if (effectiveRight.item == item->parentItem()) {
670                 setItemX(adjustedPosition(effectiveRight.item, effectiveRight.anchorLine) - item->width() - effectiveRightMargin);
671             } else if (effectiveRight.item->parentItem() == item->parentItem()) {
672                 setItemX(position(effectiveRight.item, effectiveRight.anchorLine) - item->width() - effectiveRightMargin);
673             }
674         } else if (usedAnchors & QQuickAnchors::HCenterAnchor) {
675             //Handle hCenter
676             if (effectiveHorizontalCenter.item == item->parentItem()) {
677                 setItemX(adjustedPosition(effectiveHorizontalCenter.item, effectiveHorizontalCenter.anchorLine) - hcenter(item) + effectiveHorizontalCenterOffset);
678             } else if (effectiveHorizontalCenter.item->parentItem() == item->parentItem()) {
679                 setItemX(position(effectiveHorizontalCenter.item, effectiveHorizontalCenter.anchorLine) - hcenter(item) + effectiveHorizontalCenterOffset);
680             }
681         }
682         --updatingHorizontalAnchor;
683     } else {
684         // ### Make this certain :)
685         qmlInfo(item) << QQuickAnchors::tr("Possible anchor loop detected on horizontal anchor.");
686     }
687 }
688
689 QQuickAnchorLine QQuickAnchors::top() const
690 {
691     Q_D(const QQuickAnchors);
692     return d->top;
693 }
694
695 void QQuickAnchors::setTop(const QQuickAnchorLine &edge)
696 {
697     Q_D(QQuickAnchors);
698     if (!d->checkVAnchorValid(edge) || d->top == edge)
699         return;
700
701     d->usedAnchors |= TopAnchor;
702
703     if (!d->checkVValid()) {
704         d->usedAnchors &= ~TopAnchor;
705         return;
706     }
707
708     QQuickItem *oldTop = d->top.item;
709     d->top = edge;
710     d->remDepend(oldTop);
711     d->addDepend(d->top.item);
712     emit topChanged();
713     d->updateVerticalAnchors();
714 }
715
716 void QQuickAnchors::resetTop()
717 {
718     Q_D(QQuickAnchors);
719     d->usedAnchors &= ~TopAnchor;
720     d->remDepend(d->top.item);
721     d->top = QQuickAnchorLine();
722     emit topChanged();
723     d->updateVerticalAnchors();
724 }
725
726 QQuickAnchorLine QQuickAnchors::bottom() const
727 {
728     Q_D(const QQuickAnchors);
729     return d->bottom;
730 }
731
732 void QQuickAnchors::setBottom(const QQuickAnchorLine &edge)
733 {
734     Q_D(QQuickAnchors);
735     if (!d->checkVAnchorValid(edge) || d->bottom == edge)
736         return;
737
738     d->usedAnchors |= BottomAnchor;
739
740     if (!d->checkVValid()) {
741         d->usedAnchors &= ~BottomAnchor;
742         return;
743     }
744
745     QQuickItem *oldBottom = d->bottom.item;
746     d->bottom = edge;
747     d->remDepend(oldBottom);
748     d->addDepend(d->bottom.item);
749     emit bottomChanged();
750     d->updateVerticalAnchors();
751 }
752
753 void QQuickAnchors::resetBottom()
754 {
755     Q_D(QQuickAnchors);
756     d->usedAnchors &= ~BottomAnchor;
757     d->remDepend(d->bottom.item);
758     d->bottom = QQuickAnchorLine();
759     emit bottomChanged();
760     d->updateVerticalAnchors();
761 }
762
763 QQuickAnchorLine QQuickAnchors::verticalCenter() const
764 {
765     Q_D(const QQuickAnchors);
766     return d->vCenter;
767 }
768
769 void QQuickAnchors::setVerticalCenter(const QQuickAnchorLine &edge)
770 {
771     Q_D(QQuickAnchors);
772     if (!d->checkVAnchorValid(edge) || d->vCenter == edge)
773         return;
774
775     d->usedAnchors |= VCenterAnchor;
776
777     if (!d->checkVValid()) {
778         d->usedAnchors &= ~VCenterAnchor;
779         return;
780     }
781
782     QQuickItem *oldVCenter = d->vCenter.item;
783     d->vCenter = edge;
784     d->remDepend(oldVCenter);
785     d->addDepend(d->vCenter.item);
786     emit verticalCenterChanged();
787     d->updateVerticalAnchors();
788 }
789
790 void QQuickAnchors::resetVerticalCenter()
791 {
792     Q_D(QQuickAnchors);
793     d->usedAnchors &= ~VCenterAnchor;
794     d->remDepend(d->vCenter.item);
795     d->vCenter = QQuickAnchorLine();
796     emit verticalCenterChanged();
797     d->updateVerticalAnchors();
798 }
799
800 QQuickAnchorLine QQuickAnchors::baseline() const
801 {
802     Q_D(const QQuickAnchors);
803     return d->baseline;
804 }
805
806 void QQuickAnchors::setBaseline(const QQuickAnchorLine &edge)
807 {
808     Q_D(QQuickAnchors);
809     if (!d->checkVAnchorValid(edge) || d->baseline == edge)
810         return;
811
812     d->usedAnchors |= BaselineAnchor;
813
814     if (!d->checkVValid()) {
815         d->usedAnchors &= ~BaselineAnchor;
816         return;
817     }
818
819     QQuickItem *oldBaseline = d->baseline.item;
820     d->baseline = edge;
821     d->remDepend(oldBaseline);
822     d->addDepend(d->baseline.item);
823     emit baselineChanged();
824     d->updateVerticalAnchors();
825 }
826
827 void QQuickAnchors::resetBaseline()
828 {
829     Q_D(QQuickAnchors);
830     d->usedAnchors &= ~BaselineAnchor;
831     d->remDepend(d->baseline.item);
832     d->baseline = QQuickAnchorLine();
833     emit baselineChanged();
834     d->updateVerticalAnchors();
835 }
836
837 QQuickAnchorLine QQuickAnchors::left() const
838 {
839     Q_D(const QQuickAnchors);
840     return d->left;
841 }
842
843 void QQuickAnchors::setLeft(const QQuickAnchorLine &edge)
844 {
845     Q_D(QQuickAnchors);
846     if (!d->checkHAnchorValid(edge) || d->left == edge)
847         return;
848
849     d->usedAnchors |= LeftAnchor;
850
851     if (!d->checkHValid()) {
852         d->usedAnchors &= ~LeftAnchor;
853         return;
854     }
855
856     QQuickItem *oldLeft = d->left.item;
857     d->left = edge;
858     d->remDepend(oldLeft);
859     d->addDepend(d->left.item);
860     emit leftChanged();
861     d->updateHorizontalAnchors();
862 }
863
864 void QQuickAnchors::resetLeft()
865 {
866     Q_D(QQuickAnchors);
867     d->usedAnchors &= ~LeftAnchor;
868     d->remDepend(d->left.item);
869     d->left = QQuickAnchorLine();
870     emit leftChanged();
871     d->updateHorizontalAnchors();
872 }
873
874 QQuickAnchorLine QQuickAnchors::right() const
875 {
876     Q_D(const QQuickAnchors);
877     return d->right;
878 }
879
880 void QQuickAnchors::setRight(const QQuickAnchorLine &edge)
881 {
882     Q_D(QQuickAnchors);
883     if (!d->checkHAnchorValid(edge) || d->right == edge)
884         return;
885
886     d->usedAnchors |= RightAnchor;
887
888     if (!d->checkHValid()) {
889         d->usedAnchors &= ~RightAnchor;
890         return;
891     }
892
893     QQuickItem *oldRight = d->right.item;
894     d->right = edge;
895     d->remDepend(oldRight);
896     d->addDepend(d->right.item);
897     emit rightChanged();
898     d->updateHorizontalAnchors();
899 }
900
901 void QQuickAnchors::resetRight()
902 {
903     Q_D(QQuickAnchors);
904     d->usedAnchors &= ~RightAnchor;
905     d->remDepend(d->right.item);
906     d->right = QQuickAnchorLine();
907     emit rightChanged();
908     d->updateHorizontalAnchors();
909 }
910
911 QQuickAnchorLine QQuickAnchors::horizontalCenter() const
912 {
913     Q_D(const QQuickAnchors);
914     return d->hCenter;
915 }
916
917 void QQuickAnchors::setHorizontalCenter(const QQuickAnchorLine &edge)
918 {
919     Q_D(QQuickAnchors);
920     if (!d->checkHAnchorValid(edge) || d->hCenter == edge)
921         return;
922
923     d->usedAnchors |= HCenterAnchor;
924
925     if (!d->checkHValid()) {
926         d->usedAnchors &= ~HCenterAnchor;
927         return;
928     }
929
930     QQuickItem *oldHCenter = d->hCenter.item;
931     d->hCenter = edge;
932     d->remDepend(oldHCenter);
933     d->addDepend(d->hCenter.item);
934     emit horizontalCenterChanged();
935     d->updateHorizontalAnchors();
936 }
937
938 void QQuickAnchors::resetHorizontalCenter()
939 {
940     Q_D(QQuickAnchors);
941     d->usedAnchors &= ~HCenterAnchor;
942     d->remDepend(d->hCenter.item);
943     d->hCenter = QQuickAnchorLine();
944     emit horizontalCenterChanged();
945     d->updateHorizontalAnchors();
946 }
947
948 qreal QQuickAnchors::leftMargin() const
949 {
950     Q_D(const QQuickAnchors);
951     return d->leftMargin;
952 }
953
954 void QQuickAnchors::setLeftMargin(qreal offset)
955 {
956     Q_D(QQuickAnchors);
957     if (d->leftMargin == offset)
958         return;
959     d->leftMargin = offset;
960     if (d->fill)
961         d->fillChanged();
962     else
963         d->updateHorizontalAnchors();
964     emit leftMarginChanged();
965 }
966
967 qreal QQuickAnchors::rightMargin() const
968 {
969     Q_D(const QQuickAnchors);
970     return d->rightMargin;
971 }
972
973 void QQuickAnchors::setRightMargin(qreal offset)
974 {
975     Q_D(QQuickAnchors);
976     if (d->rightMargin == offset)
977         return;
978     d->rightMargin = offset;
979     if (d->fill)
980         d->fillChanged();
981     else
982         d->updateHorizontalAnchors();
983     emit rightMarginChanged();
984 }
985
986 qreal QQuickAnchors::margins() const
987 {
988     Q_D(const QQuickAnchors);
989     return d->margins;
990 }
991
992 void QQuickAnchors::setMargins(qreal offset)
993 {
994     Q_D(QQuickAnchors);
995     if (d->margins == offset)
996         return;
997     //###Is it significantly faster to set them directly so we can call fillChanged only once?
998     if (!d->rightMargin || d->rightMargin == d->margins)
999         setRightMargin(offset);
1000     if (!d->leftMargin || d->leftMargin == d->margins)
1001         setLeftMargin(offset);
1002     if (!d->topMargin || d->topMargin == d->margins)
1003         setTopMargin(offset);
1004     if (!d->bottomMargin || d->bottomMargin == d->margins)
1005         setBottomMargin(offset);
1006     d->margins = offset;
1007     emit marginsChanged();
1008
1009 }
1010
1011 qreal QQuickAnchors::horizontalCenterOffset() const
1012 {
1013     Q_D(const QQuickAnchors);
1014     return d->hCenterOffset;
1015 }
1016
1017 void QQuickAnchors::setHorizontalCenterOffset(qreal offset)
1018 {
1019     Q_D(QQuickAnchors);
1020     if (d->hCenterOffset == offset)
1021         return;
1022     d->hCenterOffset = offset;
1023     if (d->centerIn)
1024         d->centerInChanged();
1025     else
1026         d->updateHorizontalAnchors();
1027     emit horizontalCenterOffsetChanged();
1028 }
1029
1030 qreal QQuickAnchors::topMargin() const
1031 {
1032     Q_D(const QQuickAnchors);
1033     return d->topMargin;
1034 }
1035
1036 void QQuickAnchors::setTopMargin(qreal offset)
1037 {
1038     Q_D(QQuickAnchors);
1039     if (d->topMargin == offset)
1040         return;
1041     d->topMargin = offset;
1042     if (d->fill)
1043         d->fillChanged();
1044     else
1045         d->updateVerticalAnchors();
1046     emit topMarginChanged();
1047 }
1048
1049 qreal QQuickAnchors::bottomMargin() const
1050 {
1051     Q_D(const QQuickAnchors);
1052     return d->bottomMargin;
1053 }
1054
1055 void QQuickAnchors::setBottomMargin(qreal offset)
1056 {
1057     Q_D(QQuickAnchors);
1058     if (d->bottomMargin == offset)
1059         return;
1060     d->bottomMargin = offset;
1061     if (d->fill)
1062         d->fillChanged();
1063     else
1064         d->updateVerticalAnchors();
1065     emit bottomMarginChanged();
1066 }
1067
1068 qreal QQuickAnchors::verticalCenterOffset() const
1069 {
1070     Q_D(const QQuickAnchors);
1071     return d->vCenterOffset;
1072 }
1073
1074 void QQuickAnchors::setVerticalCenterOffset(qreal offset)
1075 {
1076     Q_D(QQuickAnchors);
1077     if (d->vCenterOffset == offset)
1078         return;
1079     d->vCenterOffset = offset;
1080     if (d->centerIn)
1081         d->centerInChanged();
1082     else
1083         d->updateVerticalAnchors();
1084     emit verticalCenterOffsetChanged();
1085 }
1086
1087 qreal QQuickAnchors::baselineOffset() const
1088 {
1089     Q_D(const QQuickAnchors);
1090     return d->baselineOffset;
1091 }
1092
1093 void QQuickAnchors::setBaselineOffset(qreal offset)
1094 {
1095     Q_D(QQuickAnchors);
1096     if (d->baselineOffset == offset)
1097         return;
1098     d->baselineOffset = offset;
1099     d->updateVerticalAnchors();
1100     emit baselineOffsetChanged();
1101 }
1102
1103 QQuickAnchors::Anchors QQuickAnchors::usedAnchors() const
1104 {
1105     Q_D(const QQuickAnchors);
1106     return d->usedAnchors;
1107 }
1108
1109 bool QQuickAnchorsPrivate::checkHValid() const
1110 {
1111     if (usedAnchors & QQuickAnchors::LeftAnchor &&
1112         usedAnchors & QQuickAnchors::RightAnchor &&
1113         usedAnchors & QQuickAnchors::HCenterAnchor) {
1114         qmlInfo(item) << QQuickAnchors::tr("Cannot specify left, right, and hcenter anchors.");
1115         return false;
1116     }
1117
1118     return true;
1119 }
1120
1121 bool QQuickAnchorsPrivate::checkHAnchorValid(QQuickAnchorLine anchor) const
1122 {
1123     if (!anchor.item) {
1124         qmlInfo(item) << QQuickAnchors::tr("Cannot anchor to a null item.");
1125         return false;
1126     } else if (anchor.anchorLine & QQuickAnchorLine::Vertical_Mask) {
1127         qmlInfo(item) << QQuickAnchors::tr("Cannot anchor a horizontal edge to a vertical edge.");
1128         return false;
1129     } else if (anchor.item != item->parentItem() && anchor.item->parentItem() != item->parentItem()){
1130         qmlInfo(item) << QQuickAnchors::tr("Cannot anchor to an item that isn't a parent or sibling.");
1131         return false;
1132     } else if (anchor.item == item) {
1133         qmlInfo(item) << QQuickAnchors::tr("Cannot anchor item to self.");
1134         return false;
1135     }
1136
1137     return true;
1138 }
1139
1140 bool QQuickAnchorsPrivate::checkVValid() const
1141 {
1142     if (usedAnchors & QQuickAnchors::TopAnchor &&
1143         usedAnchors & QQuickAnchors::BottomAnchor &&
1144         usedAnchors & QQuickAnchors::VCenterAnchor) {
1145         qmlInfo(item) << QQuickAnchors::tr("Cannot specify top, bottom, and vcenter anchors.");
1146         return false;
1147     } else if (usedAnchors & QQuickAnchors::BaselineAnchor &&
1148                (usedAnchors & QQuickAnchors::TopAnchor ||
1149                 usedAnchors & QQuickAnchors::BottomAnchor ||
1150                 usedAnchors & QQuickAnchors::VCenterAnchor)) {
1151         qmlInfo(item) << QQuickAnchors::tr("Baseline anchor cannot be used in conjunction with top, bottom, or vcenter anchors.");
1152         return false;
1153     }
1154
1155     return true;
1156 }
1157
1158 bool QQuickAnchorsPrivate::checkVAnchorValid(QQuickAnchorLine anchor) const
1159 {
1160     if (!anchor.item) {
1161         qmlInfo(item) << QQuickAnchors::tr("Cannot anchor to a null item.");
1162         return false;
1163     } else if (anchor.anchorLine & QQuickAnchorLine::Horizontal_Mask) {
1164         qmlInfo(item) << QQuickAnchors::tr("Cannot anchor a vertical edge to a horizontal edge.");
1165         return false;
1166     } else if (anchor.item != item->parentItem() && anchor.item->parentItem() != item->parentItem()){
1167         qmlInfo(item) << QQuickAnchors::tr("Cannot anchor to an item that isn't a parent or sibling.");
1168         return false;
1169     } else if (anchor.item == item){
1170         qmlInfo(item) << QQuickAnchors::tr("Cannot anchor item to self.");
1171         return false;
1172     }
1173
1174     return true;
1175 }
1176
1177 QT_END_NAMESPACE
1178
1179 #include <moc_qquickanchors_p.cpp>
1180