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