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