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