Commit 480d014b authored by Marco Bubke's avatar Marco Bubke
Browse files

QmlDesigner: Add AnchorIndicator



Change-Id: I0cd4b3c9dc0178936ffd96d8acb443ce1a228d1f
Reviewed-by: default avatarThomas Hartmann <Thomas.Hartmann@digia.com>
parent 036ab272
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "anchorindicator.h"
#include "qmlanchors.h"
#include "anchorindicatorgraphicsitem.h"
#include <QGraphicsScene>
#include <QGraphicsPathItem>
namespace QmlDesigner {
AnchorIndicator::AnchorIndicator(LayerItem *layerItem)
: m_layerItem(layerItem)
{
}
AnchorIndicator::AnchorIndicator()
{
}
AnchorIndicator::~AnchorIndicator()
{
clear();
}
void AnchorIndicator::show()
{
if (m_indicatorTopShape)
m_indicatorTopShape->show();
if (m_indicatorBottomShape)
m_indicatorBottomShape->show();
if (m_indicatorLeftShape)
m_indicatorLeftShape->show();
if (m_indicatorRightShape)
m_indicatorRightShape->show();
}
void AnchorIndicator::hide()
{
if (m_indicatorTopShape)
m_indicatorTopShape->hide();
if (m_indicatorBottomShape)
m_indicatorBottomShape->hide();
if (m_indicatorLeftShape)
m_indicatorLeftShape->hide();
if (m_indicatorRightShape)
m_indicatorRightShape->hide();
}
void AnchorIndicator::clear()
{
delete m_indicatorTopShape;
delete m_indicatorBottomShape;
delete m_indicatorLeftShape;
delete m_indicatorRightShape;
}
void AnchorIndicator::setItems(const QList<FormEditorItem *> &itemList)
{
clear();
if (itemList.count() == 1) {
m_formEditorItem = itemList.first();
QmlItemNode sourceQmlItemNode = m_formEditorItem->qmlItemNode();
QmlAnchors qmlAnchors = sourceQmlItemNode.anchors();
if (qmlAnchors.modelHasAnchor(AnchorLine::Top)) {
m_indicatorTopShape = new AnchorIndicatorGraphicsItem(m_layerItem.data());
m_indicatorTopShape->updateAnchorIndicator(AnchorLine(sourceQmlItemNode, AnchorLine::Top),
qmlAnchors.modelAnchor(AnchorLine::Top));
}
if (qmlAnchors.modelHasAnchor(AnchorLine::Bottom)) {
m_indicatorBottomShape = new AnchorIndicatorGraphicsItem(m_layerItem.data());
m_indicatorBottomShape->updateAnchorIndicator(AnchorLine(sourceQmlItemNode, AnchorLine::Bottom),
qmlAnchors.modelAnchor(AnchorLine::Bottom));
}
if (qmlAnchors.modelHasAnchor(AnchorLine::Left)) {
m_indicatorLeftShape = new AnchorIndicatorGraphicsItem(m_layerItem.data());
m_indicatorLeftShape->updateAnchorIndicator(AnchorLine(sourceQmlItemNode, AnchorLine::Left),
qmlAnchors.modelAnchor(AnchorLine::Left));
}
if (qmlAnchors.modelHasAnchor(AnchorLine::Right)) {
m_indicatorRightShape = new AnchorIndicatorGraphicsItem(m_layerItem.data());
m_indicatorRightShape->updateAnchorIndicator(AnchorLine(sourceQmlItemNode, AnchorLine::Right),
qmlAnchors.modelAnchor(AnchorLine::Right));
}
}
}
void AnchorIndicator::updateItems(const QList<FormEditorItem *> &itemList)
{
foreach (FormEditorItem *formEditorItem, itemList) {
if (formEditorItem == m_formEditorItem) {
QmlItemNode sourceQmlItemNode = m_formEditorItem->qmlItemNode();
QmlAnchors qmlAnchors = formEditorItem->qmlItemNode().anchors();
if (qmlAnchors.modelHasAnchor(AnchorLine::Top)) {
if (m_indicatorTopShape.isNull())
m_indicatorTopShape = new AnchorIndicatorGraphicsItem(m_layerItem.data());
m_indicatorTopShape->updateAnchorIndicator(AnchorLine(sourceQmlItemNode, AnchorLine::Top),
qmlAnchors.modelAnchor(AnchorLine::Top));
} else {
delete m_indicatorTopShape;
}
if (qmlAnchors.modelHasAnchor(AnchorLine::Bottom)) {
if (m_indicatorBottomShape.isNull())
m_indicatorBottomShape = new AnchorIndicatorGraphicsItem(m_layerItem.data());
m_indicatorBottomShape->updateAnchorIndicator(AnchorLine(sourceQmlItemNode, AnchorLine::Bottom),
qmlAnchors.modelAnchor(AnchorLine::Bottom));
} else {
delete m_indicatorBottomShape;
}
if (qmlAnchors.modelHasAnchor(AnchorLine::Left)) {
if (m_indicatorLeftShape.isNull())
m_indicatorLeftShape = new AnchorIndicatorGraphicsItem(m_layerItem.data());
m_indicatorLeftShape->updateAnchorIndicator(AnchorLine(sourceQmlItemNode, AnchorLine::Left),
qmlAnchors.modelAnchor(AnchorLine::Left));
} else {
delete m_indicatorLeftShape;
}
if (qmlAnchors.modelHasAnchor(AnchorLine::Right)) {
if (m_indicatorRightShape.isNull())
m_indicatorRightShape = new AnchorIndicatorGraphicsItem(m_layerItem.data());
m_indicatorRightShape->updateAnchorIndicator(AnchorLine(sourceQmlItemNode, AnchorLine::Right),
qmlAnchors.modelAnchor(AnchorLine::Right));
} else {
delete m_indicatorRightShape;
}
return;
}
}
}
} // namespace QmlDesigner
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef QMLDESIGNER_ANCHORINDICATOR_H
#define QMLDESIGNER_ANCHORINDICATOR_H
#include <QPointer>
#include "layeritem.h"
#include "formeditoritem.h"
namespace QmlDesigner {
class FormEditorItem;
class AnchorIndicatorGraphicsItem;
class AnchorIndicator
{
public:
AnchorIndicator(LayerItem *layerItem);
AnchorIndicator();
~AnchorIndicator();
void show();
void hide();
void clear();
void setItems(const QList<FormEditorItem*> &itemList);
void updateItems(const QList<FormEditorItem*> &itemList);
private:
QPointer<LayerItem> m_layerItem;
QPointer<FormEditorItem> m_formEditorItem;
QPointer<AnchorIndicatorGraphicsItem> m_indicatorTopShape;
QPointer<AnchorIndicatorGraphicsItem> m_indicatorBottomShape;
QPointer<AnchorIndicatorGraphicsItem> m_indicatorLeftShape;
QPointer<AnchorIndicatorGraphicsItem> m_indicatorRightShape;
};
} // namespace QmlDesigner
#endif // QMLDESIGNER_ANCHORINDICATOR_H
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "anchorindicatorgraphicsitem.h"
#include <QPainter>
#include <QPainterPath>
namespace QmlDesigner {
AnchorIndicatorGraphicsItem::AnchorIndicatorGraphicsItem(QGraphicsItem *parent) :
QGraphicsObject(parent)
{
setZValue(-3);
}
int startAngleForAnchorLine(const AnchorLine::Type &anchorLineType)
{
switch (anchorLineType) {
case AnchorLine::Top:
return 0;
case AnchorLine::Bottom:
return 180 * 16;
case AnchorLine::Left:
return 90 * 16;
case AnchorLine::Right:
return 270 * 16;
default:
return 0;
}
}
void AnchorIndicatorGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/)
{
painter->save();
QPen linePen(QColor(0, 0, 0, 150));
linePen.setDashPattern(QVector<double>() << 3. << 2.);
painter->setPen(linePen);
painter->drawLine(m_startPoint, m_firstControlPoint);
painter->drawLine(m_firstControlPoint, m_secondControlPoint);
painter->drawLine(m_secondControlPoint, m_endPoint);
linePen.setColor(QColor(255, 255, 255, 150));
linePen.setDashPattern(QVector<double>() << 2. << 3.);
linePen.setDashOffset(2.);
painter->setPen(linePen);
painter->drawLine(m_startPoint, m_firstControlPoint);
painter->drawLine(m_firstControlPoint, m_secondControlPoint);
painter->drawLine(m_secondControlPoint, m_endPoint);
static QRectF bumpRectangle(0., 0., 8., 8.);
painter->setPen(QPen(QColor(0, 255 , 0), 2));
painter->drawLine(m_sourceAnchorLineFirstPoint, m_sourceAnchorLineSecondPoint);
bumpRectangle.moveTo(m_startPoint.x() - 4., m_startPoint.y() - 4.);
painter->setBrush(painter->pen().color());
painter->setRenderHint(QPainter::Antialiasing, true);
painter->drawChord(bumpRectangle, startAngleForAnchorLine(m_sourceAnchorLineType), 180 * 16);
painter->setRenderHint(QPainter::Antialiasing, false);
painter->setPen(QPen(QColor(0, 0 , 255), 2));
painter->drawLine(m_targetAnchorLineFirstPoint, m_targetAnchorLineSecondPoint);
bumpRectangle.moveTo(m_endPoint.x() - 4., m_endPoint.y() - 4.);
painter->setBrush(painter->pen().color());
painter->setRenderHint(QPainter::Antialiasing, true);
painter->drawChord(bumpRectangle, startAngleForAnchorLine(m_targetAnchorLineType), 180 * 16);
painter->setRenderHint(QPainter::Antialiasing, false);
painter->restore();
}
QRectF AnchorIndicatorGraphicsItem::boundingRect() const
{
return m_boundingRect;
}
static QPointF createParentAnchorPoint(const QmlItemNode &parentQmlItemNode, AnchorLine::Type anchorLineType, const QmlItemNode &childQmlItemNode)
{
QRectF parentBoundingRect = parentQmlItemNode.instanceSceneTransform().mapRect(parentQmlItemNode.instanceBoundingRect().adjusted(0., 0., 1., 1.));
QRectF childBoundingRect = childQmlItemNode.instanceSceneTransform().mapRect(childQmlItemNode.instanceBoundingRect().adjusted(0., 0., 1., 1.));
QPointF anchorPoint;
switch (anchorLineType) {
case AnchorLine::Top:
anchorPoint = QPointF(childBoundingRect.center().x(), parentBoundingRect.top());
break;
case AnchorLine::Bottom:
anchorPoint = QPointF(childBoundingRect.center().x(), parentBoundingRect.bottom());
break;
case AnchorLine::Left:
anchorPoint = QPointF(parentBoundingRect.left(), childBoundingRect.center().y());
break;
case AnchorLine::Right:
anchorPoint = QPointF(parentBoundingRect.right(), childBoundingRect.center().y());
break;
default:
break;
}
return anchorPoint;
}
static QPointF createAnchorPoint(const QmlItemNode &qmlItemNode, AnchorLine::Type anchorLineType)
{
QRectF boundingRect = qmlItemNode.instanceBoundingRect().adjusted(0., 0., 1., 1.);
QPointF anchorPoint;
switch (anchorLineType) {
case AnchorLine::Top:
anchorPoint = QPointF(boundingRect.center().x(), boundingRect.top());
break;
case AnchorLine::Bottom:
anchorPoint = QPointF(boundingRect.center().x(), boundingRect.bottom());
break;
case AnchorLine::Left:
anchorPoint = QPointF(boundingRect.left(), boundingRect.center().y());
break;
case AnchorLine::Right:
anchorPoint = QPointF(boundingRect.right(), boundingRect.center().y());
break;
default:
break;
}
return qmlItemNode.instanceSceneTransform().map(anchorPoint);
}
static QPointF createControlPoint(const QPointF &firstEditPoint, AnchorLine::Type anchorLineType, const QPointF &secondEditPoint)
{
QPointF controlPoint = firstEditPoint;
switch (anchorLineType) {
case AnchorLine::Top:
case AnchorLine::Bottom:
controlPoint.ry() += (secondEditPoint.y() - firstEditPoint.y()) / 2.0;
break;
case AnchorLine::Left:
case AnchorLine::Right:
controlPoint.rx() += (secondEditPoint.x() - firstEditPoint.x()) / 2.0;
break;
default:
break;
}
return controlPoint;
}
static void updateAnchorLinePoints(QPointF *firstPoint, QPointF *secondPoint, const AnchorLine &anchorLine)
{
QRectF boundingRectangle = anchorLine.qmlItemNode().instanceBoundingRect().adjusted(0., 0., 1., 1.);
switch (anchorLine.type()) {
case AnchorLine::Top:
*firstPoint = boundingRectangle.topLeft();
*secondPoint = boundingRectangle.topRight();
break;
case AnchorLine::Bottom:
*firstPoint = boundingRectangle.bottomLeft();
*secondPoint = boundingRectangle.bottomRight();
break;
case AnchorLine::Left:
*firstPoint = boundingRectangle.topLeft();
*secondPoint = boundingRectangle.bottomLeft();
break;
case AnchorLine::Right:
*firstPoint = boundingRectangle.topRight();
*secondPoint = boundingRectangle.bottomRight();
break;
default:
break;
}
*firstPoint = anchorLine.qmlItemNode().instanceSceneTransform().map(*firstPoint);
*secondPoint = anchorLine.qmlItemNode().instanceSceneTransform().map(*secondPoint);
}
void AnchorIndicatorGraphicsItem::updateAnchorIndicator(const AnchorLine &sourceAnchorLine, const AnchorLine targetAnchorLine)
{
m_sourceAnchorLineType = sourceAnchorLine.type();
m_targetAnchorLineType = targetAnchorLine.type();
m_startPoint = createAnchorPoint(sourceAnchorLine.qmlItemNode(), sourceAnchorLine.type());
if (targetAnchorLine.qmlItemNode() == sourceAnchorLine.qmlItemNode().instanceParentItem())
m_endPoint = createParentAnchorPoint(targetAnchorLine.qmlItemNode(), targetAnchorLine.type(), sourceAnchorLine.qmlItemNode());
else
m_endPoint = createAnchorPoint(targetAnchorLine.qmlItemNode(), targetAnchorLine.type());
m_firstControlPoint = createControlPoint(m_startPoint, sourceAnchorLine.type(), m_endPoint);
m_secondControlPoint = createControlPoint(m_endPoint, targetAnchorLine.type(), m_startPoint);
updateAnchorLinePoints(&m_sourceAnchorLineFirstPoint, &m_sourceAnchorLineSecondPoint, sourceAnchorLine);
updateAnchorLinePoints(&m_targetAnchorLineFirstPoint, &m_targetAnchorLineSecondPoint, targetAnchorLine);
updateBoundingRect();
}
void AnchorIndicatorGraphicsItem::updateBoundingRect()
{
QPolygonF controlPolygon(QVector<QPointF>()
<< m_startPoint
<< m_firstControlPoint
<< m_secondControlPoint
<< m_endPoint
<< m_sourceAnchorLineFirstPoint
<< m_sourceAnchorLineSecondPoint
<< m_targetAnchorLineFirstPoint
<< m_targetAnchorLineSecondPoint
);
m_boundingRect = controlPolygon.boundingRect().adjusted(-10., -10., 10., 10.);
}
AnchorLine::Type AnchorIndicatorGraphicsItem::sourceAnchorLineType() const
{
return m_sourceAnchorLineType;
}
void AnchorIndicatorGraphicsItem::setSourceAnchorLineType(const AnchorLine::Type &sourceAnchorLineType)
{
m_sourceAnchorLineType = sourceAnchorLineType;
}
} // namespace QmlDesigner
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef QMLDESIGNER_ANCHORINDICATORGRAPHICSITEM_H
#define QMLDESIGNER_ANCHORINDICATORGRAPHICSITEM_H
#include <QGraphicsObject>
#include <qmlanchors.h>
namespace QmlDesigner {
class AnchorIndicatorGraphicsItem : public QGraphicsObject
{
Q_OBJECT
public:
explicit AnchorIndicatorGraphicsItem(QGraphicsItem *parent = 0);
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
QRectF boundingRect() const;
void updateAnchorIndicator(const AnchorLine &sourceAnchorLine, const AnchorLine targetAnchorLine);
AnchorLine::Type sourceAnchorLineType() const;
void setSourceAnchorLineType(const AnchorLine::Type &sourceAnchorLineType);
protected:
void updateBoundingRect();
private:
QPointF m_startPoint;
QPointF m_firstControlPoint;
QPointF m_secondControlPoint;
QPointF m_endPoint;
QPointF m_sourceAnchorLineFirstPoint;
QPointF m_sourceAnchorLineSecondPoint;
QPointF m_targetAnchorLineFirstPoint;
QPointF m_targetAnchorLineSecondPoint;
AnchorLine::Type m_sourceAnchorLineType;
AnchorLine::Type m_targetAnchorLineType;
QRectF m_boundingRect;
};
} // namespace QmlDesigner
#endif // QMLDESIGNER_ANCHORINDICATORGRAPHICSITEM_H