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