diff options
Diffstat (limited to 'src/plugins/qmldesigner/components/formeditor')
93 files changed, 12538 insertions, 0 deletions
diff --git a/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp new file mode 100644 index 0000000000..884ba4c351 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp @@ -0,0 +1,190 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "abstractformeditortool.h" +#include "formeditorview.h" +#include "formeditorview.h" + +#include <QtDebug> +#include <QGraphicsSceneDragDropEvent> +#include <nodemetainfo.h> + +namespace QmlDesigner { + +AbstractFormEditorTool::AbstractFormEditorTool(FormEditorView *editorView) : m_view(editorView) +{ +} + + +AbstractFormEditorTool::~AbstractFormEditorTool() +{ + +} + +FormEditorView* AbstractFormEditorTool::view() const +{ + return m_view; +} + +FormEditorScene* AbstractFormEditorTool::scene() const +{ + return view()->scene(); +} + +void AbstractFormEditorTool::setItems(const QList<FormEditorItem*> &itemList) +{ + m_itemList = itemList; + selectedItemsChanged(m_itemList); +} + +QList<FormEditorItem*> AbstractFormEditorTool::items() const +{ + return m_itemList; +} + +bool AbstractFormEditorTool::topItemIsMovable(const QList<QGraphicsItem*> & itemList) +{ + QGraphicsItem *firstSelectableItem = topMovableGraphicsItem(itemList); + if (firstSelectableItem == 0) + return false; + + FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(firstSelectableItem); + QList<QmlItemNode> selectedNodes = view()->selectedQmlItemNodes(); + + if (formEditorItem != 0 + && selectedNodes.contains(formEditorItem->qmlItemNode())) + return true; + + return false; + +} + +bool AbstractFormEditorTool::topSelectedItemIsMovable(const QList<QGraphicsItem*> &itemList) +{ + QList<QmlItemNode> selectedNodes = view()->selectedQmlItemNodes(); + + foreach (QGraphicsItem *item, itemList) { + FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item); + if (formEditorItem + && selectedNodes.contains(formEditorItem->qmlItemNode()) + && !formEditorItem->qmlItemNode().isRootNode() + && (formEditorItem->qmlItemNode().hasShowContent())) + return true; + } + + foreach (QGraphicsItem *item, itemList) { + FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item); + if (formEditorItem + && !formEditorItem->qmlItemNode().isRootNode() + && selectedNodes.contains(formEditorItem->qmlItemNode())) + return true; + } + + return false; + +} + + +bool AbstractFormEditorTool::topItemIsResizeHandle(const QList<QGraphicsItem*> &/*itemList*/) +{ + return false; +} + +QGraphicsItem *AbstractFormEditorTool::topMovableGraphicsItem(const QList<QGraphicsItem*> &itemList) +{ + foreach (QGraphicsItem *item, itemList) { + if (item->flags().testFlag(QGraphicsItem::ItemIsMovable)) + return item; + } + + return 0; +} +FormEditorItem *AbstractFormEditorTool::topMovableFormEditorItem(const QList<QGraphicsItem*> &itemList) +{ + foreach (QGraphicsItem *item, itemList) { + FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item); + if (formEditorItem + && (formEditorItem->qmlItemNode().hasShowContent())) + return formEditorItem; + } + + return 0; +} + +FormEditorItem* AbstractFormEditorTool::topFormEditorItem(const QList<QGraphicsItem*> & itemList) +{ + foreach (QGraphicsItem *item, itemList) { + FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item); + if (formEditorItem && !formEditorItem->qmlItemNode().isRootNode()) + return formEditorItem; + } + + return 0; +} + +FormEditorItem* AbstractFormEditorTool::topFormEditorItemWithRootItem(const QList<QGraphicsItem*> & itemList) +{ + foreach (QGraphicsItem *item, itemList) { + FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item); + if (formEditorItem) + return formEditorItem; + } + + return 0; +} + +void AbstractFormEditorTool::dropEvent(QGraphicsSceneDragDropEvent * /* event */) +{ + Q_ASSERT(false); +} + +void AbstractFormEditorTool::dragEnterEvent(QGraphicsSceneDragDropEvent * event) +{ + if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo") || + event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) { + event->accept(); + view()->changeToDragTool(); + view()->currentTool()->dragEnterEvent(event); + } else { + event->ignore(); + } +} + +void AbstractFormEditorTool::dragLeaveEvent(QGraphicsSceneDragDropEvent * /* event */) +{ + Q_ASSERT(false); +} + +void AbstractFormEditorTool::dragMoveEvent(QGraphicsSceneDragDropEvent * /* event */) +{ + Q_ASSERT(false); +} + + +} diff --git a/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.h b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.h new file mode 100644 index 0000000000..c2e387c696 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.h @@ -0,0 +1,103 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef ABSTRACTFORMEDITORTOOL_H +#define ABSTRACTFORMEDITORTOOL_H + +#include "formeditoritem.h" + +class QGraphicsItem; + +namespace QmlDesigner { + +class FormEditorView; + +class AbstractFormEditorTool +{ + +public: + AbstractFormEditorTool(FormEditorView* view); + + virtual ~AbstractFormEditorTool(); + + virtual void mousePressEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event) = 0; + virtual void mouseMoveEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event) = 0; + virtual void mouseReleaseEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event) = 0; + virtual void mouseDoubleClickEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event) = 0; + + virtual void hoverMoveEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event) = 0; + + virtual void dropEvent(QGraphicsSceneDragDropEvent * event); + virtual void dragEnterEvent(QGraphicsSceneDragDropEvent * event); + virtual void dragLeaveEvent(QGraphicsSceneDragDropEvent * event); + virtual void dragMoveEvent(QGraphicsSceneDragDropEvent * event); + + virtual void keyPressEvent(QKeyEvent *event) = 0; + virtual void keyReleaseEvent(QKeyEvent *keyEvent) = 0; + + virtual void itemsAboutToRemoved(const QList<FormEditorItem*> &itemList) = 0; + // virtual QVariant itemChange(QList<QGraphicsItem*> itemList, +// QGraphicsItem::GraphicsItemChange change, +// const QVariant &value ) = 0; +// virtual void update() = 0; + virtual void clear() = 0; + + virtual void formEditorItemsChanged(const QList<FormEditorItem*> &itemList) = 0; + + void setItems(const QList<FormEditorItem*> &itemList); + QList<FormEditorItem*> items() const; + + static QGraphicsItem* topMovableGraphicsItem(const QList<QGraphicsItem*> &itemList); + static FormEditorItem* topMovableFormEditorItem(const QList<QGraphicsItem*> &itemList); + bool topItemIsMovable(const QList<QGraphicsItem*> &itemList); + bool topSelectedItemIsMovable(const QList<QGraphicsItem*> &itemList); + bool topItemIsResizeHandle(const QList<QGraphicsItem*> &itemList); + + static FormEditorItem* topFormEditorItem(const QList<QGraphicsItem*> &itemList); + static FormEditorItem* topFormEditorItemWithRootItem(const QList<QGraphicsItem*> &itemList); +protected: + + virtual void selectedItemsChanged(const QList<FormEditorItem*> &itemList) = 0; + + + FormEditorView *view() const; + FormEditorScene* scene() const; +private: + FormEditorView *m_view; + QList<FormEditorItem*> m_itemList; +}; + +} + +#endif // ABSTRACTFORMEDITORTOOL_H diff --git a/src/plugins/qmldesigner/components/formeditor/anchor.png b/src/plugins/qmldesigner/components/formeditor/anchor.png Binary files differnew file mode 100644 index 0000000000..fa59038318 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/anchor.png diff --git a/src/plugins/qmldesigner/components/formeditor/anchorcontroller.cpp b/src/plugins/qmldesigner/components/formeditor/anchorcontroller.cpp new file mode 100644 index 0000000000..e59712216c --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/anchorcontroller.cpp @@ -0,0 +1,537 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "anchorcontroller.h" + +#include "formeditoritem.h" +#include "layeritem.h" +#include "formeditorscene.h" +#include "anchorhandleitem.h" +#include <QtDebug> +#include <cmath> +namespace QmlDesigner { + +AnchorControllerData::AnchorControllerData(LayerItem *layerItem, FormEditorItem *formEditorItem) + : layerItem(layerItem), + formEditorItem(formEditorItem), + topItem(0), + leftItem(0), + rightItem(0), + bottomItem(0) +{ +} + +AnchorControllerData::AnchorControllerData(const AnchorControllerData &other) + : layerItem(other.layerItem), + formEditorItem(other.formEditorItem), + topItem(other.topItem), + leftItem(other.leftItem), + rightItem(other.rightItem), + bottomItem(other.bottomItem) +{ +} + +AnchorControllerData::~AnchorControllerData() +{ + if (layerItem) { + layerItem->scene()->removeItem(topItem); + layerItem->scene()->removeItem(leftItem); + layerItem->scene()->removeItem(rightItem); + layerItem->scene()->removeItem(bottomItem); + } +} + + +AnchorController::AnchorController() + : m_data(new AnchorControllerData(0, 0)) +{ + +} + +AnchorController::AnchorController(const QSharedPointer<AnchorControllerData> &data) + : m_data(data) +{ + +} + +AnchorController::AnchorController(LayerItem *layerItem, FormEditorItem *formEditorItem) + : m_data(new AnchorControllerData(layerItem, formEditorItem)) +{ + m_data->topItem = new AnchorHandleItem(layerItem, *this); + m_data->topItem->setZValue(400); + m_data->topItem->setToolTip(m_data->topItem->toolTipString()); + + m_data->leftItem = new AnchorHandleItem(layerItem, *this); + m_data->leftItem->setZValue(400); + m_data->leftItem->setToolTip(m_data->leftItem->toolTipString()); + + m_data->rightItem = new AnchorHandleItem(layerItem, *this); + m_data->rightItem->setZValue(400); + m_data->rightItem->setToolTip(m_data->rightItem->toolTipString()); + + m_data->bottomItem = new AnchorHandleItem(layerItem, *this); + m_data->bottomItem->setZValue(400); + m_data->bottomItem->setToolTip(m_data->bottomItem->toolTipString()); + + m_data->sceneTransform = formEditorItem->sceneTransform(); + + updatePosition(); +} + + +bool AnchorController::isValid() const +{ + return m_data->formEditorItem != 0; +} + +void AnchorController::show() +{ + m_data->topItem->show(); + m_data->leftItem->show(); + m_data->rightItem->show(); + m_data->bottomItem->show(); +} + + + +void AnchorController::hide() +{ + m_data->topItem->hide(); + m_data->leftItem->hide(); + m_data->rightItem->hide(); + m_data->bottomItem->hide(); +} + + +static QPointF topCenter(const QRectF &rect) +{ + return QPointF(rect.center().x(), rect.top()); +} + +static QPointF leftCenter(const QRectF &rect) +{ + return QPointF(rect.left(), rect.center().y()); +} + +static QPointF rightCenter(const QRectF &rect) +{ + return QPointF(rect.right(), rect.center().y()); +} + +static QPointF bottomCenter(const QRectF &rect) +{ + return QPointF(rect.center().x(), rect.bottom()); +} + +static QPainterPath curveToPath(const QPointF &firstPoint, + const QPointF &secondPoint, + const QPointF &thirdPoint, + const QPointF &fourthPoint) +{ + QPainterPath path; + path.moveTo(firstPoint); + path.cubicTo(secondPoint, thirdPoint, fourthPoint); + + return path; +} + +static QPointF anchorPoint(const QRectF &boundingRect, AnchorLine::Type anchorLine, double baseOffset, double innerOffset = 0.0) +{ + switch(anchorLine) { + case AnchorLine::Top : return topCenter(boundingRect) + QPointF(baseOffset, innerOffset); + case AnchorLine::Bottom : return bottomCenter(boundingRect) - QPointF(baseOffset, innerOffset); + case AnchorLine::Left : return leftCenter(boundingRect) + QPointF(innerOffset, baseOffset); + case AnchorLine::Right : return rightCenter(boundingRect) - QPointF(innerOffset, baseOffset); + default: return QPointF(); + } + + return QPointF(); +} + + +static QPainterPath createArrowPath(QPointF arrowCenter, double arrowDegrees) +{ + QRectF arrowRect(0.0, 0.0, 16., 16.); + arrowRect.moveCenter(arrowCenter); + QPainterPath arrowPath; + + + arrowPath.moveTo(arrowCenter); + + arrowPath.arcTo(arrowRect, arrowDegrees + 180 - 20, 40.); + + return arrowPath; +} + +AnchorHandlePathData AnchorController::createPainterPathForAnchor(const QRectF &boundingRect, + AnchorLine::Type anchorLine, + const QPointF &targetPoint) const +{ + + + QPointF firstPointInLayerSpace(m_data->sceneTransform.map(anchorPoint(boundingRect, anchorLine, 0.0, 5.0))); + + QPointF topLeftBoundingBoxInLayerSpace(m_data->sceneTransform.map(boundingRect.topLeft())); + QPointF bottomLeftBoundingBoxInLayerSpace(m_data->sceneTransform.map(boundingRect.bottomLeft())); + QPointF topRightBoundingBoxInLayerSpace(m_data->sceneTransform.map(boundingRect.topRight())); + QPointF bottomRightBoundingBoxInLayerSpace(m_data->sceneTransform.map(boundingRect.bottomRight())); + + AnchorLine::Type secondAnchorLine(AnchorLine::Invalid); + + QPointF secondPointInLayerSpace(targetPoint); + if (targetPoint.isNull()) { + AnchorLine targetAnchorLine(m_data->formEditorItem->qmlItemNode().anchors().instanceAnchor(anchorLine)); + secondAnchorLine = targetAnchorLine.type(); + FormEditorItem *targetItem = m_data->formEditorItem->scene()->itemForQmlItemNode(targetAnchorLine.qmlItemNode());; + bool secondItemIsParent = m_data->formEditorItem->parentItem() == targetItem; + + if (secondItemIsParent) + secondPointInLayerSpace = (targetItem->mapToItem(m_data->layerItem.data(), + anchorPoint(targetItem->qmlItemNode().instanceBoundingRect(), targetAnchorLine.type(), 0.0))); + else + + secondPointInLayerSpace = (targetItem->mapToItem(m_data->layerItem.data(), + anchorPoint(targetItem->qmlItemNode().instanceBoundingRect(), targetAnchorLine.type(), 0.0))); + } + + QPointF firstControlPointInLayerSpace = (3. * firstPointInLayerSpace + 3 * secondPointInLayerSpace) / 6.; + QPointF secondControlPointInLayerSpace = (3 * firstPointInLayerSpace + 3. * secondPointInLayerSpace) / 6.; + + bool showAnchorLine(true); + switch (anchorLine) { + case AnchorLine::Top : + case AnchorLine::Bottom : + firstControlPointInLayerSpace.rx() = firstPointInLayerSpace.x(); + if (qAbs(secondPointInLayerSpace.y() - firstPointInLayerSpace.y()) < 18.0) + showAnchorLine = false; + if (qAbs(secondControlPointInLayerSpace.y() - secondPointInLayerSpace.y()) < 20.0 && + qAbs(secondControlPointInLayerSpace.x() - secondPointInLayerSpace.x()) > 20.0) { + firstControlPointInLayerSpace.ry() = firstPointInLayerSpace.y() + ((firstControlPointInLayerSpace.y() - firstPointInLayerSpace.y() > 0) ? 20 : -20); + } + break; + case AnchorLine::Left : + case AnchorLine::Right : + firstControlPointInLayerSpace.ry() = firstPointInLayerSpace.y(); + if (qAbs(secondPointInLayerSpace.x() - firstPointInLayerSpace.x()) < 18.0) + showAnchorLine = false; + if (qAbs(secondControlPointInLayerSpace.x() - secondPointInLayerSpace.x()) < 20.0 && + qAbs(secondControlPointInLayerSpace.y() - secondPointInLayerSpace.y()) > 20.0) { + firstControlPointInLayerSpace.rx() = firstPointInLayerSpace.x() + ((firstControlPointInLayerSpace.x() - firstPointInLayerSpace.x() > 0) ? 20 : -20); + } + break; + default: break; + } + + switch(secondAnchorLine) { + case AnchorLine::Top : + case AnchorLine::Bottom : + secondControlPointInLayerSpace.rx() = secondPointInLayerSpace.x(); + if (qAbs(secondControlPointInLayerSpace.y() - secondPointInLayerSpace.y()) < 20.0 && + qAbs(secondControlPointInLayerSpace.x() - secondPointInLayerSpace.x()) > 20.0) { + secondControlPointInLayerSpace.ry() = secondPointInLayerSpace.y() + ((secondControlPointInLayerSpace.y() - secondPointInLayerSpace.y() < 0) ? 20 : -20); + } + break; + case AnchorLine::Left : + case AnchorLine::Right : + secondControlPointInLayerSpace.ry() = secondPointInLayerSpace.y(); + if (qAbs(secondControlPointInLayerSpace.x() - secondPointInLayerSpace.x()) < 20.0 && + qAbs(secondControlPointInLayerSpace.y() - secondPointInLayerSpace.y()) > 20.0) { + secondControlPointInLayerSpace.rx() = secondPointInLayerSpace.x() + ((secondControlPointInLayerSpace.x() - secondPointInLayerSpace.x() < 0) ? 20 : -20); + } + break; + default: break; + } + + QPainterPath anchorLinePath; + anchorLinePath.setFillRule(Qt::WindingFill); + + QRectF baseRect(0.0, 0.0, 5., 5.); + baseRect.moveCenter(firstPointInLayerSpace); + QPainterPath basePath; + basePath.addRoundedRect(baseRect, 6., 6.); + anchorLinePath = anchorLinePath.united(basePath); + + QRectF baseLineRect; + switch (anchorLine) { + case AnchorLine::Left : { + baseLineRect = QRectF(topLeftBoundingBoxInLayerSpace, bottomLeftBoundingBoxInLayerSpace); + baseLineRect.setWidth(3); + } + break; + case AnchorLine::Top : { + baseLineRect = QRectF(topLeftBoundingBoxInLayerSpace, topRightBoundingBoxInLayerSpace); + baseLineRect.setHeight(3); + } + break; + case AnchorLine::Right : { + baseLineRect = QRectF(topRightBoundingBoxInLayerSpace, bottomRightBoundingBoxInLayerSpace); + baseLineRect.adjust(-3, 0, 0, 0); + } + break; + case AnchorLine::Bottom : { + baseLineRect = QRectF(bottomLeftBoundingBoxInLayerSpace, bottomRightBoundingBoxInLayerSpace); + baseLineRect.adjust(0, -3, 0, 0); + } + break; + default: break; + } + + if (!baseLineRect.isEmpty()) { + + QPainterPath baseLinePath; + baseLinePath.addRoundedRect(baseLineRect, 1., 1.); + anchorLinePath = anchorLinePath.united(baseLinePath); + } + + QPainterPath arrowPath; + arrowPath.setFillRule(Qt::WindingFill); + + + + if (showAnchorLine) { + QPainterPath curvePath(curveToPath(firstPointInLayerSpace, + firstControlPointInLayerSpace, + secondControlPointInLayerSpace, + secondPointInLayerSpace)); + + double arrowDegrees = curvePath.angleAtPercent(curvePath.percentAtLength(curvePath.length() - 2.5)); + + + + QPainterPathStroker arrowPathStroker; + arrowPathStroker.setWidth(2.0); + arrowPathStroker.setCapStyle(Qt::RoundCap); + + arrowPath = arrowPath.united(arrowPathStroker.createStroke(curvePath)); + + + + + + QRectF arrowCutRect(0.0, 0.0, 8., 8.); + arrowCutRect.moveCenter(secondPointInLayerSpace); + QPainterPath arrowCutPath; + arrowCutPath.addRect(arrowCutRect); + arrowPath = arrowPath.subtracted(arrowCutPath); + + arrowPath = arrowPath.united(createArrowPath(secondPointInLayerSpace, arrowDegrees)); + } + + AnchorHandlePathData pathData; + pathData.arrowPath = arrowPath; + pathData.sourceAnchorLinePath = anchorLinePath; + pathData.beginArrowPoint = firstPointInLayerSpace; + pathData.endArrowPoint = secondPointInLayerSpace; + + pathData.targetAnchorLinePath = createTargetAnchorLinePath(anchorLine); + pathData.targetNamePath = createTargetNamePathPath(anchorLine); + + return pathData; +} + +QPainterPath AnchorController::createTargetNamePathPath(AnchorLine::Type anchorLine) const +{ + QPainterPath path; + QmlAnchors anchors(formEditorItem()->qmlItemNode().anchors()); + if (anchors.instanceHasAnchor(anchorLine)) { + AnchorLine targetAnchorLine(anchors.instanceAnchor(anchorLine)); + + FormEditorItem *targetItem = formEditorItem()->scene()->itemForQmlItemNode(targetAnchorLine.qmlItemNode()); + QRectF boundingRect(targetItem->qmlItemNode().instanceBoundingRect()); + + QTransform sceneTransform(targetItem->qmlItemNode().instanceSceneTransform()); + + QPointF centerBoundingBoxInLayerSpace(sceneTransform.map(boundingRect.center())); + + QFont font; + font.setPixelSize(24); + QString nameString(QString("%1 (%2)").arg(targetAnchorLine.qmlItemNode().simplfiedTypeName()).arg(targetAnchorLine.qmlItemNode().id())); + path.addText(0., -4., font, nameString); + //path.translate(centerBoundingBoxInLayerSpace - path.qmlItemNode().instanceBoundingRect().center()); + + } + + return path; +} + +QPainterPath AnchorController::createTargetAnchorLinePath(AnchorLine::Type anchorLine) const +{ + QPainterPath path; + QmlAnchors anchors(formEditorItem()->qmlItemNode().anchors()); + if (anchors.instanceHasAnchor(anchorLine)) { + AnchorLine targetAnchorLine(anchors.instanceAnchor(anchorLine)); + + FormEditorItem *targetItem = formEditorItem()->scene()->itemForQmlItemNode(targetAnchorLine.qmlItemNode()); + QRectF boundingRect(targetItem->qmlItemNode().instanceBoundingRect()); + + QTransform sceneTransform(targetItem->qmlItemNode().instanceSceneTransform()); + + QPointF topLeftBoundingBoxInLayerSpace(sceneTransform.map(boundingRect.topLeft())); + QPointF bottomLeftBoundingBoxInLayerSpace(sceneTransform.map(boundingRect.bottomLeft())); + QPointF topRightBoundingBoxInLayerSpace(sceneTransform.map(boundingRect.topRight())); + QPointF bottomRightBoundingBoxInLayerSpace(sceneTransform.map(boundingRect.bottomRight())); + + + switch(targetAnchorLine.type()) { + case AnchorLine::Top : { + path.moveTo(topLeftBoundingBoxInLayerSpace); + path.lineTo(topRightBoundingBoxInLayerSpace); + } + break; + case AnchorLine::Bottom : { + path.moveTo(bottomLeftBoundingBoxInLayerSpace); + path.lineTo(bottomRightBoundingBoxInLayerSpace); + } + break; + case AnchorLine::Left : { + path.moveTo(topLeftBoundingBoxInLayerSpace); + path.lineTo(bottomLeftBoundingBoxInLayerSpace); + } + break; + case AnchorLine::Right : { + path.moveTo(topRightBoundingBoxInLayerSpace); + path.lineTo(bottomRightBoundingBoxInLayerSpace); + } + break; + default: break; + } + + QPainterPathStroker pathStroker; + pathStroker.setWidth(20.0); + pathStroker.setCapStyle(Qt::RoundCap); + path = pathStroker.createStroke(path); + + + } + + return path; +} + +void AnchorController::updatePosition() +{ + QRectF boundingRect = m_data->formEditorItem->qmlItemNode().instanceBoundingRect(); + QPointF beginPoint; + QPointF endPoint; + QmlAnchors anchors(m_data->formEditorItem->qmlItemNode().anchors()); + m_data->sceneTransform = m_data->formEditorItem->sceneTransform(); + + if (anchors.instanceHasAnchor(AnchorLine::Top)) + m_data->topItem->setHandlePath(createPainterPathForAnchor(boundingRect, AnchorLine::Top)); + else + m_data->topItem->setHandlePath(AnchorHandlePathData()); + + if (anchors.instanceHasAnchor(AnchorLine::Bottom)) + m_data->bottomItem->setHandlePath(createPainterPathForAnchor(boundingRect, AnchorLine::Bottom)); + else + m_data->bottomItem->setHandlePath(AnchorHandlePathData()); + + if (anchors.instanceHasAnchor(AnchorLine::Right)) + m_data->rightItem->setHandlePath(createPainterPathForAnchor(boundingRect, AnchorLine::Right)); + else + m_data->rightItem->setHandlePath(AnchorHandlePathData()); + + if (anchors.instanceHasAnchor(AnchorLine::Left)) + m_data->leftItem->setHandlePath(createPainterPathForAnchor(boundingRect, AnchorLine::Left)); + else + m_data->leftItem->setHandlePath(AnchorHandlePathData()); +} + + +FormEditorItem* AnchorController::formEditorItem() const +{ + return m_data->formEditorItem; +} + +QWeakPointer<AnchorControllerData> AnchorController::weakPointer() const +{ + return m_data; +} + + +bool AnchorController::isTopHandle(const AnchorHandleItem *handle) const +{ + return handle == m_data->topItem; +} + +bool AnchorController::isLeftHandle(const AnchorHandleItem *handle) const +{ + return handle == m_data->leftItem; +} + +bool AnchorController::isRightHandle(const AnchorHandleItem *handle) const +{ + return handle == m_data->rightItem; +} + +bool AnchorController::isBottomHandle(const AnchorHandleItem *handle) const +{ + return handle == m_data->bottomItem; +} + +void AnchorController::updateTargetPoint(AnchorLine::Type anchorLine, const QPointF &targetPoint) +{ + QRectF boundingRect = m_data->formEditorItem->qmlItemNode().instanceBoundingRect(); + + switch(anchorLine) { + case AnchorLine::Top : + m_data->topItem->setHandlePath(createPainterPathForAnchor(boundingRect, anchorLine, targetPoint)); break; + case AnchorLine::Bottom : + m_data->bottomItem->setHandlePath(createPainterPathForAnchor(boundingRect, anchorLine, targetPoint)); break; + case AnchorLine::Left : + m_data->leftItem->setHandlePath(createPainterPathForAnchor(boundingRect, anchorLine, targetPoint)); break; + case AnchorLine::Right : + m_data->rightItem->setHandlePath(createPainterPathForAnchor(boundingRect, anchorLine, targetPoint)); break; + default: break; + } +} + +void AnchorController::highlight(AnchorLine::Type anchorLine) +{ + switch(anchorLine) { + case AnchorLine::Top : + m_data->topItem->setHighlighted(true); break; + case AnchorLine::Bottom : + m_data->bottomItem->setHighlighted(true); break; + case AnchorLine::Left : + m_data->leftItem->setHighlighted(true); break; + case AnchorLine::Right : + m_data->rightItem->setHighlighted(true); break; + default: break; + } +} + +void AnchorController::clearHighlight() +{ + m_data->topItem->setHighlighted(false); + m_data->leftItem->setHighlighted(false); + m_data->rightItem->setHighlighted(false); + m_data->bottomItem->setHighlighted(false); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/anchorcontroller.h b/src/plugins/qmldesigner/components/formeditor/anchorcontroller.h new file mode 100644 index 0000000000..4d693dd4b0 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/anchorcontroller.h @@ -0,0 +1,117 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef ANCHORCONTROLLER_H +#define ANCHORCONTROLLER_H + +#include <QSharedPointer> +#include <QPainterPath> +#include <QPair> +#include <QTransform> +#include <qmlanchors.h> + +namespace QmlDesigner { + +struct AnchorHandlePathData +{ + QPainterPath sourceAnchorLinePath; + QPainterPath targetAnchorLinePath; + QPainterPath arrowPath; + QPainterPath targetNamePath; + QPointF beginArrowPoint; + QPointF endArrowPoint; +}; + +class FormEditorItem; +class LayerItem; +class AnchorHandleItem; + +class AnchorControllerData +{ +public: + AnchorControllerData(LayerItem *layerItem, + FormEditorItem *formEditorItem); + AnchorControllerData(const AnchorControllerData &other); + ~AnchorControllerData(); + + QWeakPointer<LayerItem> layerItem; + FormEditorItem *formEditorItem; + + AnchorHandleItem *topItem; + AnchorHandleItem *leftItem; + AnchorHandleItem *rightItem; + AnchorHandleItem *bottomItem; + + QTransform sceneTransform; +}; + + +class AnchorController +{ + public: + AnchorController(); + AnchorController(LayerItem *layerItem, FormEditorItem *formEditorItem); + AnchorController(const QSharedPointer<AnchorControllerData> &data); + + + void show(); + void hide(); + + void updatePosition(); + + bool isValid() const; + + QWeakPointer<AnchorControllerData> weakPointer() const; + + + FormEditorItem *formEditorItem() const; + + bool isTopHandle(const AnchorHandleItem *handle) const; + bool isLeftHandle(const AnchorHandleItem *handle) const; + bool isRightHandle(const AnchorHandleItem *handle) const; + bool isBottomHandle(const AnchorHandleItem *handle) const; + + void updateTargetPoint(AnchorLine::Type anchorLine, const QPointF &targetPoint); + + void clearHighlight(); + void highlight(AnchorLine::Type anchorLine); + +private: //functions + AnchorHandlePathData createPainterPathForAnchor(const QRectF &boundingRect, + AnchorLine::Type anchorLine, + const QPointF &targetPoint = QPointF()) const; + QPainterPath createTargetAnchorLinePath(AnchorLine::Type anchorLine) const; + QPainterPath createTargetNamePathPath(AnchorLine::Type anchorLine) const; +private: + QSharedPointer<AnchorControllerData> m_data; +}; + +} // namespace QmlDesigner + +#endif // ANCHORCONTROLLER_H diff --git a/src/plugins/qmldesigner/components/formeditor/anchorhandleitem.cpp b/src/plugins/qmldesigner/components/formeditor/anchorhandleitem.cpp new file mode 100644 index 0000000000..95939c6e0f --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/anchorhandleitem.cpp @@ -0,0 +1,212 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "anchorhandleitem.h" + +#include <formeditoritem.h> +#include <QPen> +#include <QPainterPathStroker> +#include <cmath> +#include <QtDebug> + +namespace QmlDesigner { + +AnchorHandleItem::AnchorHandleItem(QGraphicsItem *parent, const AnchorController &anchorController) + : QGraphicsItemGroup(parent), + m_anchorControllerData(anchorController.weakPointer()), + m_sourceAnchorLinePathItem(new QGraphicsPathItem(this)), + m_arrowPathItem(new QGraphicsPathItem(this)), + m_targetAnchorLinePathItem(new QGraphicsPathItem(this)), + m_targetNamePathItem(new QGraphicsPathItem(this)) +{ + addToGroup(m_sourceAnchorLinePathItem); + addToGroup(m_arrowPathItem); + addToGroup(m_targetAnchorLinePathItem); + addToGroup(m_targetNamePathItem); + + setFlag(QGraphicsItem::ItemIsMovable, true); +} + +AnchorLine::Type AnchorHandleItem::sourceAnchorLine() const +{ + if (isTopHandle()) + return AnchorLine::Top; + if (isBottomHandle()) + return AnchorLine::Bottom; + if (isLeftHandle()) + return AnchorLine::Left; + if (isRightHandle()) + return AnchorLine::Right; + + return AnchorLine::Invalid; +} + +AnchorLine AnchorHandleItem::targetAnchorLine() const +{ + QmlAnchors anchors(anchorController().formEditorItem()->qmlItemNode().anchors()); + + if (isTopHandle()) + return anchors.instanceAnchor(AnchorLine::Top); + if (isBottomHandle()) + return anchors.instanceAnchor(AnchorLine::Bottom); + if (isLeftHandle()) + return anchors.instanceAnchor(AnchorLine::Left); + if (isRightHandle()) + return anchors.instanceAnchor(AnchorLine::Right); + + return AnchorLine(); +} + +static QString anchorLineToString(AnchorLine::Type anchorLineType) +{ + switch(anchorLineType) { + case AnchorLine::Top: return "Top"; + case AnchorLine::Bottom: return "Bottom"; + case AnchorLine::Left: return "Left"; + case AnchorLine::Right: return "Right"; + default: break; + } + + return QString(); + +} + +QString AnchorHandleItem::toolTipString() const +{ + QString templateString("<p>Anchor Handle</p><p>%1</p><p>%2</p>"); + QmlItemNode fromNode(anchorController().formEditorItem()->qmlItemNode()); + QString fromString(QString("%3: %1(%2)").arg(fromNode.simplfiedTypeName(), fromNode.id(), anchorLineToString(sourceAnchorLine()))); + + AnchorLine toAnchorLine(targetAnchorLine()); + QmlItemNode toNode(toAnchorLine.qmlItemNode()); + QString toString; + if (toNode.isValid()) + toString = QString("%3: %1(%2)").arg(toNode.simplfiedTypeName(), toNode.id(), anchorLineToString(toAnchorLine.type())); + + return templateString.arg(fromString).arg(toString); +} + +void AnchorHandleItem::setHandlePath(const AnchorHandlePathData &pathData) +{ + m_beginArrowPoint = pathData.beginArrowPoint; + m_endArrowPoint = pathData.endArrowPoint; + m_arrowPathItem->setPath(pathData.arrowPath); + m_sourceAnchorLinePathItem->setPath(pathData.sourceAnchorLinePath); + m_targetAnchorLinePathItem->setPath(pathData.targetAnchorLinePath); + m_targetNamePathItem->setPath(pathData.targetNamePath); + + setHighlighted(false); +} + +AnchorController AnchorHandleItem::anchorController() const +{ + Q_ASSERT(!m_anchorControllerData.isNull()); + return AnchorController(m_anchorControllerData.toStrongRef()); +} + +AnchorHandleItem* AnchorHandleItem::fromGraphicsItem(QGraphicsItem *item) +{ + return qgraphicsitem_cast<AnchorHandleItem*>(item); +} + +bool AnchorHandleItem::isTopHandle() const +{ + return anchorController().isTopHandle(this); +} + +bool AnchorHandleItem::isLeftHandle() const +{ + return anchorController().isLeftHandle(this); +} + +bool AnchorHandleItem::isRightHandle() const +{ + return anchorController().isRightHandle(this); +} + +bool AnchorHandleItem::isBottomHandle() const +{ + return anchorController().isBottomHandle(this); +} + +AnchorLine::Type AnchorHandleItem::anchorType() const +{ + if (isTopHandle()) + return AnchorLine::Top; + + if (isBottomHandle()) + return AnchorLine::Bottom; + + if (isLeftHandle()) + return AnchorLine::Left; + + if (isRightHandle()) + return AnchorLine::Right; + + + return AnchorLine::Invalid; +} + +void AnchorHandleItem::setHighlighted(bool highlight) +{ + QLinearGradient gradient(m_beginArrowPoint, m_endArrowPoint); + gradient.setCoordinateMode(QGradient::LogicalMode); + m_arrowPathItem->setPen(QPen(QBrush(Qt::gray), 1.0, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin)); + m_targetAnchorLinePathItem->setPen(QColor(70, 0, 0, 90)); + m_targetAnchorLinePathItem->setBrush(QColor(255, 0, 0, 50)); + m_arrowPathItem->setPen(QPen(QBrush(Qt::gray), 1.0, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin)); + m_targetNamePathItem->setPen(QColor(0, 0, 255, 90)); + m_targetNamePathItem->setBrush(QColor(0, 0, 255, 50)); + + if (highlight) { + gradient.setColorAt(0.0, QColor(0, 0, 120, 255)); + gradient.setColorAt(1.0, QColor(120, 0, 0, 255)); + m_arrowPathItem->setBrush(gradient); + m_sourceAnchorLinePathItem->setPen(QColor(0, 0, 70, 255)); + m_sourceAnchorLinePathItem->setBrush(QColor(0, 0, 70, 255)); + m_targetAnchorLinePathItem->show(); + m_targetNamePathItem->show(); + + } else { + gradient.setColorAt(0.0, QColor(0, 0, 255, 255)); + gradient.setColorAt(1.0, QColor(255, 0, 0, 255)); + m_arrowPathItem->setBrush(gradient); + m_sourceAnchorLinePathItem->setPen(QColor(0, 0, 100, 255)); + m_sourceAnchorLinePathItem->setBrush(QColor(0, 0, 100, 255)); + m_targetAnchorLinePathItem->hide(); + m_targetNamePathItem->hide(); + } +} + +QPointF AnchorHandleItem::itemSpacePosition() const +{ + return parentItem()->mapToItem(anchorController().formEditorItem(), pos()); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/anchorhandleitem.h b/src/plugins/qmldesigner/components/formeditor/anchorhandleitem.h new file mode 100644 index 0000000000..6d6bd057f7 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/anchorhandleitem.h @@ -0,0 +1,91 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef ANCHORHANDLEITEM_H +#define ANCHORHANDLEITEM_H + +#include <QGraphicsItemGroup> + +#include "anchorcontroller.h" + +namespace QmlDesigner { + +class AnchorHandleItem : public QGraphicsItemGroup +{ +public: + enum + { + Type = 0xEAEC + }; + + + AnchorHandleItem(QGraphicsItem *parent, const AnchorController &anchorController); + + void setHandlePath(const AnchorHandlePathData &pathData); + + int type() const; + + AnchorController anchorController() const; + + static AnchorHandleItem* fromGraphicsItem(QGraphicsItem *item); + + + bool isTopHandle() const; + bool isLeftHandle() const; + bool isRightHandle() const; + bool isBottomHandle() const; + + QPointF itemSpacePosition() const; + + AnchorLine::Type anchorType() const; + + QString toolTipString() const; + AnchorLine targetAnchorLine() const; + AnchorLine::Type sourceAnchorLine() const; + + void setHighlighted(bool highlight); + +private: + QWeakPointer<AnchorControllerData> m_anchorControllerData; + QGraphicsPathItem *m_sourceAnchorLinePathItem; + QGraphicsPathItem *m_arrowPathItem; + QGraphicsPathItem *m_targetAnchorLinePathItem; + QGraphicsPathItem *m_targetNamePathItem; + QPointF m_beginArrowPoint; + QPointF m_endArrowPoint; +}; + +inline int AnchorHandleItem::type() const +{ + return Type; +} + +} // namespace QmlDesigner + +#endif // ANCHORHANDLEITEM_H diff --git a/src/plugins/qmldesigner/components/formeditor/anchorindicator.cpp b/src/plugins/qmldesigner/components/formeditor/anchorindicator.cpp new file mode 100644 index 0000000000..78762c23f7 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/anchorindicator.cpp @@ -0,0 +1,116 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "anchorindicator.h" + +#include <QSet> + +namespace QmlDesigner { + +AnchorIndicator::AnchorIndicator(LayerItem *layerItem) + : m_layerItem(layerItem) +{ + Q_ASSERT(layerItem); +} + +AnchorIndicator::~AnchorIndicator() +{ + m_itemControllerHash.clear(); +} + +void AnchorIndicator::show() +{ + QHashIterator<FormEditorItem*, AnchorController> itemControllerIterator(m_itemControllerHash); + while (itemControllerIterator.hasNext()) { + AnchorController controller = itemControllerIterator.next().value(); + controller.show(); + } +} + + +void AnchorIndicator::hide() +{ + QHashIterator<FormEditorItem*, AnchorController> itemControllerIterator(m_itemControllerHash); + while (itemControllerIterator.hasNext()) { + AnchorController controller = itemControllerIterator.next().value(); + controller.hide(); + } +} + +void AnchorIndicator::clear() +{ + m_itemControllerHash.clear(); +} + +void AnchorIndicator::setItems(const QList<FormEditorItem*> &itemList) +{ + clear(); + + foreach (FormEditorItem *item, itemList) { + AnchorController controller(m_layerItem, item); + m_itemControllerHash.insert(item, controller); + } + + updateItems(itemList); +} + +void AnchorIndicator::updateItems(const QList<FormEditorItem*> &itemList) +{ + foreach (FormEditorItem *item, itemList) { + if (m_itemControllerHash.contains(item)) { + AnchorController controller(m_itemControllerHash.value(item)); + controller.updatePosition(); + } + } +} + +void AnchorIndicator::updateTargetPoint(FormEditorItem *item, AnchorLine::Type anchorLine, const QPointF &targetPoint) +{ + AnchorController controller(m_itemControllerHash.value(item)); + controller.updateTargetPoint(anchorLine, targetPoint); +} + +void AnchorIndicator::clearHighlight() +{ + QHashIterator<FormEditorItem*, AnchorController> itemControllerIterator(m_itemControllerHash); + while (itemControllerIterator.hasNext()) { + AnchorController controller = itemControllerIterator.next().value(); + controller.clearHighlight(); + } +} + +void AnchorIndicator::highlight(FormEditorItem *item, AnchorLine::Type anchorLine) +{ + if (m_itemControllerHash.contains(item)) { + AnchorController controller(m_itemControllerHash.value(item)); + controller.highlight(anchorLine); + } +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/anchorindicator.h b/src/plugins/qmldesigner/components/formeditor/anchorindicator.h new file mode 100644 index 0000000000..c36ed04be8 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/anchorindicator.h @@ -0,0 +1,64 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef ANCHORINDICATOR_H +#define ANCHORINDICATOR_H + +#include "anchorcontroller.h" +#include <QList> +#include <QHash> + +namespace QmlDesigner { + +class AnchorIndicator +{ +public: + AnchorIndicator(LayerItem *layerItem); + ~AnchorIndicator(); + + void show(); + void hide(); + void clear(); + + void setItems(const QList<FormEditorItem*> &itemList); + + void updateItems(const QList<FormEditorItem*> &itemList); + void updateTargetPoint(FormEditorItem *item, AnchorLine::Type anchorLine, const QPointF &targetPoint); + + void clearHighlight(); + void highlight(FormEditorItem *item, AnchorLine::Type anchorLine); + +private: + QHash<FormEditorItem*, AnchorController> m_itemControllerHash; + LayerItem *m_layerItem; +}; + +} // namespace QmlDesigner + +#endif // ANCHORINDICATOR_H diff --git a/src/plugins/qmldesigner/components/formeditor/anchorlinecontroller.cpp b/src/plugins/qmldesigner/components/formeditor/anchorlinecontroller.cpp new file mode 100644 index 0000000000..6877ad1b0f --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/anchorlinecontroller.cpp @@ -0,0 +1,236 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "anchorlinecontroller.h" + +#include "formeditoritem.h" +#include "layeritem.h" +#include <QGraphicsScene> + +#include "anchorlinehandleitem.h" + +namespace QmlDesigner { + + +AnchorLineControllerData::AnchorLineControllerData(LayerItem *layerItem, FormEditorItem *formEditorItem) + : layerItem(layerItem), + formEditorItem(formEditorItem), + topItem(0), + leftItem(0), + rightItem(0), + bottomItem(0) +{ +} + +AnchorLineControllerData::AnchorLineControllerData(const AnchorLineControllerData &other) + : layerItem(other.layerItem), + formEditorItem(other.formEditorItem), + topItem(other.topItem), + leftItem(other.leftItem), + rightItem(other.rightItem), + bottomItem(other.bottomItem) +{} + +AnchorLineControllerData::~AnchorLineControllerData() +{ + if (layerItem) { + layerItem->scene()->removeItem(topItem); + layerItem->scene()->removeItem(leftItem); + layerItem->scene()->removeItem(rightItem); + layerItem->scene()->removeItem(bottomItem); + } +} + + +AnchorLineController::AnchorLineController() + : m_data(new AnchorLineControllerData(0, 0)) +{ + +} + +AnchorLineController::AnchorLineController(const QSharedPointer<AnchorLineControllerData> &data) + : m_data(data) +{ + +} + +AnchorLineController::AnchorLineController(LayerItem *layerItem, FormEditorItem *formEditorItem) + : m_data(new AnchorLineControllerData(layerItem, formEditorItem)) +{ + m_data->topItem = new AnchorLineHandleItem(layerItem, *this); + m_data->topItem->setZValue(300); + + m_data->leftItem = new AnchorLineHandleItem(layerItem, *this); + m_data->leftItem->setZValue(300); + + m_data->rightItem = new AnchorLineHandleItem(layerItem, *this); + m_data->rightItem->setZValue(300); + + m_data->bottomItem = new AnchorLineHandleItem(layerItem, *this); + m_data->bottomItem->setZValue(300); + + updatePosition(); +} + + +bool AnchorLineController::isValid() const +{ + return m_data->formEditorItem != 0; +} + +void AnchorLineController::show(AnchorLine::Type anchorLineMask) +{ + if (anchorLineMask & AnchorLine::Top) + m_data->topItem->show(); + else + m_data->topItem->hide(); + + if (anchorLineMask & AnchorLine::Left) + m_data->leftItem->show(); + else + m_data->leftItem->hide(); + + if (anchorLineMask & AnchorLine::Right) + m_data->rightItem->show(); + else + m_data->rightItem->hide(); + + if (anchorLineMask & AnchorLine::Bottom) + m_data->bottomItem->show(); + else + m_data->bottomItem->hide(); +} + +void AnchorLineController::hide() +{ + m_data->topItem->hide(); + m_data->leftItem->hide(); + m_data->rightItem->hide(); + m_data->bottomItem->hide(); +} + +static QPainterPath rectToPath(const QRectF &rect) +{ + QPainterPath path; + path.addRoundedRect(rect, 4, 4); + + return path; +} + +void AnchorLineController::updatePosition() +{ + QRectF boundingRect = m_data->formEditorItem->qmlItemNode().instanceBoundingRect(); + + QRectF topBoundingRect(boundingRect); + QRectF leftBoundingRect(boundingRect); + QRectF bottomBoundingRect(boundingRect); + QRectF rightBoundingRect(boundingRect); + + + if (formEditorItem()->isContainer()) { + topBoundingRect.setBottom(boundingRect.top() + 6); + topBoundingRect.adjust(7, -5, -7, 0); + + leftBoundingRect.setRight(boundingRect.left() + 6); + leftBoundingRect.adjust(-5, 7, 0, -7); + + bottomBoundingRect.setTop(boundingRect.bottom() - 6); + bottomBoundingRect.adjust(7, 0, -7, 5); + + rightBoundingRect.setLeft(boundingRect.right() - 6); + rightBoundingRect.adjust(0, 7, 5, -7); + + } else { + double height = qMin(boundingRect.height() / 4., 10.); + double width = qMin(boundingRect.width() / 4., 10.); + + topBoundingRect.setHeight(height); + topBoundingRect.adjust(width, -4, -width, -1); + + leftBoundingRect.setWidth(width); + leftBoundingRect.adjust(-4, height, -1, -height); + + bottomBoundingRect.setTop(boundingRect.bottom() - height); + bottomBoundingRect.adjust(width, 1, -width, 4); + + rightBoundingRect.setLeft(boundingRect.right() - width); + rightBoundingRect.adjust(1, height, 4, -height); + } + + m_data->topItem->setHandlePath(m_data->formEditorItem->mapToItem(m_data->layerItem.data(), + rectToPath(topBoundingRect))); + m_data->leftItem->setHandlePath(m_data->formEditorItem->mapToItem(m_data->layerItem.data(), + rectToPath(leftBoundingRect))); + m_data->bottomItem->setHandlePath(m_data->formEditorItem->mapToItem(m_data->layerItem.data(), + rectToPath(bottomBoundingRect))); + m_data->rightItem->setHandlePath(m_data->formEditorItem->mapToItem(m_data->layerItem.data(), + rectToPath(rightBoundingRect))); +} + + +FormEditorItem* AnchorLineController::formEditorItem() const +{ + return m_data->formEditorItem; +} + +QWeakPointer<AnchorLineControllerData> AnchorLineController::weakPointer() const +{ + return m_data; +} + + +bool AnchorLineController::isTopHandle(const AnchorLineHandleItem *handle) const +{ + return handle == m_data->topItem; +} + +bool AnchorLineController::isLeftHandle(const AnchorLineHandleItem *handle) const +{ + return handle == m_data->leftItem; +} + +bool AnchorLineController::isRightHandle(const AnchorLineHandleItem *handle) const +{ + return handle == m_data->rightItem; +} + +bool AnchorLineController::isBottomHandle(const AnchorLineHandleItem *handle) const +{ + return handle == m_data->bottomItem; +} + +void AnchorLineController::clearHighlight() +{ + m_data->topItem->setHiglighted(false); + m_data->leftItem->setHiglighted(false); + m_data->rightItem->setHiglighted(false); + m_data->bottomItem->setHiglighted(false); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/anchorlinecontroller.h b/src/plugins/qmldesigner/components/formeditor/anchorlinecontroller.h new file mode 100644 index 0000000000..98701705e0 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/anchorlinecontroller.h @@ -0,0 +1,93 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef ANCHORLINECONTROLLER_H +#define ANCHORLINECONTROLLER_H + +#include <QWeakPointer> +#include <QSharedPointer> +#include <qmlanchors.h> + +namespace QmlDesigner { + +class FormEditorItem; +class LayerItem; +class AnchorLineHandleItem; + +class AnchorLineControllerData +{ +public: + AnchorLineControllerData(LayerItem *layerItem, + FormEditorItem *formEditorItem); + AnchorLineControllerData(const AnchorLineControllerData &other); + ~AnchorLineControllerData(); + + QWeakPointer<LayerItem> layerItem; + FormEditorItem *formEditorItem; + + AnchorLineHandleItem *topItem; + AnchorLineHandleItem *leftItem; + AnchorLineHandleItem *rightItem; + AnchorLineHandleItem *bottomItem; +}; + + +class AnchorLineController +{ + public: + AnchorLineController(); + AnchorLineController(LayerItem *layerItem, FormEditorItem *formEditorItem); + AnchorLineController(const QSharedPointer<AnchorLineControllerData> &data); + + void show(AnchorLine::Type anchorLineMask); + void hide(); + + void updatePosition(); + + bool isValid() const; + + QWeakPointer<AnchorLineControllerData> weakPointer() const; + + + FormEditorItem *formEditorItem() const; + + bool isTopHandle(const AnchorLineHandleItem *handle) const; + bool isLeftHandle(const AnchorLineHandleItem *handle) const; + bool isRightHandle(const AnchorLineHandleItem *handle) const; + bool isBottomHandle(const AnchorLineHandleItem *handle) const; + + void clearHighlight(); + +private: + QSharedPointer<AnchorLineControllerData> m_data; +}; + +} // namespace QmlDesigner + +#endif // ANCHORLINECONTROLLER_H diff --git a/src/plugins/qmldesigner/components/formeditor/anchorlinehandleitem.cpp b/src/plugins/qmldesigner/components/formeditor/anchorlinehandleitem.cpp new file mode 100644 index 0000000000..e2aa10b67f --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/anchorlinehandleitem.cpp @@ -0,0 +1,148 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "anchorlinehandleitem.h" + +#include <formeditoritem.h> +#include <QPen> +#include <cmath> + +namespace QmlDesigner { + +AnchorLineHandleItem::AnchorLineHandleItem(QGraphicsItem *parent, const AnchorLineController &anchorLineController) + : QGraphicsPathItem(parent), + m_anchorLineControllerData(anchorLineController.weakPointer()) +{ + setFlag(QGraphicsItem::ItemIsMovable, true); + setHiglighted(false); +} + +void AnchorLineHandleItem::setHandlePath(const QPainterPath & path) +{ + setPath(path); + update(); +} + +QRectF AnchorLineHandleItem::boundingRect() const +{ + return QGraphicsPathItem::boundingRect(); +} + +QPainterPath AnchorLineHandleItem::shape() const +{ + return QGraphicsPathItem::shape(); +} + +AnchorLineController AnchorLineHandleItem::anchorLineController() const +{ + Q_ASSERT(!m_anchorLineControllerData.isNull()); + return AnchorLineController(m_anchorLineControllerData.toStrongRef()); +} + +AnchorLine::Type AnchorLineHandleItem::anchorLine() const +{ + if (isTopHandle()) + return AnchorLine::Top; + + if (isLeftHandle()) + return AnchorLine::Left; + + if (isRightHandle()) + return AnchorLine::Right; + + if (isBottomHandle()) + return AnchorLine::Bottom; + + return AnchorLine::Invalid; +} + +AnchorLineHandleItem* AnchorLineHandleItem::fromGraphicsItem(QGraphicsItem *item) +{ + return qgraphicsitem_cast<AnchorLineHandleItem*>(item); +} + +bool AnchorLineHandleItem::isTopHandle() const +{ + return anchorLineController().isTopHandle(this); +} + +bool AnchorLineHandleItem::isLeftHandle() const +{ + return anchorLineController().isLeftHandle(this); +} + +bool AnchorLineHandleItem::isRightHandle() const +{ + return anchorLineController().isRightHandle(this); +} + +bool AnchorLineHandleItem::isBottomHandle() const +{ + return anchorLineController().isBottomHandle(this); +} + +AnchorLine::Type AnchorLineHandleItem::anchorLineType() const +{ + if (isTopHandle()) + return AnchorLine::Top; + + if (isBottomHandle()) + return AnchorLine::Bottom; + + if (isLeftHandle()) + return AnchorLine::Left; + + if (isRightHandle()) + return AnchorLine::Right; + + + return AnchorLine::Invalid; +} + +QPointF AnchorLineHandleItem::itemSpacePosition() const +{ + return parentItem()->mapToItem(anchorLineController().formEditorItem(), pos()); +} + +void AnchorLineHandleItem::setHiglighted(bool highlight) +{ + if (highlight) { + QPen pen; + pen.setColor(QColor(108, 141, 221)); + setPen(pen); + setBrush(QColor(108, 141, 221, 140)); + } else { + QPen pen; + pen.setColor(QColor(108, 141, 221)); + setPen(pen); + setBrush(QColor(108, 141, 221, 60)); + } +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/anchorlinehandleitem.h b/src/plugins/qmldesigner/components/formeditor/anchorlinehandleitem.h new file mode 100644 index 0000000000..b35ec346ac --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/anchorlinehandleitem.h @@ -0,0 +1,86 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef ANCHORLINEHANDLEITEM_H +#define ANCHORLINEHANDLEITEM_H + +#include <QGraphicsPathItem> + +#include "anchorlinecontroller.h" + +namespace QmlDesigner { + +class AnchorLineHandleItem : public QGraphicsPathItem +{ +public: + enum + { + Type = 0xEAEB + }; + + + AnchorLineHandleItem(QGraphicsItem *parent, const AnchorLineController &AnchorLineController); + + void setHandlePath(const QPainterPath & path); + + int type() const; + QRectF boundingRect() const; + QPainterPath shape() const; + + AnchorLineController anchorLineController() const; + AnchorLine::Type anchorLine() const; + + + static AnchorLineHandleItem* fromGraphicsItem(QGraphicsItem *item); + + + bool isTopHandle() const; + bool isLeftHandle() const; + bool isRightHandle() const; + bool isBottomHandle() const; + + QPointF itemSpacePosition() const; + + AnchorLine::Type anchorLineType() const; + + void setHiglighted(bool highlight); + + +private: + QWeakPointer<AnchorLineControllerData> m_anchorLineControllerData; +}; + +inline int AnchorLineHandleItem::type() const +{ + return Type; +} + +} // namespace QmlDesigner + +#endif // ANCHORLINEHANDLEITEM_H diff --git a/src/plugins/qmldesigner/components/formeditor/anchorlineindicator.cpp b/src/plugins/qmldesigner/components/formeditor/anchorlineindicator.cpp new file mode 100644 index 0000000000..a521faf216 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/anchorlineindicator.cpp @@ -0,0 +1,131 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "anchorlineindicator.h" + +#include <QSet> + +namespace QmlDesigner { + +AnchorLineIndicator::AnchorLineIndicator(LayerItem *layerItem) + : m_layerItem(layerItem) +{ + Q_ASSERT(layerItem); +} + +AnchorLineIndicator::~AnchorLineIndicator() +{ + m_itemControllerHash.clear(); +} + +void AnchorLineIndicator::show(AnchorLine::Type anchorLineMask) +{ + QHashIterator<FormEditorItem*, AnchorLineController> itemControllerIterator(m_itemControllerHash); + while (itemControllerIterator.hasNext()) { + AnchorLineController controller = itemControllerIterator.next().value(); + controller.show(anchorLineMask); + } +} + +void AnchorLineIndicator::hide() +{ + QHashIterator<FormEditorItem*, AnchorLineController> itemControllerIterator(m_itemControllerHash); + while (itemControllerIterator.hasNext()) { + AnchorLineController controller = itemControllerIterator.next().value(); + controller.hide(); + } +} + +void AnchorLineIndicator::clear() +{ + m_itemControllerHash.clear(); +} + +void AnchorLineIndicator::setItem(FormEditorItem* item) +{ + if (!item) + return; + + QList<FormEditorItem*> itemList; + itemList.append(item); + + setItems(itemList); +} + +static bool equalLists(const QList<FormEditorItem*> &firstList, const QList<FormEditorItem*> &secondList) +{ + return firstList.toSet() == secondList.toSet(); +} + +void AnchorLineIndicator::setItems(const QList<FormEditorItem*> &itemList) +{ + if (equalLists(itemList, m_itemControllerHash.keys())) + return; + + clear(); + + foreach (FormEditorItem *item, itemList) { + AnchorLineController controller(m_layerItem, item); + m_itemControllerHash.insert(item, controller); + } + + show(AnchorLine::AllMask); +} + +void AnchorLineIndicator::updateItems(const QList<FormEditorItem*> &itemList) +{ + foreach (FormEditorItem *item, itemList) { + if (m_itemControllerHash.contains(item)) { + AnchorLineController controller(m_itemControllerHash.value(item)); + controller.updatePosition(); + } + } +} + +void AnchorLineIndicator::update() +{ + foreach (FormEditorItem *item, m_itemControllerHash.keys()) { + if (m_itemControllerHash.contains(item)) { + AnchorLineController controller(m_itemControllerHash.value(item)); + controller.updatePosition(); + } + } +} + +void AnchorLineIndicator::clearHighlight() +{ + foreach (FormEditorItem *item, m_itemControllerHash.keys()) { + if (m_itemControllerHash.contains(item)) { + AnchorLineController controller(m_itemControllerHash.value(item)); + controller.clearHighlight(); + } + } +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/anchorlineindicator.h b/src/plugins/qmldesigner/components/formeditor/anchorlineindicator.h new file mode 100644 index 0000000000..2a4c9966fc --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/anchorlineindicator.h @@ -0,0 +1,69 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef ANCHORLINEINDICATOR_H +#define ANCHORLINEINDICATOR_H + +#include "layeritem.h" +#include "anchorlinecontroller.h" +#include <QHash> + +namespace QmlDesigner { + +class FormEditorItem; + +class AnchorLineIndicator +{ +public: + AnchorLineIndicator(LayerItem *layerItem); + ~AnchorLineIndicator(); + + void show(AnchorLine::Type anchorLineMask); + + void hide(); + + void clear(); + + void update(); + + void setItems(const QList<FormEditorItem*> &itemList); + void setItem(FormEditorItem* item); + void updateItems(const QList<FormEditorItem*> &itemList); + + void clearHighlight(); + +private: + QHash<FormEditorItem*, AnchorLineController> m_itemControllerHash; + + LayerItem *m_layerItem; +}; + +} // namespace QmlDesigner + +#endif // ANCHORLINEINDICATOR_H diff --git a/src/plugins/qmldesigner/components/formeditor/anchormanipulator.cpp b/src/plugins/qmldesigner/components/formeditor/anchormanipulator.cpp new file mode 100644 index 0000000000..1468ae1e5f --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/anchormanipulator.cpp @@ -0,0 +1,144 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "anchormanipulator.h" + +#include "formeditoritem.h" +#include "formeditorscene.h" +#include "formeditorview.h" +#include <model.h> +#include <rewritertransaction.h> + +namespace QmlDesigner { + +AnchorManipulator::AnchorManipulator(FormEditorView *view) + : m_beginFormEditorItem(0), + m_beginAnchorLine(AnchorLine::Invalid), + m_view(view) +{ +} + +AnchorManipulator::~AnchorManipulator() +{ + clear(); +} + +void AnchorManipulator::begin(FormEditorItem *beginItem, AnchorLine::Type anchorLine) +{ + m_beginFormEditorItem = beginItem; + m_beginAnchorLine = anchorLine; +} + +static double offset(const QPointF &topLeft, const QPointF &bottomRight, AnchorLine::Type anchorLine) +{ + switch(anchorLine) { + case AnchorLine::Top : return topLeft.y(); + case AnchorLine::Left : return topLeft.x(); + case AnchorLine::Bottom : return bottomRight.y(); + case AnchorLine::Right : return bottomRight.x(); + default: break; + } + + return 0.0; +} + +void AnchorManipulator::setMargin(FormEditorItem *endItem, AnchorLine::Type endAnchorLine) +{ + QPointF beginItemTopLeft(m_beginFormEditorItem->mapToParent(m_beginFormEditorItem->qmlItemNode().instanceBoundingRect().topLeft())); + QPointF endItemTopLeft(m_beginFormEditorItem->parentItem()->mapFromItem(endItem, endItem->qmlItemNode().instanceBoundingRect().topLeft())); + + QPointF beginItemBottomRight(m_beginFormEditorItem->mapToParent(m_beginFormEditorItem->qmlItemNode().instanceBoundingRect().bottomRight())); + QPointF endItemBottomRight(m_beginFormEditorItem->parentItem()->mapFromItem(endItem, endItem->qmlItemNode().instanceBoundingRect().bottomRight())); + + QPointF topLeftAnchorOffset = beginItemTopLeft - endItemTopLeft; + QPointF bottomRightAnchorOffset = endItemBottomRight - beginItemBottomRight; + + + double anchorOffset = 0.0; + if (m_beginAnchorLine & (AnchorLine::Bottom | AnchorLine::Right)) { + anchorOffset = offset(endItemTopLeft, endItemBottomRight, endAnchorLine) - + offset(beginItemTopLeft, beginItemBottomRight, m_beginAnchorLine); + } else { + anchorOffset = offset(beginItemTopLeft, beginItemBottomRight, m_beginAnchorLine) - + offset(endItemTopLeft, endItemBottomRight, endAnchorLine); + } + + m_beginFormEditorItem->qmlItemNode().anchors().setMargin(m_beginAnchorLine, anchorOffset); +} +void AnchorManipulator::addAnchor(FormEditorItem *endItem, AnchorLine::Type endAnchorLine) +{ + RewriterTransaction m_rewriterTransaction = m_view->beginRewriterTransaction(); + setMargin(endItem, endAnchorLine); + + m_beginFormEditorItem->qmlItemNode().anchors().setAnchor(m_beginAnchorLine, + endItem->qmlItemNode(), + endAnchorLine); +} + +void AnchorManipulator::removeAnchor() +{ + RewriterTransaction transaction = m_view->beginRewriterTransaction(); + QmlAnchors anchors(m_beginFormEditorItem->qmlItemNode().anchors()); + if (anchors.instanceHasAnchor(m_beginAnchorLine)) { + anchors.removeAnchor(m_beginAnchorLine); + anchors.removeMargin(m_beginAnchorLine); + } +} + +void AnchorManipulator::clear() +{ + m_beginFormEditorItem = 0; + m_beginAnchorLine = AnchorLine::Invalid; +} + +bool AnchorManipulator::isActive() const +{ + return m_beginFormEditorItem && m_beginAnchorLine != AnchorLine::Invalid; +} + +AnchorLine::Type AnchorManipulator::beginAnchorLine() const +{ + return m_beginAnchorLine; +} + +bool AnchorManipulator::beginAnchorLineIsHorizontal() const +{ + return beginAnchorLine() & AnchorLine::HorizontalMask; +} +bool AnchorManipulator::beginAnchorLineIsVertical() const +{ + return beginAnchorLine() & AnchorLine::HorizontalMask; +} + +FormEditorItem *AnchorManipulator::beginFormEditorItem() const +{ + return m_beginFormEditorItem; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/anchormanipulator.h b/src/plugins/qmldesigner/components/formeditor/anchormanipulator.h new file mode 100644 index 0000000000..b44238a4e1 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/anchormanipulator.h @@ -0,0 +1,71 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef ANCHORMANIPULATOR_H +#define ANCHORMANIPULATOR_H + +#include <qmlanchors.h> + +namespace QmlDesigner { + +class FormEditorItem; +class FormEditorView; + +class AnchorManipulator +{ +public: + AnchorManipulator(FormEditorView *view); + ~AnchorManipulator(); + void begin(FormEditorItem *beginItem, AnchorLine::Type anchorLine); + void addAnchor(FormEditorItem *endItem, AnchorLine::Type anchorLine); + void removeAnchor(); + + void clear(); + + bool isActive() const; + + bool beginAnchorLineIsHorizontal() const; + bool beginAnchorLineIsVertical() const; + + AnchorLine::Type beginAnchorLine() const; + + FormEditorItem *beginFormEditorItem() const; + +private: // fucntions + void setMargin(FormEditorItem *endItem, AnchorLine::Type endAnchorLine); + +private: // variables + FormEditorItem *m_beginFormEditorItem; + AnchorLine::Type m_beginAnchorLine; + QWeakPointer<FormEditorView> m_view; +}; + +} // namespace QmlDesigner + +#endif // ANCHORMANIPULATOR_H diff --git a/src/plugins/qmldesigner/components/formeditor/anchortool.cpp b/src/plugins/qmldesigner/components/formeditor/anchortool.cpp new file mode 100644 index 0000000000..524352819d --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/anchortool.cpp @@ -0,0 +1,226 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "anchortool.h" + +#include "formeditorscene.h" +#include "formeditorview.h" +#include <qmlitemnode.h> +#include <qmlanchors.h> +#include "anchorlinehandleitem.h" + +#include <QGraphicsSceneMouseEvent> + +#include <QtDebug> + +namespace QmlDesigner { + +AnchorTool::AnchorTool(FormEditorView* editorView) + : AbstractFormEditorTool(editorView), + m_anchorLineIndicator(editorView->scene()->manipulatorLayerItem()), + m_anchorIndicator(editorView->scene()->manipulatorLayerItem()), + m_anchorManipulator(editorView), + m_lastAnchorLineHandleItem(0) +{ + m_hoverTimeLine.setDuration(200); + connect(&m_hoverTimeLine, SIGNAL(finished()), SLOT(checkIfStillHovering())); +} + +AnchorTool::~AnchorTool() +{ + +} + +void AnchorTool::mousePressEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *) +{ + AnchorLineHandleItem *anchorLineHandleItem = topAnchorLineHandleItem(itemList); + if (anchorLineHandleItem) { + m_anchorManipulator.begin(anchorLineHandleItem->anchorLineController().formEditorItem(), + anchorLineHandleItem->anchorLineType()); + } + + m_anchorLineIndicator.clear(); + +} + +bool areAchorable(FormEditorItem *firstItem, FormEditorItem *secondItem) +{ + return firstItem->qmlItemNode().anchors().canAnchor(secondItem->qmlItemNode()); +} + +void AnchorTool::mouseMoveEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event) +{ + if (m_anchorManipulator.isActive()) { + FormEditorItem *targetItem = 0; + AnchorLineHandleItem *anchorLineHandleItem = topAnchorLineHandleItem(itemList); + if (anchorLineHandleItem && areAchorable(m_anchorManipulator.beginFormEditorItem(), anchorLineHandleItem->anchorLineController().formEditorItem())) { + targetItem = anchorLineHandleItem->anchorLineController().formEditorItem(); + } else { + FormEditorItem *topFormEditItem = topFormEditorItemWithRootItem(itemList); + if (topFormEditItem && areAchorable(m_anchorManipulator.beginFormEditorItem(), topFormEditItem)) { + targetItem = topFormEditItem; + } else { + m_anchorLineIndicator.hide(); + m_anchorIndicator.updateTargetPoint(m_anchorManipulator.beginFormEditorItem(), m_anchorManipulator.beginAnchorLine(), event->scenePos()); + } + } + + if (targetItem) { + targetItem->qmlItemNode().selectNode(); + m_anchorLineIndicator.setItem(targetItem); + m_anchorLineIndicator.show(m_anchorManipulator.beginFormEditorItem()->qmlItemNode().anchors().possibleAnchorLines(m_anchorManipulator.beginAnchorLine(), targetItem->qmlItemNode())); + m_anchorIndicator.updateTargetPoint(m_anchorManipulator.beginFormEditorItem(), m_anchorManipulator.beginAnchorLine(), event->scenePos()); + targetItem->qmlItemNode().selectNode(); + } + } + +} + +void AnchorTool::mouseReleaseEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *) +{ + if (m_anchorManipulator.isActive()) { + AnchorLineHandleItem *anchorLineHandleItem = topAnchorLineHandleItem(itemList); + if (anchorLineHandleItem) { + m_anchorManipulator.addAnchor(anchorLineHandleItem->anchorLineController().formEditorItem(), + anchorLineHandleItem->anchorLineType()); + } else { + m_anchorManipulator.removeAnchor(); + } + + + } + + FormEditorItem *topFormEditItem = topFormEditorItem(itemList); + if (topFormEditItem) + topFormEditItem->qmlItemNode().selectNode(); + + m_anchorManipulator.clear(); + m_anchorLineIndicator.clear(); +} + +void AnchorTool::mouseDoubleClickEvent(const QList<QGraphicsItem*> & /*itemList*/, + QGraphicsSceneMouseEvent * /*event*/) +{ +} + +void AnchorTool::hoverMoveEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event) +{ + m_anchorLineIndicator.clearHighlight(); + m_anchorIndicator.clearHighlight(); + m_lastMousePosition = event->scenePos(); + FormEditorItem *topFormEditItem = 0; + AnchorLineHandleItem *anchorLineHandleItem = topAnchorLineHandleItem(itemList); + + if (anchorLineHandleItem) { + anchorLineHandleItem->setHiglighted(true); + m_anchorIndicator.highlight(anchorLineHandleItem->anchorLineController().formEditorItem(), + anchorLineHandleItem->anchorLineType()); + topFormEditItem = anchorLineHandleItem->anchorLineController().formEditorItem(); + if (m_hoverTimeLine.state() == QTimeLine::NotRunning) { + m_lastAnchorLineHandleItem = anchorLineHandleItem; + m_hoverTimeLine.start(); + } + } else { + topFormEditItem = topFormEditorItem(itemList); + } + + if (topFormEditItem) { + m_anchorLineIndicator.setItem(topFormEditItem); + m_anchorLineIndicator.show(AnchorLine::AllMask); + topFormEditItem->qmlItemNode().selectNode(); + } else { + + m_anchorLineIndicator.clear(); + } +} + +void AnchorTool::checkIfStillHovering() +{ + AnchorLineHandleItem *anchorLineHandleItem = topAnchorLineHandleItem(scene()->items(m_lastMousePosition)); + + if (anchorLineHandleItem && anchorLineHandleItem == m_lastAnchorLineHandleItem) { + FormEditorItem *sourceFormEditItem = anchorLineHandleItem->anchorLineController().formEditorItem(); + QmlAnchors anchors(sourceFormEditItem->qmlItemNode().anchors()); + if (anchors.instanceHasAnchor(anchorLineHandleItem->anchorLine())) { + QmlItemNode targetNode(anchors.instanceAnchor(anchorLineHandleItem->anchorLine()).qmlItemNode()); + FormEditorItem *targetFormEditorItem = scene()->itemForQmlItemNode(targetNode); + targetFormEditorItem->showAttention(); + } + } +} + +void AnchorTool::keyPressEvent(QKeyEvent *) +{ +} + +void AnchorTool::keyReleaseEvent(QKeyEvent *) +{ +} + +void AnchorTool::itemsAboutToRemoved(const QList<FormEditorItem*> &removedItems) +{ + QList<FormEditorItem*> newItemList = items().toSet().subtract(removedItems.toSet()).toList(); + setItems(newItemList); + m_anchorIndicator.setItems(newItemList); + m_anchorLineIndicator.clear(); +} + +void AnchorTool::selectedItemsChanged(const QList<FormEditorItem*> &/*itemList*/) +{ + m_anchorIndicator.setItems(view()->scene()->allFormEditorItems()); + m_anchorIndicator.show(); +} + +void AnchorTool::clear() +{ + m_anchorLineIndicator.clear(); + m_anchorIndicator.clear(); +} + +void AnchorTool::formEditorItemsChanged(const QList<FormEditorItem*> &) +{ + m_anchorLineIndicator.updateItems(view()->scene()->allFormEditorItems()); + m_anchorIndicator.updateItems(view()->scene()->allFormEditorItems()); +} + +AnchorLineHandleItem* AnchorTool::topAnchorLineHandleItem(const QList<QGraphicsItem*> & itemList) +{ + foreach (QGraphicsItem *item, itemList) { + AnchorLineHandleItem *anchorLineItem = AnchorLineHandleItem::fromGraphicsItem(item); + if (anchorLineItem) + return anchorLineItem; + } + + return 0; +} +} diff --git a/src/plugins/qmldesigner/components/formeditor/anchortool.h b/src/plugins/qmldesigner/components/formeditor/anchortool.h new file mode 100644 index 0000000000..d11dd1818e --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/anchortool.h @@ -0,0 +1,88 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef ANCHORTOOL_H +#define ANCHORTOOL_H + +#include <QTimeLine> + +#include "abstractformeditortool.h" + +#include "anchorlineindicator.h" +#include "anchorindicator.h" +#include "anchormanipulator.h" + +namespace QmlDesigner { + +class AnchorLineHandleItem; + +class AnchorTool : public QObject, public AbstractFormEditorTool +{ + Q_OBJECT +public: + AnchorTool(FormEditorView* editorView); + ~AnchorTool(); + + void mousePressEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void mouseMoveEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void mouseDoubleClickEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void hoverMoveEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *keyEvent); + + void itemsAboutToRemoved(const QList<FormEditorItem*> &itemList); + + void selectedItemsChanged(const QList<FormEditorItem*> &itemList); + + void clear(); + + void formEditorItemsChanged(const QList<FormEditorItem*> &itemList); + + static AnchorLineHandleItem* topAnchorLineHandleItem(const QList<QGraphicsItem*> & itemList); + +private slots: + void checkIfStillHovering(); + +private: //variables + AnchorLineIndicator m_anchorLineIndicator; + AnchorIndicator m_anchorIndicator; + AnchorManipulator m_anchorManipulator; + QTimeLine m_hoverTimeLine; + QPointF m_lastMousePosition; + AnchorLineHandleItem *m_lastAnchorLineHandleItem; +}; + +} +#endif // ANCHORTOOL_H diff --git a/src/plugins/qmldesigner/components/formeditor/controlelement.cpp b/src/plugins/qmldesigner/components/formeditor/controlelement.cpp new file mode 100644 index 0000000000..5894fe5c45 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/controlelement.cpp @@ -0,0 +1,66 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "controlelement.h" + +#include <QGraphicsScene> +#include <QGraphicsRectItem> +#include <QBrush> +#include "layeritem.h" +#include <QtDebug> + + +namespace QmlDesigner { + +ControlElement::ControlElement(LayerItem *layerItem) + : m_controlShape(new QGraphicsRectItem(layerItem)) +{ + QPen pen; + pen.setStyle(Qt::DashLine); + pen.setColor(Qt::blue); + m_controlShape->setPen(pen); +} + +ControlElement::~ControlElement() +{ + delete m_controlShape; +} + +void ControlElement::hide() +{ + m_controlShape->hide(); +} + +void ControlElement::setBoundingRect(const QRectF &rect) +{ + m_controlShape->show(); + m_controlShape->setRect(m_controlShape->mapFromScene(rect).boundingRect()); +} + +} diff --git a/src/plugins/qmldesigner/components/formeditor/controlelement.h b/src/plugins/qmldesigner/components/formeditor/controlelement.h new file mode 100644 index 0000000000..1ec1f3a864 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/controlelement.h @@ -0,0 +1,57 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef CONTROLELEMENT_H +#define CONTROLELEMENT_H + + +#include <QGraphicsRectItem> + + +namespace QmlDesigner { + +class LayerItem; + +class ControlElement +{ +public: + ControlElement(LayerItem *layerItem); + ~ControlElement(); + + void hide(); + + void setBoundingRect(const QRectF &rect); + +private: + QGraphicsRectItem *m_controlShape; +}; + +} + +#endif // CONTROLELEMENT_H diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp new file mode 100644 index 0000000000..7878cf86a3 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp @@ -0,0 +1,315 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "dragtool.h" + +#include "formeditorscene.h" +#include "formeditorview.h" +#include "modelutilities.h" +#include "itemutilfunctions.h" +#include <customdraganddrop.h> +#include <metainfo.h> + +#include "resizehandleitem.h" + +#include <QApplication> +#include <QGraphicsSceneMouseEvent> +#include <QtDebug> + +namespace QmlDesigner { + +DragTool::DragTool(FormEditorView *editorView) + : AbstractFormEditorTool(editorView), + m_moveManipulator(editorView->scene()->manipulatorLayerItem(), editorView), + m_selectionIndicator(editorView->scene()->manipulatorLayerItem()) +{ +// view()->setCursor(Qt::SizeAllCursor); +} + + +DragTool::~DragTool() +{ + +} + +void DragTool::clear() +{ + m_moveManipulator.clear(); + m_selectionIndicator.clear(); + m_movingItem.clear(); +} + +void DragTool::mousePressEvent(const QList<QGraphicsItem*> &, + QGraphicsSceneMouseEvent *) +{ + +} + +void DragTool::mouseMoveEvent(const QList<QGraphicsItem*> &, + QGraphicsSceneMouseEvent *) +{ + +} + +void DragTool::hoverMoveEvent(const QList<QGraphicsItem*> &, + QGraphicsSceneMouseEvent * /*event*/) +{ + +} + +void DragTool::keyPressEvent(QKeyEvent *) +{ + +} + +void DragTool::keyReleaseEvent(QKeyEvent *) +{ + +} + + +void DragTool::mouseReleaseEvent(const QList<QGraphicsItem*> &/*itemList*/, + QGraphicsSceneMouseEvent *) +{ + +} + +void DragTool::mouseDoubleClickEvent(const QList<QGraphicsItem*> & /*itemList*/, + QGraphicsSceneMouseEvent * /*event*/) +{ + +} + +void DragTool::itemsAboutToRemoved(const QList<FormEditorItem*> & /* removedItemList */) +{ + +} + +void DragTool::selectedItemsChanged(const QList<FormEditorItem*> &) +{ + +} + + + +void DragTool::updateMoveManipulator() +{ + if (m_moveManipulator.isActive()) + return; +} + +void DragTool::beginWithPoint(const QPointF &beginPoint) +{ + m_movingItem = scene()->itemForQmlItemNode(m_dragNode); + + m_moveManipulator.setItem(m_movingItem.data()); + m_moveManipulator.begin(beginPoint); + +} + +void DragTool::createQmlItemNode(const ItemLibraryInfo &itemLibraryRepresentation, QmlItemNode parentNode, QPointF scenePos) +{ + QmlDesignerItemLibraryDragAndDrop::CustomDragAndDrop::hide(); + + MetaInfo metaInfo = MetaInfo::global(); + + FormEditorItem *parentItem = scene()->itemForQmlItemNode(parentNode); + QPointF pos = parentItem->mapFromScene(scenePos); + + m_dragNode = view()->createQmlItemNode(itemLibraryRepresentation, pos, parentNode); + + Q_ASSERT(m_dragNode.modelNode().isValid()); + Q_ASSERT(m_dragNode.isValid()); + + QList<QmlItemNode> nodeList; + nodeList.append(m_dragNode); + view()->setSelectedQmlItemNodes(nodeList); + m_selectionIndicator.setItems(scene()->itemsForQmlItemNodes(nodeList)); +} + +void DragTool::createQmlItemNodeFromImage(const QString &imageName, QmlItemNode parentNode, QPointF scenePos) +{ + QmlDesignerItemLibraryDragAndDrop::CustomDragAndDrop::hide(); + + MetaInfo metaInfo = MetaInfo::global(); + + FormEditorItem *parentItem = scene()->itemForQmlItemNode(parentNode); + QPointF pos = parentItem->mapFromScene(scenePos); + + m_dragNode = view()->createQmlItemNodeFromImage(imageName, pos, parentNode); + + QList<QmlItemNode> nodeList; + nodeList.append(m_dragNode); + view()->setSelectedQmlItemNodes(nodeList); + m_selectionIndicator.setItems(scene()->itemsForQmlItemNodes(nodeList)); +} + +FormEditorItem* DragTool::calculateContainer(const QPointF &point, FormEditorItem * currentItem) +{ + QList<QGraphicsItem *> list = scene()->items(point); + foreach (QGraphicsItem *item, list) { + FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item); + if (formEditorItem && formEditorItem != currentItem && formEditorItem->isContainer()) + return formEditorItem; + } + return 0; +} + + +void DragTool::formEditorItemsChanged(const QList<FormEditorItem*> & itemList) +{ + if (m_movingItem && itemList.contains(m_movingItem.data())) { + QList<FormEditorItem*> updateItemList; + updateItemList.append(m_movingItem.data()); + m_selectionIndicator.updateItems(updateItemList); + } +} + + +void DragTool::dropEvent(QGraphicsSceneDragDropEvent * event) +{ + if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo") || + event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) { + event->accept(); + end(event->scenePos()); + //Q_ASSERT(m_token.isValid()); + m_rewriterTransaction.commit(); + m_dragNode = ModelNode(); + view()->changeToSelectionTool(); + } +} + +void DragTool::dragEnterEvent(QGraphicsSceneDragDropEvent * event) +{ + if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo") || + event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) { + if (!m_rewriterTransaction.isValid()) { + m_rewriterTransaction = view()->beginRewriterTransaction(); + } + } +} + +void DragTool::dragLeaveEvent(QGraphicsSceneDragDropEvent * event) +{ + if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo") || + event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) { + event->accept(); + if (m_dragNode.isValid()) + m_dragNode.destroy(); + end(event->scenePos()); + m_rewriterTransaction.commit(); + QmlDesignerItemLibraryDragAndDrop::CustomDragAndDrop::show(); + QList<QmlItemNode> nodeList; + view()->setSelectedQmlItemNodes(nodeList); + view()->changeToSelectionTool(); + } +} + +static ItemLibraryInfo ItemLibraryInfoFromData(const QByteArray &data) +{ + QDataStream stream(data); + + ItemLibraryInfo itemLibraryInfo; + stream >> itemLibraryInfo; + + return itemLibraryInfo; +} + +void DragTool::dragMoveEvent(QGraphicsSceneDragDropEvent * event) +{ + if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo") || + event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) { + event->accept(); + QPointF scenePos = event->scenePos(); + if (m_dragNode.isValid()) { + + FormEditorItem *parentItem = calculateContainer(event->scenePos() - QPoint(2, 2)); + if (!parentItem) { //if there is no parent any more - the use left the scene + end(event->scenePos()); + m_dragNode.destroy(); //delete the node then + QmlDesignerItemLibraryDragAndDrop::CustomDragAndDrop::show(); + return; + } + //move + move(event->scenePos()); + } else { + //create new node if container + + FormEditorItem *parentItem = calculateContainer(event->scenePos()); + if (!parentItem) + return; + QmlItemNode parentNode; //get possible container parentNode + if (parentItem) + parentNode = parentItem->qmlItemNode(); + + if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo")) { + Q_ASSERT(!event->mimeData()->data("application/vnd.bauhaus.itemlibraryinfo").isEmpty()); + ItemLibraryInfo ItemLibraryInfo = ItemLibraryInfoFromData(event->mimeData()->data("application/vnd.bauhaus.itemlibraryinfo")); + createQmlItemNode(ItemLibraryInfo, parentNode, event->scenePos()); + } else if (event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) { + Q_ASSERT(!event->mimeData()->data("application/vnd.bauhaus.libraryresource").isEmpty()); + QString imageName = QString::fromLatin1((event->mimeData()->data("application/vnd.bauhaus.libraryresource"))); + createQmlItemNodeFromImage(imageName, parentNode, event->scenePos()); + } else Q_ASSERT(false); + beginWithPoint(event->scenePos()); + } + } + if (event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) { + } +} + +void DragTool::end(QPointF scenePos) +{ + m_moveManipulator.end(scenePos); + clear(); +} + +void DragTool::move(QPointF scenePos) +{ + if (!m_movingItem) + return; + + FormEditorItem *containerItem = calculateContainer(scenePos - QPoint(2, 2), m_movingItem.data()); + if (containerItem && + containerItem != m_movingItem->parentItem() && + view()->currentState().isBaseState()) { + + m_moveManipulator.reparentTo(containerItem); + } + + //MoveManipulator::Snapping useSnapping = MoveManipulator::NoSnapping; + MoveManipulator::Snapping useSnapping = MoveManipulator::UseSnapping; + /* if (event->modifiers().testFlag(Qt::ControlModifier) != view()->isSnapButtonChecked()) + useSnapping = MoveManipulator::UseSnapping;*/ + + m_moveManipulator.update(scenePos, useSnapping); +} + + +} diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.h b/src/plugins/qmldesigner/components/formeditor/dragtool.h new file mode 100644 index 0000000000..97f676482b --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/dragtool.h @@ -0,0 +1,105 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef DRAGTOOL_H +#define DRAGTOOL_H + +#include "abstractformeditortool.h" +#include "movemanipulator.h" +#include "selectionindicator.h" +#include "resizeindicator.h" + +#include <QHash> + + +namespace QmlDesigner { + + +class DragTool : public AbstractFormEditorTool +{ +public: + DragTool(FormEditorView* editorView); + ~DragTool(); + + void mousePressEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void mouseMoveEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void mouseDoubleClickEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void hoverMoveEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *keyEvent); + + void itemsAboutToRemoved(const QList<FormEditorItem*> &itemList); + + void selectedItemsChanged(const QList<FormEditorItem*> &itemList); + + void updateMoveManipulator(); + + void beginWithPoint(const QPointF &beginPoint); + + + virtual void dropEvent(QGraphicsSceneDragDropEvent * event); + virtual void dragEnterEvent(QGraphicsSceneDragDropEvent * event); + virtual void dragLeaveEvent(QGraphicsSceneDragDropEvent * event); + virtual void dragMoveEvent(QGraphicsSceneDragDropEvent * event); + + //void beginWithPoint(const QPointF &beginPoint); + + void clear(); + + void formEditorItemsChanged(const QList<FormEditorItem*> &itemList); + +protected: + + +private: + + void createQmlItemNode(const ItemLibraryInfo &ItemLibraryRepresentation, QmlItemNode parentNode, QPointF scenePos); + void createQmlItemNodeFromImage(const QString &imageName, QmlItemNode parentNode, QPointF scenePos); + FormEditorItem* calculateContainer(const QPointF &point, FormEditorItem * currentItem = 0); + + void begin(QPointF scenePos); + void end(QPointF scenePos); + void move(QPointF scenePos); + + MoveManipulator m_moveManipulator; + SelectionIndicator m_selectionIndicator; + QWeakPointer<FormEditorItem> m_movingItem; + RewriterTransaction m_rewriterTransaction; + QmlItemNode m_dragNode; +}; + +} +#endif // DRAGTOOL_H diff --git a/src/plugins/qmldesigner/components/formeditor/formeditor.pri b/src/plugins/qmldesigner/components/formeditor/formeditor.pri new file mode 100644 index 0000000000..1c3bd78988 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/formeditor.pri @@ -0,0 +1,84 @@ +VPATH += $$PWD +QT += opengl +INCLUDEPATH += $$PWD +INCLUDEPATH += $$PWD/../navigator +DEPENDPATH += $$PWD +SOURCES += formeditoritem.cpp \ + formeditorview.cpp \ + formeditorscene.cpp \ + formeditorwidget.cpp \ + selectiontool.cpp \ + abstractformeditortool.cpp \ + controlelement.cpp \ + resizemanipulator.cpp \ + movemanipulator.cpp \ + layeritem.cpp \ + itemutilfunctions.cpp \ + selectionrectangle.cpp \ + rubberbandselectionmanipulator.cpp \ + movetool.cpp \ + selectionindicator.cpp \ + snappinglinecreator.cpp \ + snapper.cpp \ + onedimensionalcluster.cpp \ + singleselectionmanipulator.cpp \ + scalemanipulator.cpp \ + resizetool.cpp \ + resizeindicator.cpp \ + scaleitem.cpp \ + resizecontroller.cpp \ + resizehandleitem.cpp \ + anchortool.cpp \ + anchorlineindicator.cpp \ + anchorlinecontroller.cpp \ + anchorlinehandleitem.cpp \ + anchormanipulator.cpp \ + anchorindicator.cpp \ + anchorcontroller.cpp \ + anchorhandleitem.cpp \ + dragtool.cpp \ + itemcreatortool.cpp \ + toolbox.cpp \ + zoomaction.cpp \ + formeditorgraphicsview.cpp \ + numberseriesaction.cpp +HEADERS += formeditorscene.h \ + formeditorwidget.h \ + formeditoritem.h \ + formeditorview.h \ + selectiontool.h \ + abstractformeditortool.h \ + controlelement.h \ + resizemanipulator.h \ + movemanipulator.h \ + layeritem.h \ + itemutilfunctions.h \ + selectionrectangle.h \ + rubberbandselectionmanipulator.h \ + movetool.h \ + selectionindicator.h \ + snappinglinecreator.h \ + snapper.h \ + onedimensionalcluster.h \ + singleselectionmanipulator.h \ + scalemanipulator.h \ + resizetool.h \ + resizeindicator.h \ + scaleitem.h \ + resizecontroller.h \ + resizehandleitem.h \ + anchortool.h \ + anchorlineindicator.h \ + anchorlinecontroller.h \ + anchorlinehandleitem.h \ + anchormanipulator.h \ + anchorindicator.h \ + anchorcontroller.h \ + anchorhandleitem.h \ + dragtool.h \ + itemcreatortool.cpp \ + toolbox.h \ + zoomaction.h \ + formeditorgraphicsview.h \ + numberseriesaction.h +RESOURCES += formeditor.qrc diff --git a/src/plugins/qmldesigner/components/formeditor/formeditor.qrc b/src/plugins/qmldesigner/components/formeditor/formeditor.qrc new file mode 100644 index 0000000000..14e0dbd0fb --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/formeditor.qrc @@ -0,0 +1,12 @@ +<RCC> + <qresource prefix="/icon/handle"> + <file>resize_handle.png</file> + </qresource> + <qresource prefix="/icon/tool"> + <file>anchor.png</file> + <file>transform.png</file> + </qresource> + <qresource prefix="/icon/layout"> + <file>snapping.png</file> + </qresource> +</RCC> diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.cpp new file mode 100644 index 0000000000..fb2e905eda --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.cpp @@ -0,0 +1,88 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "formeditorgraphicsview.h" + +#include <QWheelEvent> + +namespace QmlDesigner { + +FormEditorGraphicsView::FormEditorGraphicsView(QWidget *parent) : + QGraphicsView(parent) +{ + setTransformationAnchor(QGraphicsView::AnchorUnderMouse); + setResizeAnchor(QGraphicsView::AnchorViewCenter); +// setCacheMode(QGraphicsView::CacheNone); + setCacheMode(QGraphicsView::CacheBackground); + setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); +// setViewportUpdateMode(QGraphicsView::NoViewportUpdate); + setRenderHint(QPainter::Antialiasing, false); + + setFrameShape(QFrame::NoFrame); + + setAutoFillBackground(true); + setBackgroundRole(QPalette::Window); + + const int checkerbordSize= 20; + QPixmap tilePixmap(checkerbordSize * 2, checkerbordSize * 2); + tilePixmap.fill(Qt::white); + QPainter tilePainter(&tilePixmap); + QColor color(220, 220, 220); + tilePainter.fillRect(0, 0, checkerbordSize, checkerbordSize, color); + tilePainter.fillRect(checkerbordSize, checkerbordSize, checkerbordSize, checkerbordSize, color); + tilePainter.end(); + + setBackgroundBrush(tilePixmap); + + viewport()->setMouseTracking(true); +} + +void FormEditorGraphicsView::wheelEvent(QWheelEvent *event) +{ + if (event->modifiers().testFlag(Qt::ControlModifier)) { + event->ignore(); + } else { + QGraphicsView::wheelEvent(event); + } + +} + +void FormEditorGraphicsView::drawBackground(QPainter *painter, const QRectF &rect) +{ + painter->save(); + painter->setBrushOrigin(0, 0); + painter->fillRect(rect.intersected(sceneRect()), backgroundBrush()); + // paint rect around editable area + painter->setPen(Qt::darkGray); + QRectF frameRect = sceneRect().adjusted(-1, -1, 0, 0); + painter->drawRect(frameRect); + painter->restore(); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.h b/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.h new file mode 100644 index 0000000000..2e79f656a4 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.h @@ -0,0 +1,51 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef FORMEDITORGRAPHICSVIEW_H +#define FORMEDITORGRAPHICSVIEW_H + +#include <QGraphicsView> + +namespace QmlDesigner { + +class FormEditorGraphicsView : public QGraphicsView +{ +Q_OBJECT +public: + explicit FormEditorGraphicsView(QWidget *parent = 0); + + +protected: + void drawBackground(QPainter *painter, const QRectF &rect); + void wheelEvent(QWheelEvent *event); +}; + +} // namespace QmlDesigner + +#endif // FORMEDITORGRAPHICSVIEW_H diff --git a/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp b/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp new file mode 100644 index 0000000000..91652fc37c --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp @@ -0,0 +1,323 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "formeditoritem.h" +#include "formeditorscene.h" +#include "formeditornodeinstanceview.h" +#include "selectiontool.h" + +#include <modelnode.h> +#include <nodemetainfo.h> +#include <widgetqueryview.h> + +#include <QGraphicsSceneMouseEvent> +#include <QDebug> +#include <QPainter> +#include <QStyleOptionGraphicsItem> +#include <QGraphicsView> +#include <QTimeLine> + +#include <cmath> + +#include <invalidmodelnodeexception.h> +#include <invalidnodestateexception.h> + +namespace QmlDesigner { + + + +FormEditorScene *FormEditorItem::scene() const { + return qobject_cast<FormEditorScene*>(QGraphicsItem::scene()); +} + +FormEditorItem::FormEditorItem(const QmlItemNode &qmlItemNode, FormEditorScene* scene) + : QGraphicsObject(scene->formLayerItem()), + m_snappingLineCreator(this), + m_qmlItemNode(qmlItemNode), + m_borderWidth(1.0), + m_opacity(0.6) +{ + setCacheMode(QGraphicsItem::ItemCoordinateCache); + setup(); +} + +void FormEditorItem::setup() +{ + if (qmlItemNode().hasInstanceParent()) + setParentItem(scene()->itemForQmlItemNode(qmlItemNode().instanceParent().toQmlItemNode())); + + if (QGraphicsItem::parentItem() == scene()->formLayerItem()) + m_borderWidth = 0.0; + + setFlag(QGraphicsItem::ItemIsMovable, true); + updateGeometry(); + updateVisibilty(); +} + +QRectF FormEditorItem::boundingRect() const +{ + return m_boundingRect; +} + +void FormEditorItem::updateGeometry() +{ + prepareGeometryChange(); + m_boundingRect = qmlItemNode().instanceBoundingRect(); + setTransform(qmlItemNode().instanceTransform()); + setTransform(m_attentionTransform, true); + //the property for zValue is called z in QGraphicsObject + Q_ASSERT(qmlItemNode().instanceValue("z").isValid()); + setZValue(qmlItemNode().instanceValue("z").toDouble()); +} + +void FormEditorItem::updateVisibilty() +{ +// setVisible(nodeInstance().isVisible()); +// setOpacity(nodeInstance().opacity()); +} + +void FormEditorItem::showAttention() +{ + if (m_attentionTimeLine.isNull()) { + m_attentionTimeLine = new QTimeLine(500, this); + m_attentionTimeLine->setCurveShape(QTimeLine::SineCurve); + connect(m_attentionTimeLine.data(), SIGNAL(valueChanged(qreal)), SLOT(changeAttention(qreal))); + connect(m_attentionTimeLine.data(), SIGNAL(finished()), m_attentionTimeLine.data(), SLOT(deleteLater())); + + m_attentionTimeLine->start(); + } +} + +void FormEditorItem::changeAttention(qreal value) +{ + if (QGraphicsItem::parentItem() == scene()->formLayerItem()) { + setAttentionHighlight(value); + } else { + setAttentionHighlight(value); + setAttentionScale(value); + } +} + +FormEditorView *FormEditorItem::formEditorView() const +{ + return scene()->editorView(); +} + +void FormEditorItem::setAttentionScale(double sinusScale) +{ + if (!qFuzzyIsNull(sinusScale)) { + double scale = std::sqrt(sinusScale); + m_attentionTransform.reset(); + QPointF centerPoint(qmlItemNode().instanceBoundingRect().center()); + m_attentionTransform.translate(centerPoint.x(), centerPoint.y()); + m_attentionTransform.scale(scale * 0.15 + 1.0, scale * 0.15 + 1.0); + m_attentionTransform.translate(-centerPoint.x(), -centerPoint.y()); + m_inverseAttentionTransform = m_attentionTransform.inverted(); + prepareGeometryChange(); + setTransform(qmlItemNode().instanceTransform()); + setTransform(m_attentionTransform, true); + } else { + m_attentionTransform.reset(); + prepareGeometryChange(); + setTransform(qmlItemNode().instanceTransform()); + } +} + +void FormEditorItem::setAttentionHighlight(double value) +{ + m_opacity = 0.6 + value; + if (QGraphicsItem::parentItem() == scene()->formLayerItem()) + m_borderWidth = value * 4; + else + m_borderWidth = 1. + value * 3; + + update(); +} + +FormEditorItem::~FormEditorItem() +{ + scene()->removeItemFromHash(this); +} + +/* \brief returns the parent item skipping all proxyItem*/ +FormEditorItem *FormEditorItem::parentItem() const +{ + return qgraphicsitem_cast<FormEditorItem*> (QGraphicsItem::parentItem()); +} + +FormEditorItem* FormEditorItem::fromQGraphicsItem(QGraphicsItem *graphicsItem) +{ + return qgraphicsitem_cast<FormEditorItem*>(graphicsItem); +} + +static QRectF alignedRect(const QRectF &rect) +{ + QRectF alignedRect(rect); + alignedRect.setTop(std::floor(rect.top()) + 0.5); + alignedRect.setBottom(std::floor(rect.bottom()) + 0.5); + alignedRect.setLeft(std::floor(rect.left()) + 0.5); + alignedRect.setRight(std::floor(rect.right()) + 0.5); + + return alignedRect; +} + +void FormEditorItem::paintBoundingRect(QPainter *painter) const +{ + if (QGraphicsItem::parentItem() == scene()->formLayerItem() && qFuzzyIsNull(m_borderWidth)) + return; + + QPen pen; + pen.setJoinStyle(Qt::MiterJoin); + + switch(scene()->paintMode()) { + case FormEditorScene::AnchorMode: { + pen.setColor(Qt::black); + pen.setWidth(m_borderWidth); + } + break; + case FormEditorScene::NormalMode: { + pen.setColor(Qt::gray); + } + break; + } + + painter->setPen(pen); + int offset = m_borderWidth / 2; + painter->drawRect(alignedRect(boundingRect().adjusted(offset, offset, -offset, -offset))); +} + +void FormEditorItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) +{ + painter->save(); + painter->setRenderHint(QPainter::Antialiasing, true); + switch(scene()->paintMode()) { + case FormEditorScene::AnchorMode: + painter->setOpacity(m_opacity); + break; + case FormEditorScene::NormalMode: + painter->setOpacity(qmlItemNode().instanceValue("opacity").toDouble()); + break; + } + + qmlItemNode().paintInstance(painter); + + painter->setRenderHint(QPainter::Antialiasing, false); + paintBoundingRect(painter); + + painter->restore(); +} + +AbstractFormEditorTool* FormEditorItem::tool() const +{ + return static_cast<FormEditorScene*>(scene())->currentTool(); +} + +SnapLineMap FormEditorItem::topSnappingLines() const +{ + return m_snappingLineCreator.topLines(); +} + +SnapLineMap FormEditorItem::bottomSnappingLines() const +{ + return m_snappingLineCreator.bottomLines(); +} + +SnapLineMap FormEditorItem::leftSnappingLines() const +{ + return m_snappingLineCreator.leftLines(); +} + +SnapLineMap FormEditorItem::rightSnappingLines() const +{ + return m_snappingLineCreator.rightLines(); +} + +SnapLineMap FormEditorItem::horizontalCenterSnappingLines() const +{ + return m_snappingLineCreator.horizontalCenterLines(); +} + +SnapLineMap FormEditorItem::verticalCenterSnappingLines() const +{ + return m_snappingLineCreator.verticalCenterLines(); +} + +SnapLineMap FormEditorItem::topSnappingOffsets() const +{ + return m_snappingLineCreator.topOffsets(); +} + +SnapLineMap FormEditorItem::bottomSnappingOffsets() const +{ + return m_snappingLineCreator.bottomOffsets(); +} + +SnapLineMap FormEditorItem::leftSnappingOffsets() const +{ + return m_snappingLineCreator.leftOffsets(); +} + +SnapLineMap FormEditorItem::rightSnappingOffsets() const +{ + return m_snappingLineCreator.rightOffsets(); +} + + +void FormEditorItem::updateSnappingLines(const QList<FormEditorItem*> &exceptionList, + FormEditorItem *transformationSpaceItem) +{ + m_snappingLineCreator.update(exceptionList, transformationSpaceItem); +} + + +QList<FormEditorItem*> FormEditorItem::childFormEditorItems() const +{ + QList<FormEditorItem*> formEditorItemList; + + foreach (QGraphicsItem *item, childItems()) { + FormEditorItem *formEditorItem = fromQGraphicsItem(item); + if (formEditorItem) + formEditorItemList.append(formEditorItem); + } + + return formEditorItemList; +} + +bool FormEditorItem::isContainer() const +{ + return qmlItemNode().modelNode().metaInfo().isContainer(); +} + +QmlItemNode FormEditorItem::qmlItemNode() const +{ + return m_qmlItemNode; +} + +} + diff --git a/src/plugins/qmldesigner/components/formeditor/formeditoritem.h b/src/plugins/qmldesigner/components/formeditor/formeditoritem.h new file mode 100644 index 0000000000..b5ffc76992 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/formeditoritem.h @@ -0,0 +1,131 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef FORMEDITORITEM_H +#define FORMEDITORITEM_H + +#include <QWeakPointer> +#include <QGraphicsWidget> +#include <qmlitemnode.h> +#include "snappinglinecreator.h" + +class QTimeLine; + +namespace QmlDesigner { + +class FormEditorScene; +class FormEditorView; +class AbstractFormEditorTool; + +namespace Internal { + class GraphicItemResizer; + class MoveController; +} + +class FormEditorItem : public QGraphicsObject +{ + Q_OBJECT + + friend class QmlDesigner::FormEditorScene; +public: + ~FormEditorItem(); + + void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0 ); + + bool isContainer() const; + QmlItemNode qmlItemNode() const; + + + enum { Type = UserType + 0xfffa }; + + int type() const; + + static FormEditorItem* fromQGraphicsItem(QGraphicsItem *graphicsItem); + + void updateSnappingLines(const QList<FormEditorItem*> &exceptionList, + FormEditorItem *transformationSpaceItem); + + SnapLineMap topSnappingLines() const; + SnapLineMap bottomSnappingLines() const; + SnapLineMap leftSnappingLines() const; + SnapLineMap rightSnappingLines() const; + SnapLineMap horizontalCenterSnappingLines() const; + SnapLineMap verticalCenterSnappingLines() const; + + SnapLineMap topSnappingOffsets() const; + SnapLineMap bottomSnappingOffsets() const; + SnapLineMap leftSnappingOffsets() const; + SnapLineMap rightSnappingOffsets() const; + + QList<FormEditorItem*> childFormEditorItems() const; + FormEditorScene *scene() const; + FormEditorItem *parentItem() const; + + QRectF boundingRect() const; + + void updateGeometry(); + void updateVisibilty(); + + void showAttention(); + + FormEditorView *formEditorView() const; + +protected: + AbstractFormEditorTool* tool() const; + void paintBoundingRect(QPainter *painter) const; + +private slots: + void changeAttention(qreal value); + +private: // functions + FormEditorItem(const QmlItemNode &qmlItemNode, FormEditorScene* scene); + void setup(); + void setAttentionScale(double scale); + void setAttentionHighlight(double value); + +private: // variables + SnappingLineCreator m_snappingLineCreator; + QmlItemNode m_qmlItemNode; + QWeakPointer<QTimeLine> m_attentionTimeLine; + QTransform m_attentionTransform; // make item larger in anchor mode + QTransform m_inverseAttentionTransform; + QRectF m_boundingRect; + double m_borderWidth; + double m_opacity; +}; + + +inline int FormEditorItem::type() const +{ + return UserType + 0xfffa; +} + +} + +#endif // FORMEDITORITEM_H diff --git a/src/plugins/qmldesigner/components/formeditor/formeditormainview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditormainview.cpp new file mode 100644 index 0000000000..d1da63fafc --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/formeditormainview.cpp @@ -0,0 +1,401 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "formeditormainview.h" + +#include "formeditorview.h" +#include "formeditorwidget.h" +#include <QPixmapCache> +#include <QtDebug> + +#include "zoomaction.h" + +namespace QmlDesigner { + + +FormEditorMainView::FormEditorMainView() + : m_formMainEditorWidget(new FormEditorMainWidget(this)) +{ + QPixmapCache::setCacheLimit(1024 * 100); +} + +FormEditorMainView::~FormEditorMainView() +{ + resetViews(); + + if (m_formMainEditorWidget) + m_formMainEditorWidget->deleteLater(); +} + +void FormEditorMainView::modelAttached(Model *model) +{ + AbstractView::modelAttached(model); + + setupSubViews(); + + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) { + if (view) + view->modelAttached(model); + } + + m_formMainEditorWidget->setModel(model); +} + +void FormEditorMainView::createSubView(const QmlModelState &state) +{ + FormEditorView *subView = new FormEditorView(this); + subView->setCurrentState(state); + m_formEditorViewList.append(subView); + + m_formMainEditorWidget->addWidget(subView->widget()); + m_subWindowMap.insert(state, subView->widget()); + + subView->setZoomLevel(zoomAction()->zoomLevel()); + connect(zoomAction(), SIGNAL(zoomLevelChanged(double)), subView, SLOT(setZoomLevel(double))); +} + +void FormEditorMainView::removeSubView(const ModelState &state) +{ + QWidget *subWindow = m_subWindowMap.take(state).data(); + Q_ASSERT(subWindow); + if (subWindow == m_formMainEditorWidget->currentWidget()) + setCurrentState(); + delete subWindow; + + FormEditorView *editorView = 0; + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) { + if (view->modelState() == state) { + editorView = view.data(); + break; + } + } + Q_ASSERT(editorView); + m_formEditorViewList.removeOne(editorView); + delete editorView; +} + +static bool modelStateLessThan(const ModelState &firstState, const ModelState &secondState) + { + if (firstState.isBaseState()) + return false; + + return firstState.name().toLower() > secondState.name().toLower(); + } + +void FormEditorMainView::setupSubViews() +{ + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) + delete view.data(); + m_formEditorViewList.clear(); + + foreach(const QWeakPointer<QWidget> &view, m_subWindowMap.values()) + delete view.data(); + m_subWindowMap.clear(); + + QList<ModelState> invertedStates(model()->modelStates()); + qSort(invertedStates.begin(), invertedStates.end(), modelStateLessThan); + foreach(const ModelState &state, invertedStates) + createSubView(state); +} + +void FormEditorMainView::resetViews() +{ + m_subWindowMap.clear(); + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) + delete view.data(); + m_formEditorViewList.clear(); +} + +void FormEditorMainView::nodeCreated(const ModelNode &createdNode) +{ + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) { + if (view) + view->nodeCreated(createdNode); + } +} + +void FormEditorMainView::modelAboutToBeDetached(Model *model) +{ + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) { + if (view) + view->modelAboutToBeDetached(model); + } + + resetViews(); + + m_formMainEditorWidget->setModel(0); + + AbstractView::modelAboutToBeDetached(model); +} + +void FormEditorMainView::nodeAboutToBeRemoved(const ModelNode &removedNode) +{ + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) { + if (view) + view->nodeAboutToBeRemoved(removedNode); + } +} + +void FormEditorMainView::propertiesAdded(const NodeState &state, const QList<NodeProperty>& propertyList) +{ + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) { + if (view) + view->propertiesAdded(state, propertyList); + } +} + +void FormEditorMainView::propertiesAboutToBeRemoved(const NodeState &state, const QList<NodeProperty>& propertyList) +{ + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) { + if (view) + view->propertiesAboutToBeRemoved(state, propertyList); + } +} + +void FormEditorMainView::propertyValuesChanged(const NodeState &state, const QList<NodeProperty>& propertyList) +{ + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) { + if (view) + view->propertyValuesChanged(state, propertyList); + } +} + +void FormEditorMainView::nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId) +{ + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) { + if (view) + view->nodeIdChanged(node, newId, oldId); + } +} + +void FormEditorMainView::nodeReparented(const ModelNode &node, const ModelNode &oldParent, const ModelNode &newParent) +{ + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) { + if (view) + view->nodeReparented(node, oldParent, newParent); + } +} + +FormEditorMainWidget *FormEditorMainView::widget() const +{ + return m_formMainEditorWidget.data(); +} + +NodeInstanceView *FormEditorMainView::nodeInstanceView(const ModelState &modelState) const +{ + foreach (const QWeakPointer<FormEditorView> &view, m_formEditorViewList) { + if (view->modelState() == modelState) + return view->nodeInstanceView(); + } + + return 0; +} + +void FormEditorMainView::selectedNodesChanged(const QList<ModelNode> &selectedNodeList, + const QList<ModelNode> &lastSelectedNodeList) +{ + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) { + if (view) + view->selectedNodesChanged(selectedNodeList, lastSelectedNodeList); + } +} + +void FormEditorMainView::modelStateAboutToBeRemoved(const ModelState &modelState) +{ + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) { + if (view) + view->modelStateAboutToBeRemoved(modelState); + } + + removeSubView(modelState); +} + +void FormEditorMainView::modelStateAdded(const ModelState &modelState) +{ + createSubView(modelState); + m_formEditorViewList.last()->modelAttached(model()); + + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) { + if (view) + view->modelStateAdded(modelState); + } +} + +void FormEditorMainView::nodeStatesAboutToBeRemoved(const QList<NodeState> &nodeStateList) +{ + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) { + if (view) + view->nodeStatesAboutToBeRemoved(nodeStateList); + } +} + +void FormEditorMainView::nodeStatesAdded(const QList<NodeState> &nodeStateList) +{ + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) { + if (view) + view->nodeStatesAdded(nodeStateList); + } +} + +void FormEditorMainView::setCurrentState(const QmlModelState &state) +{ + Q_ASSERT(m_subWindowMap.contains(state)); + m_formMainEditorWidget->setCurrentWidget(m_subWindowMap.value(state).data()); + emit stateChanged(state); +} + +ModelState FormEditorMainView::currentState() const +{ + QWidget *currentWidget = m_formMainEditorWidget->currentWidget(); + QMapIterator<ModelState, QWeakPointer<QWidget> > iter(m_subWindowMap); + while (iter.hasNext()) { + iter.next(); + if (iter.value().data() == currentWidget) { + return iter.key(); + } + } + Q_ASSERT_X(0, Q_FUNC_INFO, "cannot find current state"); + return ModelState(); +} + +FormEditorMainView::EditorTool FormEditorMainView::currentTool() const +{ + return m_currentTool; +} + +void FormEditorMainView::setCurrentTool(FormEditorMainView::EditorTool tool) +{ + if (m_currentTool == tool) + return; + m_currentTool = tool; + switch (tool) { + case MoveTool: { + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) + view->changeToMoveTool(); + break; + } + case DragTool: { + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) + view->changeToDragTool(); + break; + } + case SelectTool: { + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) + view->changeToSelectionTool(); + break; + } + case ResizeTool: { + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) + view->changeToResizeTool(); + break; + } + case AnchorTool: { + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) + view->changeToAnchorTool(); + break; + } + default: Q_ASSERT(0); + } + emit toolChanged(m_currentTool); +} + +void FormEditorMainView::changeToDragTool() +{ + setCurrentTool(DragTool); +} + + +void FormEditorMainView::changeToMoveTool() +{ + setCurrentTool(MoveTool); +} + +void FormEditorMainView::changeToMoveTool(const QPointF &/*beginPoint*/) +{ + setCurrentTool(MoveTool); +} + +void FormEditorMainView::changeToSelectionTool() +{ + setCurrentTool(SelectTool); +} + +void FormEditorMainView::changeToResizeTool() +{ + setCurrentTool(ResizeTool); +} + +void FormEditorMainView::changeToAnchorTool() +{ + setCurrentTool(AnchorTool); +} + +void FormEditorMainView::changeToTransformTools() +{ + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) + if (view) + view->changeToTransformTools(); +} + +void FormEditorMainView::anchorsChanged(const NodeState &nodeState) +{ + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) { + if (view) + view->anchorsChanged(nodeState); + } +} + + +void FormEditorMainView::auxiliaryDataChanged(const ModelNode &node, const QString &name, const QVariant &data) +{ + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) { + if (view) + view->auxiliaryDataChanged(node, name, data); + } +} + +void FormEditorMainView::nodeSlidedToIndex(const ModelNode &node, int newIndex, int oldIndex) +{ + foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) { + if (view) + view->nodeSlidedToIndex(node, newIndex, oldIndex); + } +} + +ComponentAction *FormEditorMainView::componentAction() const +{ + return m_formMainEditorWidget->componentAction(); +} + +ZoomAction *FormEditorMainView::zoomAction() const +{ + return m_formMainEditorWidget->zoomAction(); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/formeditormainview.h b/src/plugins/qmldesigner/components/formeditor/formeditormainview.h new file mode 100644 index 0000000000..05a563f09e --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/formeditormainview.h @@ -0,0 +1,123 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef FORMEDITORMAINVIEW_H +#define FORMEDITORMAINVIEW_H + +#include <forwardview.h> + +#include <formeditormainwidget.h> +#include <formeditorview.h> +#include <QPointer> + + +namespace QmlDesigner { +class AbstractFormEditorTool; + +class FormEditorMainView : public ForwardView<FormEditorView> +{ + Q_OBJECT + +public: + FormEditorMainView(); + ~FormEditorMainView(); + + // AbstractView + void modelAttached(Model *model); + void modelAboutToBeDetached(Model *model); + void nodeCreated(const ModelNode &createdNode); + void nodeAboutToBeRemoved(const ModelNode &removedNode); + void nodeReparented(const ModelNode &node, const ModelNode &oldParent, const ModelNode &newParent); + void propertiesAdded(const NodeState &state, const QList<NodeProperty>& propertyList); + void propertiesAboutToBeRemoved(const NodeState &state, const QList<NodeProperty>& propertyList); + void propertyValuesChanged(const NodeState& state, const QList<NodeProperty> &propertyList); + void nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId); + + void selectedNodesChanged(const QList<ModelNode> &selectedNodeList, + const QList<ModelNode> &lastSelectedNodeList); + + void modelStateAboutToBeRemoved(const ModelState &modelState); + void modelStateAdded(const ModelState &modelState); + + void nodeStatesAboutToBeRemoved(const QList<NodeState> &nodeStateList); + void nodeStatesAdded(const QList<NodeState> &nodeStateList); + + void auxiliaryDataChanged(const ModelNode &node, const QString &name, const QVariant &data); + // FormEditorMainView + FormEditorMainWidget *widget() const; + NodeInstanceView *nodeInstanceView(const ModelState &modelState) const; + + void setCurrentState(const ModelState &state); + ModelState currentState() const; + + enum EditorTool { + MoveTool, + DragTool, + SelectTool, + ResizeTool, + AnchorTool + }; + + EditorTool currentTool() const; + void setCurrentTool(EditorTool tool); + + void changeToMoveTool(); + void changeToMoveTool(const QPointF &beginPoint); + void changeToDragTool(); + void changeToSelectionTool(); + void changeToResizeTool(); + void changeToTransformTools(); + void changeToAnchorTool(); + + void anchorsChanged(const NodeState &nodeState); + void nodeSlidedToIndex(const ModelNode &node, int newIndex, int oldIndex); + + ComponentAction *componentAction() const; + ZoomAction *zoomAction() const; + +signals: + void stateChanged(const ModelState &state); + void toolChanged(EditorTool tool); + +protected: + void setupSubViews(); + void createSubView(const QmlModelState &state); + void removeSubView(const QmlModelState &state); + void resetViews(); + +private: + QWeakPointer<FormEditorMainWidget> m_formMainEditorWidget; + QList<QWeakPointer<FormEditorView> > m_formEditorViewList; + QMap<ModelState, QWeakPointer<QWidget> > m_subWindowMap; + EditorTool m_currentTool; +}; + +} // namespace QmlDesigner + +#endif // FORMEDITORMAINVIEW_H diff --git a/src/plugins/qmldesigner/components/formeditor/formeditormainwidget.cpp b/src/plugins/qmldesigner/components/formeditor/formeditormainwidget.cpp new file mode 100644 index 0000000000..ade4aace51 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/formeditormainwidget.cpp @@ -0,0 +1,156 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "formeditormainwidget.h" + +#include <QAction> +#include <formeditormainview.h> +#include <QtDebug> +#include <QToolBar> +#include <QVBoxLayout> +#include <QFile> +#include "toolbox.h" +#include "componentaction.h" +#include "zoomaction.h" +#include <QWheelEvent> +#include <cmath> + +namespace QmlDesigner { + +FormEditorMainWidget::FormEditorMainWidget(FormEditorMainView *mainView) + : QWidget(), + m_formEditorMainView(mainView), + m_stackedWidget(new QStackedWidget(this)) +{ + QFile file(":/qmldesigner/stylesheet.css"); + file.open(QFile::ReadOnly); + QString styleSheet = QLatin1String(file.readAll()); + setStyleSheet(styleSheet); + + QVBoxLayout *fillLayout = new QVBoxLayout(this); + fillLayout->setMargin(0); + fillLayout->setSpacing(0); + setLayout(fillLayout); + + QActionGroup *toolActionGroup = new QActionGroup(this); + + QAction *transformToolAction = toolActionGroup->addAction("Transform Tool (Press Key Q)"); + transformToolAction->setShortcut(Qt::Key_Q); + transformToolAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); + transformToolAction->setCheckable(true); + transformToolAction->setChecked(true); + transformToolAction->setIcon(QPixmap(":/icon/tool/transform.png")); + connect(transformToolAction, SIGNAL(triggered(bool)), SLOT(changeTransformTool(bool))); + + QAction *anchorToolAction = toolActionGroup->addAction("Anchor Tool (Press Key W)"); + anchorToolAction->setShortcut(Qt::Key_W); + anchorToolAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); + anchorToolAction->setCheckable(true); + anchorToolAction->setIcon(QPixmap(":/icon/tool/anchor.png")); + connect(anchorToolAction, SIGNAL(triggered(bool)), SLOT(changeAnchorTool(bool))); + + addActions(toolActionGroup->actions()); + + + m_componentAction = new ComponentAction(toolActionGroup); + addAction(m_componentAction.data()); + + m_zoomAction = new ZoomAction(toolActionGroup); + addAction(m_zoomAction.data()); + + ToolBox *toolBox = new ToolBox(this); + toolBox->setActions(actions()); + fillLayout->addWidget(toolBox); + + fillLayout->addWidget(m_stackedWidget.data()); +} + +void FormEditorMainWidget::addWidget(QWidget *widget) +{ + m_stackedWidget->addWidget(widget); +} + +QWidget *FormEditorMainWidget::currentWidget() const +{ + return m_stackedWidget->currentWidget(); +} + +void FormEditorMainWidget::setCurrentWidget(QWidget *widget) +{ + m_stackedWidget->setCurrentWidget(widget); +} + +void FormEditorMainWidget::setModel(Model *model) +{ + m_componentAction->setDisabled(true); + + if (model) { + m_componentAction->setModel(model->masterModel()); + m_componentAction->setEnabled(true); + } +} + +void FormEditorMainWidget::changeTransformTool(bool checked) +{ + if (checked) + m_formEditorMainView->changeToTransformTools(); +} + +void FormEditorMainWidget::changeAnchorTool(bool checked) +{ + if (checked) + m_formEditorMainView->changeToAnchorTool(); +} + +ComponentAction *FormEditorMainWidget::componentAction() const +{ + return m_componentAction.data(); +} + +ZoomAction *FormEditorMainWidget::zoomAction() const +{ + return m_zoomAction.data(); +} + +void FormEditorMainWidget::wheelEvent(QWheelEvent *event) +{ + if (event->modifiers().testFlag(Qt::ControlModifier)) { + if (event->delta() > 0) { + zoomAction()->zoomIn(); + } else { + zoomAction()->zoomOut(); + } + + event->accept(); + } else { + QWidget::wheelEvent(event); + } +} + +} diff --git a/src/plugins/qmldesigner/components/formeditor/formeditormainwidget.h b/src/plugins/qmldesigner/components/formeditor/formeditormainwidget.h new file mode 100644 index 0000000000..d07afa5fc4 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/formeditormainwidget.h @@ -0,0 +1,74 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef FORMEDITORMAINWIDGET_H +#define FORMEDITORMAINWIDGET_H + +#include <QStackedWidget> +#include <QWeakPointer> + + + +namespace QmlDesigner { + +class Model; +class FormEditorMainView; +class ComponentAction; +class ZoomAction; + +class FormEditorMainWidget : public QWidget +{ + Q_OBJECT +public: + FormEditorMainWidget(FormEditorMainView *mainView); + + void addWidget(QWidget *widget); + QWidget *currentWidget() const; + void setCurrentWidget(QWidget *widget); + void setModel(Model *model); + + ComponentAction *componentAction() const; + ZoomAction *zoomAction() const; + +protected: + void wheelEvent(QWheelEvent *event); + +private slots: + void changeTransformTool(bool checked); + void changeAnchorTool(bool checked); + +private: + QWeakPointer<FormEditorMainView> m_formEditorMainView; + QWeakPointer<QStackedWidget> m_stackedWidget; + QWeakPointer<ComponentAction> m_componentAction; + QWeakPointer<ZoomAction> m_zoomAction; +}; + +} +#endif // FORMEDITORMAINWIDGET_H diff --git a/src/plugins/qmldesigner/components/formeditor/formeditornodeinstanceview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditornodeinstanceview.cpp new file mode 100644 index 0000000000..7516f55934 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/formeditornodeinstanceview.cpp @@ -0,0 +1,48 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "formeditornodeinstanceview.h" +#include "formeditorview.h" + +#include <modelnode.h> +#include <QtCore/QDebug> + + +namespace QmlDesigner { + +FormEditorNodeInstanceView::FormEditorNodeInstanceView(QObject * parent) : NodeInstanceView(parent) +{ + +} + +FormEditorNodeInstanceView::~FormEditorNodeInstanceView() +{ +} + +} diff --git a/src/plugins/qmldesigner/components/formeditor/formeditornodeinstanceview.h b/src/plugins/qmldesigner/components/formeditor/formeditornodeinstanceview.h new file mode 100644 index 0000000000..b1c9909e92 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/formeditornodeinstanceview.h @@ -0,0 +1,50 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef FORMEDITORNODEINSTANCE_H +#define FORMEDITORNODEINSTANCE_H + + +#include <nodeinstanceview.h> + +namespace QmlDesigner { + +class FormEditorView; + +class FormEditorNodeInstanceView : public NodeInstanceView +{ + Q_OBJECT +public: + FormEditorNodeInstanceView(QObject * parent); + ~FormEditorNodeInstanceView(); +}; + + +} +#endif //FORMEDITORNODEINSTANCE_H diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorscene.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorscene.cpp new file mode 100644 index 0000000000..9c7c69d67a --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/formeditorscene.cpp @@ -0,0 +1,364 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "formeditorscene.h" +#include "formeditorview.h" +#include "formeditorwidget.h" +#include "formeditoritem.h" +#include "movemanipulator.h" +#include <metainfo.h> +#include <QGraphicsSceneDragDropEvent> + +#include <QEvent> +#include <QGraphicsSceneMouseEvent> +#include <QGraphicsSceneHoverEvent> +#include <QGraphicsView> + +#include <QApplication> +#include <QDebug> +#include <QList> + +#include "formeditornodeinstanceview.h" + +#include "resizehandleitem.h" +#include <QtDebug> + + + +namespace QmlDesigner { + +FormEditorScene::FormEditorScene(FormEditorWidget *view, FormEditorView *editorView) + : QGraphicsScene(), + m_editorView(editorView), + m_formLayerItem(new LayerItem(this)), + m_manipulatorLayerItem(new LayerItem(this)), + m_paintMode(NormalMode) + +{ + setSceneRect(0, 0, 1, 1); // prevent automatic calculation (causing a recursion), right size will be set later + + m_manipulatorLayerItem->setZValue(1.0); + m_formLayerItem->setZValue(0.0); + m_formLayerItem->setFlag(QGraphicsItem::ItemClipsChildrenToShape, true); + view->setScene(this); + +// setItemIndexMethod(QGraphicsScene::NoIndex); +} + +FormEditorScene::~FormEditorScene() +{ + clear(); //FormEditorItems have to be cleared before destruction + //Reason: FormEditorItems accesses FormEditorScene in destructor +} + + +FormEditorItem* FormEditorScene::itemForQmlItemNode(const QmlItemNode &qmlItemNode) const +{ + Q_ASSERT(hasItemForQmlItemNode(qmlItemNode)); + return m_qmlItemNodeItemHash.value(qmlItemNode); +} + + +QList<FormEditorItem*> FormEditorScene::itemsForQmlItemNodes(const QList<QmlItemNode> &nodeList) const +{ + QList<FormEditorItem*> itemList; + foreach (const QmlItemNode &node, nodeList) { + if (hasItemForQmlItemNode(node)) + itemList += itemForQmlItemNode(node); + } + + return itemList; +} + +QList<FormEditorItem*> FormEditorScene::allFormEditorItems() const +{ + return m_qmlItemNodeItemHash.values(); +} + +void FormEditorScene::updateAllFormEditorItems() +{ + foreach (FormEditorItem *item, allFormEditorItems()) { + item->update(); + } +} + +bool FormEditorScene::hasItemForQmlItemNode(const QmlItemNode &qmlItemNode) const +{ + return m_qmlItemNodeItemHash.contains(qmlItemNode); +} + +void FormEditorScene::removeItemFromHash(FormEditorItem *item) +{ + m_qmlItemNodeItemHash.remove(item->qmlItemNode()); +} + + +AbstractFormEditorTool* FormEditorScene::currentTool() const +{ + return m_editorView->currentTool(); +} + +//This method calculates the possible parent for reparent +FormEditorItem* FormEditorScene::calulateNewParent(FormEditorItem *formEditorItem) +{ + QList<QGraphicsItem *> list = items(formEditorItem->qmlItemNode().instanceBoundingRect().center()); + foreach (QGraphicsItem *graphicsItem, list) { + if (qgraphicsitem_cast<FormEditorItem*>(graphicsItem) && + graphicsItem->collidesWithItem(formEditorItem, Qt::ContainsItemShape)) + return qgraphicsitem_cast<FormEditorItem*>(graphicsItem); + } + return 0; +} + +void FormEditorScene::synchronizeTransformation(const QmlItemNode &qmlItemNode) +{ + FormEditorItem *item = itemForQmlItemNode(qmlItemNode); + item->updateGeometry(); + item->update(); + + if (qmlItemNode.isRootNode()) { + QRectF sceneRect(qmlItemNode.instanceBoundingRect()); + + setSceneRect(sceneRect); + formLayerItem()->update(); + manipulatorLayerItem()->update(); + } +} + +void FormEditorScene::synchronizeParent(const QmlItemNode &qmlItemNode) +{ + QmlItemNode parentNode = qmlItemNode.instanceParent().toQmlItemNode(); + if (parentNode.isValid()) + reparentItem(qmlItemNode, parentNode); +} + +void FormEditorScene::synchronizeOtherProperty(const QmlItemNode &qmlItemNode) +{ + if (hasItemForQmlItemNode(qmlItemNode)) { + FormEditorItem *item = itemForQmlItemNode(qmlItemNode); + if (item) + item->update(); + } +} + +void FormEditorScene::synchronizeState(const QmlItemNode &qmlItemNode) +{ + if (hasItemForQmlItemNode(qmlItemNode)) { + FormEditorItem *item = itemForQmlItemNode(qmlItemNode); + if (item) + item->update(); + } +} + + +FormEditorItem *FormEditorScene::addFormEditorItem(const QmlItemNode &qmlItemNode) +{ + FormEditorItem *formEditorItem = new FormEditorItem(qmlItemNode, this); + Q_ASSERT(!m_qmlItemNodeItemHash.contains(qmlItemNode)); + + m_qmlItemNodeItemHash.insert(qmlItemNode, formEditorItem); + if (qmlItemNode.isRootNode()) { + QRectF sceneRect(qmlItemNode.instanceBoundingRect()); + + setSceneRect(sceneRect); + formLayerItem()->update(); + manipulatorLayerItem()->update(); + } + + return formEditorItem; +} + + +void FormEditorScene::dropEvent(QGraphicsSceneDragDropEvent * event) +{ + currentTool()->dropEvent(event); + + if (views().first()) + views().first()->setFocus(); +} + +void FormEditorScene::dragEnterEvent(QGraphicsSceneDragDropEvent * event) +{ + currentTool()->dragEnterEvent(event); +} + +void FormEditorScene::dragLeaveEvent(QGraphicsSceneDragDropEvent * event) +{ + currentTool()->dragLeaveEvent(event); + + return; + + if (m_dragNode.isValid()) { + m_dragNode.destroy(); + } +} + +void FormEditorScene::dragMoveEvent(QGraphicsSceneDragDropEvent * event) +{ + currentTool()->dragMoveEvent(event); +} + +QList<QGraphicsItem *> FormEditorScene::removeLayerItems(const QList<QGraphicsItem *> &itemList) +{ + QList<QGraphicsItem *> itemListWithoutLayerItems; + + foreach (QGraphicsItem *item, itemList) + if (item != manipulatorLayerItem() && item != formLayerItem()) + itemListWithoutLayerItems.append(item); + + return itemListWithoutLayerItems; +} + +void FormEditorScene::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + currentTool()->mousePressEvent(removeLayerItems(items(event->scenePos())), event); +} + +void FormEditorScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + if (event->buttons()) + currentTool()->mouseMoveEvent(removeLayerItems(items(event->scenePos())), event); + else + currentTool()->hoverMoveEvent(removeLayerItems(items(event->scenePos())), event); + + event->accept(); +} + +void FormEditorScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + currentTool()->mouseReleaseEvent(removeLayerItems(items(event->scenePos())), event); + + event->accept(); + } + +void FormEditorScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) +{ + currentTool()->mouseDoubleClickEvent(removeLayerItems(items(event->scenePos())), event); + + event->accept(); +} + +void FormEditorScene::keyPressEvent(QKeyEvent *keyEvent) +{ + currentTool()->keyPressEvent(keyEvent); +} + +void FormEditorScene::keyReleaseEvent(QKeyEvent *keyEvent) +{ + currentTool()->keyReleaseEvent(keyEvent); +} + +FormEditorView *FormEditorScene::editorView() const +{ + return m_editorView; +} + +LayerItem* FormEditorScene::manipulatorLayerItem() const +{ + return m_manipulatorLayerItem.data(); +} + +LayerItem* FormEditorScene::formLayerItem() const +{ + return m_formLayerItem.data(); +} + +bool FormEditorScene::event(QEvent * event) +{ + switch(event->type()) + { + case QEvent::GraphicsSceneHoverEnter : + hoverEnterEvent(static_cast<QGraphicsSceneHoverEvent *>(event)); + return true; + case QEvent::GraphicsSceneHoverMove : + hoverMoveEvent(static_cast<QGraphicsSceneHoverEvent *>(event)); + return true; + case QEvent::GraphicsSceneHoverLeave : + hoverLeaveEvent(static_cast<QGraphicsSceneHoverEvent *>(event)); + return true; + default: return QGraphicsScene::event(event); + } + +} + +void FormEditorScene::hoverEnterEvent(QGraphicsSceneHoverEvent * /*event*/) +{ + qDebug() << __FUNCTION__; +} + +void FormEditorScene::hoverMoveEvent(QGraphicsSceneHoverEvent * /*event*/) +{ + qDebug() << __FUNCTION__; +} + +void FormEditorScene::hoverLeaveEvent(QGraphicsSceneHoverEvent * /*event*/) +{ + qDebug() << __FUNCTION__; +} + + +void FormEditorScene::reparentItem(const QmlItemNode &node, const QmlItemNode &newParent) +{ + Q_ASSERT(hasItemForQmlItemNode(node)); + Q_ASSERT(hasItemForQmlItemNode(newParent)); + FormEditorItem *item = itemForQmlItemNode(node); + FormEditorItem *parentItem = itemForQmlItemNode(newParent); + item->setParentItem(parentItem); + item->setParent(parentItem); +} + +FormEditorItem* FormEditorScene::rootFormEditorItem() const +{ + QList<QGraphicsItem*> childItemList(m_formLayerItem->childItems()); + if (!childItemList.isEmpty()) + return FormEditorItem::fromQGraphicsItem(childItemList.first()); + + return 0; +} + +FormEditorScene::PaintMode FormEditorScene::paintMode() const +{ + return m_paintMode; +} + +void FormEditorScene::setPaintMode(PaintMode paintMode) +{ + m_paintMode = paintMode; +} + +void FormEditorScene::clearFormEditorItems() +{ + foreach (QGraphicsItem *item, items()) { + if (qgraphicsitem_cast<FormEditorItem* >(item)) + delete item; + } +} + +} + diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorscene.h b/src/plugins/qmldesigner/components/formeditor/formeditorscene.h new file mode 100644 index 0000000000..89098ba7ab --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/formeditorscene.h @@ -0,0 +1,133 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef FORMEDITORSCENE_H +#define FORMEDITORSCENE_H + + +#include <QGraphicsScene> +#include <QWeakPointer> +#include <QHash> +#include <qmlitemnode.h> +#include "abstractformeditortool.h" + + +class QGraphicsSceneMouseEvent; + +namespace QmlDesigner { + +class FormEditorWidget; +class FormEditorItem; +class FormEditorView; +class LayerItem; + +class FormEditorScene : public QGraphicsScene +{ + Q_OBJECT + + friend class QmlDesigner::FormEditorItem; + friend class QmlDesigner::FormEditorView; + +public: + enum PaintMode { + NormalMode, + AnchorMode + }; + + FormEditorScene(FormEditorWidget *widget, FormEditorView *editorView); + ~FormEditorScene(); + FormEditorItem *addFormEditorItem(const QmlItemNode &qmlItemNode); + + FormEditorItem* itemForQmlItemNode(const QmlItemNode &qmlItemNode) const; + + QList<FormEditorItem*> itemsForQmlItemNodes(const QList<QmlItemNode> &nodeList) const; + QList<FormEditorItem*> allFormEditorItems() const; + + void updateAllFormEditorItems(); + + bool hasItemForQmlItemNode(const QmlItemNode &qmlItemNode) const; + + void synchronizeTransformation(const QmlItemNode &qmlItemNode); + void synchronizeParent(const QmlItemNode &qmlItemNode); + void synchronizeOtherProperty(const QmlItemNode &qmlItemNode); + void synchronizeState(const QmlItemNode &qmlItemNode); + + FormEditorItem* calulateNewParent(FormEditorItem *widget); + bool event(QEvent *event); + LayerItem* manipulatorLayerItem() const; + LayerItem* formLayerItem() const; + FormEditorView *editorView() const; + + FormEditorItem *rootFormEditorItem() const; + + void reparentItem(const QmlItemNode &node, const QmlItemNode &newParent); + + PaintMode paintMode() const; + void setPaintMode(PaintMode paintMode); + + void clearFormEditorItems(); + +protected: + void dropEvent(QGraphicsSceneDragDropEvent * event); + void dragEnterEvent(QGraphicsSceneDragDropEvent * event); + void dragLeaveEvent(QGraphicsSceneDragDropEvent * event); + void dragMoveEvent(QGraphicsSceneDragDropEvent * event); + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); + + void hoverEnterEvent(QGraphicsSceneHoverEvent *event); + void hoverMoveEvent(QGraphicsSceneHoverEvent *event); + void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); + + void keyPressEvent(QKeyEvent *keyEvent); + void keyReleaseEvent(QKeyEvent *keyEvent); + +private: + QList<QGraphicsItem *> removeLayerItems(const QList<QGraphicsItem *> &itemList); + + AbstractFormEditorTool* currentTool() const; + void removeItemFromHash(FormEditorItem*); + + FormEditorView *m_editorView; + AbstractFormEditorTool *m_currentTool; + QHash<QmlItemNode, FormEditorItem*> m_qmlItemNodeItemHash; + QWeakPointer<LayerItem> m_formLayerItem; + QWeakPointer<LayerItem> m_manipulatorLayerItem; + ModelNode m_dragNode; + PaintMode m_paintMode; +}; + + + + +} +#endif //FORMEDITORSCENE_H + diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorsubwindow.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorsubwindow.cpp new file mode 100644 index 0000000000..8fe38a042e --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/formeditorsubwindow.cpp @@ -0,0 +1,38 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "formeditorsubwindow.h" + +namespace QmlDesigner { + +FormEditorSubWindow::FormEditorSubWindow() +{ +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorsubwindow.h b/src/plugins/qmldesigner/components/formeditor/formeditorsubwindow.h new file mode 100644 index 0000000000..9376d73b89 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/formeditorsubwindow.h @@ -0,0 +1,45 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef FORMEDITORSUBWINDOW_H +#define FORMEDITORSUBWINDOW_H + +#include <QMdiSubWindow> + +namespace QmlDesigner { + +class FormEditorSubWindow : public QMdiSubWindow +{ +public: + FormEditorSubWindow(); +}; + +} // namespace QmlDesigner + +#endif // FORMEDITORSUBWINDOW_H diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp new file mode 100644 index 0000000000..7da0cb9ed5 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp @@ -0,0 +1,531 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "selectiontool.h" +#include "movetool.h" +#include "resizetool.h" +#include "anchortool.h" +#include "dragtool.h" +#include "itemcreatortool.h" +#include "formeditorview.h" +#include "formeditorwidget.h" +#include "formeditornodeinstanceview.h" +#include "formeditoritem.h" +#include "formeditorscene.h" +#include <rewritertransaction.h> +#include <modelnode.h> +#include <modelutilities.h> +#include <itemlibraryinfo.h> +#include <metainfo.h> +#include <model.h> +#include <QApplication> +#include <QtDebug> +#include <QPair> +#include <QString> +#include <QDir> +#include <QAction> +#include <zoomaction.h> + +namespace QmlDesigner { + +FormEditorView::FormEditorView(QObject *parent) + : QmlModelView(parent), + m_formEditorWidget(new FormEditorWidget(this)), + m_scene(new FormEditorScene(m_formEditorWidget.data(), this)), + m_moveTool(new MoveTool(this)), + m_selectionTool(new SelectionTool(this)), + m_resizeTool(new ResizeTool(this)), + m_anchorTool(new AnchorTool(this)), + m_dragTool(new DragTool(this)), + m_itemCreatorTool(new ItemCreatorTool(this)), + m_currentTool(m_selectionTool) +{ + connect(widget()->zoomAction(), SIGNAL(zoomLevelChanged(double)), SLOT(updateGraphicsIndicators())); +} + +FormEditorScene* FormEditorView::scene() const +{ + return m_scene.data(); +} + +FormEditorView::~FormEditorView() +{ + delete m_selectionTool; + m_selectionTool = 0; + delete m_moveTool; + m_moveTool = 0; + delete m_resizeTool; + m_resizeTool = 0; + delete m_anchorTool; + m_anchorTool = 0; + delete m_dragTool; + m_dragTool = 0; + + + // delete scene after tools to prevent double deletion + // of items + delete m_scene.data(); + delete m_formEditorWidget.data(); +} + +void FormEditorView::modelAttached(Model *model) +{ + Q_ASSERT(model); + + QmlModelView::modelAttached(model); + + Q_ASSERT(m_scene->formLayerItem()); + + if (rootQmlObjectNode().toQmlItemNode().isValid()) + setupFormEditorItemTree(rootQmlObjectNode().toQmlItemNode()); +} + + +//This method does the setup of the inital FormEditorItem tree in the scene +void FormEditorView::setupFormEditorItemTree(const QmlItemNode &qmlItemNode) +{ + m_scene->addFormEditorItem(qmlItemNode); + + foreach (const QmlItemNode &nextNode, qmlItemNode.children()) //TODO instance children + setupFormEditorItemTree(nextNode); +} + +void FormEditorView::nodeCreated(const ModelNode &createdNode) +{ + QmlModelView::nodeCreated(createdNode); + ModelNode node(createdNode); + if (QmlItemNode(node).isValid()) //only setup QmlItems + setupFormEditorItemTree(QmlItemNode(node)); +} + +void FormEditorView::modelAboutToBeDetached(Model *model) +{ + m_selectionTool->clear(); + m_moveTool->clear(); + m_resizeTool->clear(); + m_anchorTool->clear(); + m_dragTool->clear(); + m_scene->clearFormEditorItems(); + + QmlModelView::modelAboutToBeDetached(model); +} + +void FormEditorView::nodeAboutToBeRemoved(const ModelNode &removedNode) +{ + QmlItemNode qmlItemNode(removedNode); + + if (qmlItemNode.isValid()) { + + FormEditorItem *item = m_scene->itemForQmlItemNode(qmlItemNode); + + QList<QmlItemNode> nodeList; + nodeList.append(qmlItemNode.allSubModelNodes()); + nodeList.append(qmlItemNode); + + QList<FormEditorItem*> removedItemList; + removedItemList.append(scene()->itemsForQmlItemNodes(nodeList)); + m_currentTool->itemsAboutToRemoved(removedItemList); + + delete item; + } + + QmlModelView::nodeAboutToBeRemoved(removedNode); +} + + void FormEditorView::nodeTypeChanged(const ModelNode &node,const QString &type, int majorVersion, int minorVersion) + { + QmlItemNode oldItemNode(node); + if (oldItemNode.isValid() && m_scene->hasItemForQmlItemNode(oldItemNode)) { + FormEditorItem *item = m_scene->itemForQmlItemNode(oldItemNode); + + QList<QmlItemNode> nodeList; + nodeList.append(oldItemNode.allSubModelNodes()); + nodeList.append(oldItemNode); + + QList<FormEditorItem*> removedItemList; + removedItemList.append(scene()->itemsForQmlItemNodes(nodeList)); + m_currentTool->itemsAboutToRemoved(removedItemList); + + delete item; + } + + QmlModelView::nodeTypeChanged(node, type, majorVersion, minorVersion); + + QmlItemNode newItemNode(node); + if (newItemNode.isValid()) //only setup QmlItems + setupFormEditorItemTree(newItemNode); + } + +void FormEditorView::propertiesAboutToBeRemoved(const QList<AbstractProperty>& propertyList) +{ + QmlModelView::propertiesAboutToBeRemoved(propertyList); +} +void FormEditorView::nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange) +{ + QmlModelView::nodeReparented(node, newPropertyParent, oldPropertyParent, propertyChange); +} + +void FormEditorView::variantPropertiesChanged(const QList<VariantProperty>& propertyList, PropertyChangeFlags propertyChange) +{ + QmlModelView::variantPropertiesChanged(propertyList, propertyChange); +} + +void FormEditorView::bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags propertyChange) +{ + QmlModelView::bindingPropertiesChanged(propertyList, propertyChange); +} + +FormEditorWidget *FormEditorView::widget() const +{ + Q_ASSERT(!m_formEditorWidget.isNull()); + return m_formEditorWidget.data(); +} + +void FormEditorView::nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId) +{ + nodeInstanceView()->nodeIdChanged(node, newId, oldId); +} + +void FormEditorView::selectedNodesChanged(const QList<ModelNode> &selectedNodeList, + const QList<ModelNode> &lastSelectedNodeList) +{ + QmlModelView::selectedNodesChanged(selectedNodeList, lastSelectedNodeList); + + m_currentTool->setItems(scene()->itemsForQmlItemNodes(toQmlItemNodeList(selectedNodeList))); + if (scene()->paintMode() == FormEditorScene::AnchorMode) { + foreach (FormEditorItem *item, m_scene->itemsForQmlItemNodes(toQmlItemNodeList(selectedNodeList))) + item->update(); + + foreach (FormEditorItem *item, m_scene->itemsForQmlItemNodes(toQmlItemNodeList(lastSelectedNodeList))) + item->update(); + } + + m_scene->update(); +} + +AbstractFormEditorTool* FormEditorView::currentTool() const +{ + return m_currentTool; +} + +void FormEditorView::changeToMoveTool() +{ + if (m_currentTool == m_moveTool) + return; + + scene()->setPaintMode(FormEditorScene::NormalMode); + m_scene->updateAllFormEditorItems(); + setCursor(Qt::SizeAllCursor); + m_currentTool->clear(); + m_currentTool = m_moveTool; + m_currentTool->clear(); + m_currentTool->setItems(scene()->itemsForQmlItemNodes(selectedQmlItemNodes())); +} + +void FormEditorView::changeToDragTool() +{ + if (m_currentTool == m_dragTool) + return; + + scene()->setPaintMode(FormEditorScene::NormalMode); + m_scene->updateAllFormEditorItems(); + setCursor(Qt::ArrowCursor); + setCurrentState(baseState()); + m_currentTool->clear(); + m_currentTool = m_dragTool; + m_currentTool->clear(); + m_currentTool->setItems(scene()->itemsForQmlItemNodes(selectedQmlItemNodes())); +} + + +void FormEditorView::changeToMoveTool(const QPointF &beginPoint) +{ + if (m_currentTool == m_moveTool) + return; + + scene()->setPaintMode(FormEditorScene::NormalMode); + m_scene->updateAllFormEditorItems(); + setCursor(Qt::SizeAllCursor); + m_currentTool->clear(); + m_currentTool = m_moveTool; + m_currentTool->clear(); + m_currentTool->setItems(scene()->itemsForQmlItemNodes(selectedQmlItemNodes())); + m_moveTool->beginWithPoint(beginPoint); +} + +void FormEditorView::changeToSelectionTool() +{ + if (m_currentTool == m_selectionTool) + return; + + scene()->setPaintMode(FormEditorScene::NormalMode); + m_scene->updateAllFormEditorItems(); + setCursor(Qt::ArrowCursor); + m_currentTool->clear(); + m_currentTool = m_selectionTool; + m_currentTool->clear(); + m_currentTool->setItems(scene()->itemsForQmlItemNodes(selectedQmlItemNodes())); +} + +void FormEditorView::changeToItemCreatorTool() +{ + if(m_currentTool == m_itemCreatorTool) + return; + + scene()->setPaintMode(FormEditorScene::NormalMode); + m_scene->updateAllFormEditorItems(); + setCursor(Qt::CrossCursor); + setCurrentState(baseState()); + m_currentTool->clear(); + m_currentTool = m_itemCreatorTool; + m_currentTool->clear(); + setSelectedQmlItemNodes(QList<QmlItemNode>()); + m_currentTool->setItems(scene()->itemsForQmlItemNodes(selectedQmlItemNodes())); +} + +void FormEditorView::changeToSelectionTool(QGraphicsSceneMouseEvent *event) +{ + if (m_currentTool == m_selectionTool) + return; + + scene()->setPaintMode(FormEditorScene::NormalMode); + m_scene->updateAllFormEditorItems(); + setCursor(Qt::ArrowCursor); + m_currentTool->clear(); + m_currentTool = m_selectionTool; + m_currentTool->clear(); + m_currentTool->setItems(scene()->itemsForQmlItemNodes(selectedQmlItemNodes())); + + m_selectionTool->selectUnderPoint(event); +} + +void FormEditorView::changeToResizeTool() +{ + if (m_currentTool == m_resizeTool) + return; + + scene()->setPaintMode(FormEditorScene::NormalMode); + m_scene->updateAllFormEditorItems(); + setCursor(Qt::ArrowCursor); + m_currentTool->clear(); + m_currentTool = m_resizeTool; + m_currentTool->clear(); + m_currentTool->setItems(scene()->itemsForQmlItemNodes(selectedQmlItemNodes())); +} + +void FormEditorView::changeToAnchorTool() +{ + if (m_currentTool == m_anchorTool) + return; + + scene()->setPaintMode(FormEditorScene::AnchorMode); + m_scene->updateAllFormEditorItems(); + setCursor(Qt::ArrowCursor); + m_currentTool->clear(); + m_currentTool = m_anchorTool; + m_currentTool->clear(); + m_currentTool->setItems(scene()->itemsForQmlItemNodes(selectedQmlItemNodes())); +} + +void FormEditorView::changeToTransformTools() +{ + if (m_currentTool == m_moveTool || + m_currentTool == m_resizeTool || + m_currentTool == m_selectionTool) + return; + + changeToSelectionTool(); +} + +void FormEditorView::setCursor(const QCursor &cursor) +{ + m_formEditorWidget->setCursor(cursor); +} + +bool FormEditorView::isSnapButtonChecked() const +{ + return m_formEditorWidget->isSnapButtonChecked(); +} + + +void FormEditorView::nodeSlidedToIndex(const NodeListProperty &listProperty, int /*newIndex*/, int /*oldIndex*/) +{ + QList<ModelNode> newOrderModelNodeList = listProperty.toModelNodeList(); + foreach(const ModelNode &node, newOrderModelNodeList) { + FormEditorItem *item = m_scene->itemForQmlItemNode(QmlItemNode(node)); + if (item) { + FormEditorItem *oldParentItem = item->parentItem(); + item->setParentItem(0); + item->setParentItem(oldParentItem); + } + } + + m_currentTool->formEditorItemsChanged(scene()->allFormEditorItems()); +} + +void FormEditorView::auxiliaryDataChanged(const ModelNode &node, const QString &name, const QVariant &data) +{ + QmlModelView::auxiliaryDataChanged(node, name, data); + if (name == "invisible") { + FormEditorItem *item(m_scene->itemForQmlItemNode(QmlItemNode(node))); + bool isInvisible = data.toBool(); + item->setVisible(!isInvisible); + ModelNode newNode(node); + if (isInvisible) + newNode.deselectNode(); + } +} + +double FormEditorView::margins() const +{ + return m_formEditorWidget->margins(); +} + +double FormEditorView::spacing() const +{ + return m_formEditorWidget->spacing(); +} + +void FormEditorView::activateItemCreator(const QString &name) +{ + if (m_currentTool == m_itemCreatorTool) { + m_itemCreatorTool->setItemString(name); + return; + } + changeToItemCreatorTool(); + m_itemCreatorTool->setItemString(name); +} + +void FormEditorView::deActivateItemCreator() +{ + if (m_currentTool == m_itemCreatorTool) { + changeToSelectionTool(); + emit ItemCreatorDeActivated(); + } +} + +QList<ModelNode> FormEditorView::adjustStatesForModelNodes(const QList<ModelNode> &nodeList) const +{ + QList<ModelNode> adjustedNodeList; + foreach (const ModelNode &node, nodeList) + adjustedNodeList.append(node); + + return adjustedNodeList; +} + +QmlItemNode findRecursiveQmlItemNode(const QmlObjectNode &firstQmlObjectNode) +{ + QmlObjectNode qmlObjectNode = firstQmlObjectNode; + + while (true) { + QmlItemNode itemNode = qmlObjectNode.toQmlItemNode(); + if (itemNode.isValid()) + return itemNode; + if (qmlObjectNode.hasInstanceParent()) + qmlObjectNode = qmlObjectNode.instanceParent(); + else + break; + } + + return QmlItemNode(); +} + +void FormEditorView::transformChanged(const QmlObjectNode &qmlObjectNode) +{ + QmlItemNode itemNode = qmlObjectNode.toQmlItemNode(); + if (itemNode.isValid() && scene()->hasItemForQmlItemNode(itemNode)) { + m_scene->synchronizeTransformation(itemNode); + m_currentTool->formEditorItemsChanged(QList<FormEditorItem*>() << m_scene->itemForQmlItemNode(itemNode)); + } +} + +void FormEditorView::parentChanged(const QmlObjectNode &qmlObjectNode) +{ + QmlItemNode itemNode = qmlObjectNode.toQmlItemNode(); + QmlItemNode parentNode = qmlObjectNode.instanceParent().toQmlItemNode(); + if (itemNode.isValid() + && scene()->hasItemForQmlItemNode(itemNode) + && parentNode.isValid() + && scene()->hasItemForQmlItemNode(parentNode) + && scene()->itemForQmlItemNode(itemNode)->parentItem() != scene()->itemForQmlItemNode(parentNode)) { + scene()->synchronizeParent(itemNode); + m_currentTool->formEditorItemsChanged(QList<FormEditorItem*>() << m_scene->itemForQmlItemNode(itemNode)); + } +} + +void FormEditorView::otherPropertyChanged(const QmlObjectNode &qmlObjectNode) +{ + Q_ASSERT(qmlObjectNode.isValid()); + + QmlItemNode itemNode = findRecursiveQmlItemNode(qmlObjectNode); + + if (itemNode.isValid() && scene()->hasItemForQmlItemNode(itemNode)) { + m_scene->synchronizeOtherProperty(itemNode); + m_currentTool->formEditorItemsChanged(QList<FormEditorItem*>() << m_scene->itemForQmlItemNode(itemNode)); + } +} + +void FormEditorView::updateGraphicsIndicators() +{ + m_currentTool->formEditorItemsChanged(scene()->allFormEditorItems()); +} + +void FormEditorView::updateItem(const QmlObjectNode &qmlObjectNode) +{ + + Q_ASSERT(qmlObjectNode.isValid()); + + QmlItemNode itemNode = findRecursiveQmlItemNode(qmlObjectNode); + + if (itemNode.isValid() && scene()->hasItemForQmlItemNode(itemNode)) { + m_scene->synchronizeOtherProperty(itemNode); + m_currentTool->formEditorItemsChanged(QList<FormEditorItem*>() << m_scene->itemForQmlItemNode(itemNode)); + } +} + +void FormEditorView::stateChanged(const QmlModelState &newQmlModelState, const QmlModelState &oldQmlModelState) +{ + QmlModelView::stateChanged(newQmlModelState, oldQmlModelState); + + + m_formEditorWidget->anchorToolAction()->setEnabled(newQmlModelState.isBaseState()); + + if (!newQmlModelState.isBaseState() && currentTool() == m_anchorTool) { + changeToTransformTools(); + m_formEditorWidget->transformToolAction()->setChecked(true); + } + +// FormEditorItem *item = m_scene->itemForQmlItemNode(fxObjectNode); +// +// m_currentTool->formEditorItemsChanged(itemList); +} + + +} + diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.h b/src/plugins/qmldesigner/components/formeditor/formeditorview.h new file mode 100644 index 0000000000..82b6f18a75 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.h @@ -0,0 +1,141 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef FORMEDITORVIEW_H +#define FORMEDITORVIEW_H + +#include <qmlmodelview.h> + +class QGraphicsScene; +class QGraphicsSceneMouseEvent; + +namespace QmlDesigner { + +class FormEditorWidget; +class FormEditorNodeInstanceView; +class FormEditorScene; +class NodeInstanceView; + +class AbstractFormEditorTool; +class MoveTool; +class SelectionTool; +class ResizeTool; +class AnchorTool; +class DragTool; +class ItemCreatorTool; +class ItemLibraryInfo; +class QmlItemNode; + +class FormEditorView : public QmlModelView +{ + Q_OBJECT + +public: + FormEditorView(QObject *parent); + ~FormEditorView(); + + // AbstractView + void modelAttached(Model *model); + void modelAboutToBeDetached(Model *model); + + void nodeCreated(const ModelNode &createdNode); + void nodeAboutToBeRemoved(const ModelNode &removedNode); + void nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange); + void nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId); + void propertiesAboutToBeRemoved(const QList<AbstractProperty>& propertyList); + void variantPropertiesChanged(const QList<VariantProperty>& propertyList, PropertyChangeFlags propertyChange); + void bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags propertyChange); + void nodeTypeChanged(const ModelNode &node,const QString &type, int majorVersion, int minorVersion); + + void selectedNodesChanged(const QList<ModelNode> &selectedNodeList, + const QList<ModelNode> &lastSelectedNodeList); + + // FormEditorView + FormEditorWidget *widget() const; + AbstractFormEditorTool *currentTool() const; + FormEditorScene *scene() const; + + void changeToMoveTool(); + void changeToMoveTool(const QPointF &beginPoint); + void changeToDragTool(); + void changeToSelectionTool(); + void changeToItemCreatorTool(); + void changeToSelectionTool(QGraphicsSceneMouseEvent *event); + void changeToResizeTool(); + void changeToAnchorTool(); + void changeToTransformTools(); + + void setCursor(const QCursor &cursor); + + bool isSnapButtonChecked() const; + + void nodeSlidedToIndex(const NodeListProperty &listProperty, int newIndex, int oldIndex); + void auxiliaryDataChanged(const ModelNode &node, const QString &name, const QVariant &data); + + double margins() const; + double spacing() const; + void deActivateItemCreator(); + +public slots: + void activateItemCreator(const QString &name); + +signals: + void ItemCreatorDeActivated(); + +protected: + void transformChanged(const QmlObjectNode &qmlObjectNode); + void parentChanged(const QmlObjectNode &qmlObjectNode); + void otherPropertyChanged(const QmlObjectNode &qmlObjectNode); + void updateItem(const QmlObjectNode &qmlObjectNode); + void stateChanged(const QmlModelState &newQmlModelState, const QmlModelState &oldQmlModelState); + +protected slots: + QList<ModelNode> adjustStatesForModelNodes(const QList<ModelNode> &nodeList) const; + void updateGraphicsIndicators(); + +private: //functions + void setupFormEditorItemTree(const QmlItemNode &qmlItemNode); + + +private: //variables + QWeakPointer<FormEditorWidget> m_formEditorWidget; + QWeakPointer<FormEditorScene> m_scene; + MoveTool *m_moveTool; + SelectionTool *m_selectionTool; + ResizeTool *m_resizeTool; + AnchorTool *m_anchorTool; + DragTool *m_dragTool; + ItemCreatorTool *m_itemCreatorTool; + AbstractFormEditorTool *m_currentTool; + +}; + +} + +#endif //FORMEDITORVIEW_H diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp new file mode 100644 index 0000000000..5217711fa4 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp @@ -0,0 +1,221 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "formeditorwidget.h" + +#include <QWheelEvent> +#include <cmath> +#include <QCoreApplication> +#include <QPushButton> +#include <QFile> +#include <QVBoxLayout> +#include <QActionGroup> +#include <QGraphicsView> +#include <toolbox.h> +#include <zoomaction.h> +#include <formeditorgraphicsview.h> +#include <formeditorscene.h> +#include <formeditorview.h> +#include "numberseriesaction.h" + +namespace QmlDesigner { + +FormEditorWidget::FormEditorWidget(FormEditorView *view) + : QWidget(), + m_formEditorView(view) +{ + QFile file(":/qmldesigner/stylesheet.css"); + file.open(QFile::ReadOnly); + QString styleSheet = QLatin1String(file.readAll()); + setStyleSheet(styleSheet); + + QVBoxLayout *fillLayout = new QVBoxLayout(this); + fillLayout->setMargin(0); + fillLayout->setSpacing(0); + setLayout(fillLayout); + + m_toolActionGroup = new QActionGroup(this); + + m_transformToolAction = m_toolActionGroup->addAction("Transform Tool (Press Key Q)"); + m_transformToolAction->setShortcut(Qt::Key_Q); + m_transformToolAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); + m_transformToolAction->setCheckable(true); + m_transformToolAction->setChecked(true); + m_transformToolAction->setIcon(QPixmap(":/icon/tool/transform.png")); + connect(m_transformToolAction.data(), SIGNAL(triggered(bool)), SLOT(changeTransformTool(bool))); + + m_anchorToolAction = m_toolActionGroup->addAction("Anchor Tool (Press Key W)"); + m_anchorToolAction->setShortcut(Qt::Key_W); + m_anchorToolAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); + m_anchorToolAction->setCheckable(true); + m_anchorToolAction->setIcon(QPixmap(":/icon/tool/anchor.png")); + connect(m_anchorToolAction.data(), SIGNAL(triggered(bool)), SLOT(changeAnchorTool(bool))); + + addActions(m_toolActionGroup->actions()); + + QActionGroup *layoutActionGroup = new QActionGroup(this); + layoutActionGroup->setExclusive(false); + + m_snappingToolAction = layoutActionGroup->addAction("Toogle Snapping (Press Key E)"); + m_snappingToolAction->setShortcut(Qt::Key_E); + m_snappingToolAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); + m_snappingToolAction->setCheckable(true); + m_snappingToolAction->setChecked(true); + m_snappingToolAction->setIcon(QPixmap(":/icon/layout/snapping.png")); + connect(m_snappingToolAction.data(), SIGNAL(triggered(bool)), SLOT(changeSnappingTool(bool))); + + m_snappingMarginAction = new NumberSeriesAction(layoutActionGroup); + m_snappingMarginAction->addEntry("no margins (0)", 0); + m_snappingMarginAction->addEntry("small margin (2)", 2); + m_snappingMarginAction->addEntry("medium margin (6)", 6); + m_snappingMarginAction->addEntry("all in margin (10)", 10); + m_snappingMarginAction->setCurrentEntryIndex(3); + layoutActionGroup->addAction(m_snappingMarginAction.data()); + addActions(layoutActionGroup->actions()); + + m_snappingSpacingAction = new NumberSeriesAction(layoutActionGroup); + m_snappingSpacingAction->addEntry("no spacing (0)", 0); + m_snappingSpacingAction->addEntry("small spacing (2)", 2); + m_snappingSpacingAction->addEntry("medium spacing (4)", 4); + m_snappingSpacingAction->addEntry("all in spacing (6)", 6); + m_snappingSpacingAction->setCurrentEntryIndex(1); + layoutActionGroup->addAction(m_snappingSpacingAction.data()); + + addActions(layoutActionGroup->actions()); + + m_zoomAction = new ZoomAction(toolActionGroup()); + connect(m_zoomAction.data(), SIGNAL(zoomLevelChanged(double)), SLOT(setZoomLevel(double))); + addAction(m_zoomAction.data()); + + QAction *separatorAction = new QAction(toolActionGroup()); + separatorAction->setSeparator(true); + addAction(separatorAction); + + m_toolBox = new ToolBox(this); + toolBox()->setActions(actions()); + fillLayout->addWidget(toolBox()); + + m_graphicsView = new FormEditorGraphicsView(this); + fillLayout->addWidget(m_graphicsView.data()); +} + +void FormEditorWidget::enterEvent(QEvent *event) +{ + setFocus(); + QWidget::enterEvent(event); +} + +void FormEditorWidget::changeTransformTool(bool checked) +{ + if (checked) + m_formEditorView->changeToTransformTools(); +} + +void FormEditorWidget::changeAnchorTool(bool checked) +{ + if (checked && m_formEditorView->currentState().isBaseState()) + m_formEditorView->changeToAnchorTool(); +} + +void FormEditorWidget::changeSnappingTool(bool /*checked*/) +{ + // TODO +} + +void FormEditorWidget::wheelEvent(QWheelEvent *event) +{ + if (event->modifiers().testFlag(Qt::ControlModifier)) { + if (event->delta() > 0) { + zoomAction()->zoomIn(); + } else { + zoomAction()->zoomOut(); + } + + event->accept(); + } else { + QWidget::wheelEvent(event); + } + +} + +ZoomAction *FormEditorWidget::zoomAction() const +{ + return m_zoomAction.data(); +} + +QAction *FormEditorWidget::anchorToolAction() const +{ + return m_anchorToolAction.data(); +} + +QAction *FormEditorWidget::transformToolAction() const +{ + return m_transformToolAction.data(); +} + +void FormEditorWidget::setZoomLevel(double zoomLevel) +{ + m_graphicsView->resetTransform(); + + m_graphicsView->scale(zoomLevel, zoomLevel); +} + +void FormEditorWidget::setScene(FormEditorScene *scene) +{ + m_graphicsView->setScene(scene); +} + +QActionGroup *FormEditorWidget::toolActionGroup() const +{ + return m_toolActionGroup.data(); +} + +ToolBox *FormEditorWidget::toolBox() const +{ + return m_toolBox.data(); +} + +bool FormEditorWidget::isSnapButtonChecked() const +{ + return m_snappingToolAction->isChecked(); +} + +double FormEditorWidget::spacing() const +{ + return m_snappingSpacingAction->currentValue().toDouble(); +} + +double FormEditorWidget::margins() const +{ + return m_snappingMarginAction->currentValue().toDouble(); +} + +} + + diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h new file mode 100644 index 0000000000..2a718507f8 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h @@ -0,0 +1,91 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef FORMEDITORWIDGET_H +#define FORMEDITORWIDGET_H + +#include <QWidget> + +class QActionGroup; + +namespace QmlDesigner { + +class ZoomAction; +class FormEditorView; +class FormEditorScene; +class FormEditorGraphicsView; +class ToolBox; +class NumberSeriesAction; + +class FormEditorWidget : public QWidget +{ + Q_OBJECT +public: + FormEditorWidget(FormEditorView *view); + bool isSnapButtonChecked() const; + + ZoomAction *zoomAction() const; + QAction *anchorToolAction() const; + QAction *transformToolAction() const; + + void setScene(FormEditorScene *scene); + ToolBox *toolBox() const; + + double spacing() const; + double margins() const; + + +protected: + void enterEvent(QEvent *event); + void wheelEvent(QWheelEvent *event); + QActionGroup *toolActionGroup() const; + +private slots: + void changeTransformTool(bool checked); + void changeAnchorTool(bool checked); + void setZoomLevel(double zoomLevel); + void changeSnappingTool(bool checked); + +private: + QWeakPointer<FormEditorView> m_formEditorView; + QWeakPointer<FormEditorGraphicsView> m_graphicsView; + QWeakPointer<ZoomAction> m_zoomAction; + QWeakPointer<QAction> m_anchorToolAction; + QWeakPointer<QAction> m_transformToolAction; + QWeakPointer<QActionGroup> m_toolActionGroup; + QWeakPointer<ToolBox> m_toolBox; + QWeakPointer<QAction> m_snappingToolAction; + QWeakPointer<NumberSeriesAction> m_snappingMarginAction; + QWeakPointer<NumberSeriesAction> m_snappingSpacingAction; +}; + + +} +#endif //FORMEDITORWIDGET_H + diff --git a/src/plugins/qmldesigner/components/formeditor/itemcreatortool.cpp b/src/plugins/qmldesigner/components/formeditor/itemcreatortool.cpp new file mode 100644 index 0000000000..9376ed18dc --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/itemcreatortool.cpp @@ -0,0 +1,191 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "itemcreatortool.h" +#include "formeditorscene.h" +#include "formeditorview.h" + +#include <metainfo.h> +#include <itemlibrary.h> + +#include <QApplication> +#include <QGraphicsSceneMouseEvent> +#include <QtDebug> +#include <QClipboard> + +namespace QmlDesigner { + +ItemCreatorTool::ItemCreatorTool(FormEditorView *editorView) + : AbstractFormEditorTool(editorView), + m_rubberbandSelectionManipulator(editorView->scene()->manipulatorLayerItem(), editorView) + +{ + +} + + +ItemCreatorTool::~ItemCreatorTool() +{ +} + +void ItemCreatorTool::mousePressEvent(const QList<QGraphicsItem*> &/*itemList*/, + QGraphicsSceneMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) + m_rubberbandSelectionManipulator.begin(event->scenePos()); + else + view()->deActivateItemCreator(); +} + +void ItemCreatorTool::mouseMoveEvent(const QList<QGraphicsItem*> &/*itemList*/, + QGraphicsSceneMouseEvent *event) +{ + view()->setCursor(Qt::CrossCursor); + if (m_rubberbandSelectionManipulator.isActive()) { + m_rubberbandSelectionManipulator.update(event->scenePos()); + } else { + + } +} + +void ItemCreatorTool::hoverMoveEvent(const QList<QGraphicsItem*> &/*itemList*/, + QGraphicsSceneMouseEvent * /*event*/) +{ +} + +void ItemCreatorTool::mouseReleaseEvent(const QList<QGraphicsItem*> &/*itemList*/, + QGraphicsSceneMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + if (m_rubberbandSelectionManipulator.isActive()) { + QPointF mouseMovementVector = m_rubberbandSelectionManipulator.beginPoint() - event->scenePos(); + if (mouseMovementVector.toPoint().manhattanLength() < QApplication::startDragDistance()) { + m_rubberbandSelectionManipulator.update(event->scenePos()); + } else { + m_rubberbandSelectionManipulator.update(event->scenePos()); + QRectF rect(m_rubberbandSelectionManipulator.beginPoint(), event->scenePos()); + createAtItem(rect); + m_rubberbandSelectionManipulator.end(); + view()->deActivateItemCreator(); + } + } + } else { + view()->deActivateItemCreator(); + } +} + +void ItemCreatorTool::mouseDoubleClickEvent(const QList<QGraphicsItem*> &/*itemList*/, + QGraphicsSceneMouseEvent * /*event*/) +{ + +} + +void ItemCreatorTool::keyPressEvent(QKeyEvent *event) +{ + switch(event->key()) { + case Qt::Key_Escape: + view()->deActivateItemCreator(); + break; + } +} + +void ItemCreatorTool::keyReleaseEvent(QKeyEvent * /*keyEvent*/) +{ + +} + +void ItemCreatorTool::itemsAboutToRemoved(const QList<FormEditorItem*> &/*itemList*/) +{ + +} + +void ItemCreatorTool::clear() +{ + m_rubberbandSelectionManipulator.clear(); +} + +void ItemCreatorTool::selectedItemsChanged(const QList<FormEditorItem*> &/*itemList*/) +{ +} + +void ItemCreatorTool::formEditorItemsChanged(const QList<FormEditorItem*> &/*itemList*/) +{ +} + +void ItemCreatorTool::setItemString(const QString &itemString) +{ + m_itemString = itemString; +} + +FormEditorItem* ItemCreatorTool::calculateContainer(const QPointF &point) +{ + QList<QGraphicsItem *> list = scene()->items(point); + foreach (QGraphicsItem *item, list) { + FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item); + if (formEditorItem && formEditorItem->isContainer()) + return formEditorItem; + } + return 0; +} + +void ItemCreatorTool::createAtItem(const QRectF &rect) +{ + QPointF pos = rect.topLeft(); + + QmlItemNode parentNode = view()->rootQmlItemNode(); + FormEditorItem *parentItem = calculateContainer(pos); + if (parentItem) { + parentNode = parentItem->qmlItemNode(); + pos = parentItem->mapFromScene(pos); + } + + QStringList list = m_itemString.split("^"); + if (list.count() != 2) + return; + if (list.first() == "item") { + RewriterTransaction transaction = view()->beginRewriterTransaction(); + ItemLibraryInfo itemLibraryRepresentation = view()->model()->metaInfo().itemLibraryRepresentation(list.at(1)); + QmlItemNode newNode = view()->createQmlItemNode(itemLibraryRepresentation, pos, parentNode); + newNode.modelNode().variantProperty("width") = rect.width(); + newNode.modelNode().variantProperty("height") = rect.height(); + QList<QmlItemNode> nodeList; + nodeList.append(newNode); + view()->setSelectedQmlItemNodes(nodeList); + } else if (list.first() == "image") { + RewriterTransaction transaction = view()->beginRewriterTransaction(); + QmlItemNode newNode = view()->createQmlItemNodeFromImage(list.at(1), pos, parentNode); + newNode.modelNode().variantProperty("width") = rect.width(); + newNode.modelNode().variantProperty("height") = rect.height(); + QList<QmlItemNode> nodeList; + nodeList.append(newNode); + view()->setSelectedQmlItemNodes(nodeList); + } +} + +} //QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/itemcreatortool.h b/src/plugins/qmldesigner/components/formeditor/itemcreatortool.h new file mode 100644 index 0000000000..c266103905 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/itemcreatortool.h @@ -0,0 +1,82 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef ITEMCREATORTOOL_H +#define ITEMCREATORTOOL_H + + +#include "abstractformeditortool.h" +#include "rubberbandselectionmanipulator.h" + +#include <QHash> + + +namespace QmlDesigner { + + +class ItemCreatorTool : public AbstractFormEditorTool +{ +public: + ItemCreatorTool(FormEditorView* editorView); + ~ItemCreatorTool(); + + void mousePressEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void mouseMoveEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void mouseDoubleClickEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void hoverMoveEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *keyEvent); + + void itemsAboutToRemoved(const QList<FormEditorItem*> &itemList); + + void clear(); + + void selectedItemsChanged(const QList<FormEditorItem*> &itemList); + + void formEditorItemsChanged(const QList<FormEditorItem*> &itemList); + + void setItemString(const QString &itemString); + + FormEditorItem* calculateContainer(const QPointF &point); + + void createAtItem(const QRectF &rect); + +private: + RubberBandSelectionManipulator m_rubberbandSelectionManipulator; + QString m_itemString; +}; + +} +#endif // ITEMCREATORTOOL_H diff --git a/src/plugins/qmldesigner/components/formeditor/itemutilfunctions.cpp b/src/plugins/qmldesigner/components/formeditor/itemutilfunctions.cpp new file mode 100644 index 0000000000..405b617e9d --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/itemutilfunctions.cpp @@ -0,0 +1,78 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "itemutilfunctions.h" +#include <modelutilities.h> +#include <formeditorscene.h> + +#include <QRectF> +#include <QtDebug> + +namespace QmlDesigner { + +class FormEditorItem; + +QRectF boundingRectForItemList(QList<FormEditorItem*> itemList) +{ + QRectF boundingRect; + + foreach (FormEditorItem *item, itemList) + { + boundingRect = boundingRect.united(item->mapToScene(item->qmlItemNode().instanceBoundingRect()).boundingRect()); + } + + return boundingRect; +} + +//ModelNode parentNodeSemanticallyChecked(const ModelNode &childNode, const ModelNode &parentNode) +//{ +// if (ModelUtilities::canReparent(childNode, parentNode)) { +// ModelNode newParentNode; +// newParentNode = ModelUtilities::mapGraphicsViewToGraphicsScene(parentNode); +// if (newParentNode == childNode.parentNode()) +// return ModelNode(); +// if (ModelUtilities::isQWidget(childNode)) +// return ModelUtilities::reparentAndProxymize(childNode, newParentNode); +// else +// return parentNode; +// } +// +// return ModelNode(); +//} + +//FormEditorItem* mapGraphicsViewToGraphicsScene(FormEditorItem* item) +//{ +// if (item == 0) //null pointer +// return 0; +// ModelNode newNode = ModelUtilities::mapGraphicsViewToGraphicsScene(item->modelNode()); +// return item->scene()->itemForNode(newNode); +//} + + +} diff --git a/src/plugins/qmldesigner/components/formeditor/itemutilfunctions.h b/src/plugins/qmldesigner/components/formeditor/itemutilfunctions.h new file mode 100644 index 0000000000..95760f2cb8 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/itemutilfunctions.h @@ -0,0 +1,48 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef ITEMUTILFUNCTIONS_H +#define ITEMUTILFUNCTIONS_H + +#include <QRectF> +#include <QGraphicsItem> +#include "formeditoritem.h" + + +namespace QmlDesigner { + +QRectF boundingRectForItemList(QList<FormEditorItem*> itemList); + +ModelNode parentNodeSemanticallyChecked(const ModelNode &childNode, const ModelNode &parentNode); + +FormEditorItem* mapGraphicsViewToGraphicsScene(FormEditorItem* item); + +} + +#endif // ITEMUTILFUNCTIONS_H diff --git a/src/plugins/qmldesigner/components/formeditor/layeritem.cpp b/src/plugins/qmldesigner/components/formeditor/layeritem.cpp new file mode 100644 index 0000000000..5a94811531 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/layeritem.cpp @@ -0,0 +1,73 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "layeritem.h" + +#include <formeditorscene.h> + + +namespace QmlDesigner { + +LayerItem::LayerItem(FormEditorScene* scene) + : QGraphicsObject() +{ + scene->addItem(this); + setZValue(1); + setFlag(QGraphicsItem::ItemIsMovable, false); +} + +LayerItem::~LayerItem() +{ +} + +void LayerItem::paint(QPainter * /*painter*/, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) +{ +} + +QRectF LayerItem::boundingRect() const +{ + return childrenBoundingRect(); +} + +QList<QGraphicsItem*> LayerItem::findAllChildItems() const +{ + return findAllChildItems(this); +} + +QList<QGraphicsItem*> LayerItem::findAllChildItems(const QGraphicsItem *item) const +{ + QList<QGraphicsItem*> itemList(item->childItems()); + + foreach (QGraphicsItem *childItem, item->childItems()) + itemList += findAllChildItems(childItem); + + return itemList; +} + +} diff --git a/src/plugins/qmldesigner/components/formeditor/layeritem.h b/src/plugins/qmldesigner/components/formeditor/layeritem.h new file mode 100644 index 0000000000..09881a065c --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/layeritem.h @@ -0,0 +1,66 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef LAYERITEM_H +#define LAYERITEM_H + +#include <QGraphicsObject> +#include <QWeakPointer> + +namespace QmlDesigner { + +class FormEditorScene; + +class LayerItem : public QGraphicsObject +{ +public: + enum + { + Type = 0xEAAA + }; + LayerItem(FormEditorScene* scene); + ~LayerItem(); + void paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0 ); + QRectF boundingRect() const; + int type() const; + + QList<QGraphicsItem*> findAllChildItems() const; + +protected: + QList<QGraphicsItem*> findAllChildItems(const QGraphicsItem *item) const; +}; + +inline int LayerItem::type() const +{ + return Type; +} + +} + +#endif // LAYERITEM_H diff --git a/src/plugins/qmldesigner/components/formeditor/manipulatorlayeritem.h b/src/plugins/qmldesigner/components/formeditor/manipulatorlayeritem.h new file mode 100644 index 0000000000..215d1702fe --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/manipulatorlayeritem.h @@ -0,0 +1,39 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef MANIPULATORLAYERITEM_H +#define MANIPULATORLAYERITEM_H + +class ManipulatorLayerItem +{ +public: + ManipulatorLayerItem(); +}; + +#endif // MANIPULATORLAYERITEM_H diff --git a/src/plugins/qmldesigner/components/formeditor/movemanipulator.cpp b/src/plugins/qmldesigner/components/formeditor/movemanipulator.cpp new file mode 100644 index 0000000000..fe0ca9893a --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/movemanipulator.cpp @@ -0,0 +1,363 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "movemanipulator.h" +#include "itemutilfunctions.h" +#include "layeritem.h" +#include "formeditoritem.h" +#include "formeditorscene.h" + +#include <QPointF> +#include <QtDebug> +#include <QColor> +#include <QPen> +#include <QApplication> + +#include <limits> +#include <model.h> +#include <qmlanchors.h> + + +namespace QmlDesigner { + +MoveManipulator::MoveManipulator(LayerItem *layerItem, FormEditorView *view) + : m_layerItem(layerItem), + m_view(view), + m_isActive(false) +{ +} + +MoveManipulator::~MoveManipulator() +{ + deleteSnapLines(); +} + +QPointF MoveManipulator::beginPoint() const +{ + return m_beginPoint; +} + +void MoveManipulator::setItem(FormEditorItem* item) +{ + QList<FormEditorItem*> itemList; + itemList.append(item); + + setItems(itemList); +} + +void MoveManipulator::setItems(const QList<FormEditorItem*> &itemList) +{ + m_itemList = itemList; + if (!m_itemList.isEmpty()) { + if (m_itemList.first()->parentItem()) + m_snapper.setContainerFormEditorItem(m_itemList.first()->parentItem()); + else + m_snapper.setContainerFormEditorItem(m_itemList.first()); + m_snapper.setTransformtionSpaceFormEditorItem(m_snapper.containerFormEditorItem()); + } +} + +void MoveManipulator::updateHashes() +{ +// foreach (FormEditorItem* item, m_itemList) +// m_beginItemRectHash[item] = item->mapRectToParent(item->qmlItemNode().instanceBoundingRect()); + + foreach (FormEditorItem* item, m_itemList) { + QPointF positionInParentSpace = m_snapper.containerFormEditorItem()->mapFromScene(m_beginPositionInSceneSpaceHash.value(item)); + m_beginItemRectHash[item].translate(positionInParentSpace - m_beginPositionHash.value(item)); + m_beginPositionHash.insert(item, positionInParentSpace); + } +} + +bool MoveManipulator::itemsCanReparented() const +{ + foreach (FormEditorItem* item, m_itemList) { + if (!item->qmlItemNode().canReparent()) + return false; + } + + return true; +} + +void MoveManipulator::begin(const QPointF &beginPoint) +{ + m_isActive = true; + + m_snapper.updateSnappingLines(m_itemList); + + + foreach (FormEditorItem* item, m_itemList) + m_beginItemRectHash.insert(item, m_snapper.containerFormEditorItem()->mapRectFromItem(item, item->qmlItemNode().instanceBoundingRect())); + + foreach (FormEditorItem* item, m_itemList) { + QPointF positionInParentSpace(item->qmlItemNode().instancePosition()); + QPointF positionInScenesSpace = m_snapper.containerFormEditorItem()->mapToScene(positionInParentSpace); + m_beginPositionInSceneSpaceHash.insert(item, positionInScenesSpace); + } + + foreach (FormEditorItem* item, m_itemList) { + QPointF positionInParentSpace = m_snapper.containerFormEditorItem()->mapFromScene(m_beginPositionInSceneSpaceHash.value(item)); + m_beginPositionHash.insert(item, positionInParentSpace); + + QmlAnchors anchors(item->qmlItemNode().anchors()); + m_beginTopMarginHash.insert(item, anchors.instanceMargin(AnchorLine::Top)); + m_beginLeftMarginHash.insert(item, anchors.instanceMargin(AnchorLine::Left)); + m_beginRightMarginHash.insert(item, anchors.instanceMargin(AnchorLine::Right)); + m_beginBottomMarginHash.insert(item, anchors.instanceMargin(AnchorLine::Bottom)); + m_beginHorizontalCenterHash.insert(item, anchors.instanceMargin(AnchorLine::HorizontalCenter)); + m_beginVerticalCenterHash.insert(item, anchors.instanceMargin(AnchorLine::VerticalCenter)); + } + + m_beginPoint = beginPoint; + +// setOpacityForAllElements(0.62); + + m_rewriterTransaction = m_view->beginRewriterTransaction(); +} + + + + + +QPointF MoveManipulator::findSnappingOffset(const QList<QRectF> &boundingRectList) +{ + QPointF offset; + + QMap<double, double> verticalOffsetMap; + foreach (const QRectF &boundingRect, boundingRectList) { + double verticalOffset = m_snapper.snappedVerticalOffset(boundingRect); + if (verticalOffset < std::numeric_limits<double>::max()) + verticalOffsetMap.insert(qAbs(verticalOffset), verticalOffset); + } + + + if (!verticalOffsetMap.isEmpty()) + offset.rx() = verticalOffsetMap.begin().value(); + + + + QMap<double, double> horizontalOffsetMap; + foreach (const QRectF &boundingRect, boundingRectList) { + double horizontalOffset = m_snapper.snappedHorizontalOffset(boundingRect); + if (horizontalOffset < std::numeric_limits<double>::max()) + horizontalOffsetMap.insert(qAbs(horizontalOffset), horizontalOffset); + } + + + if (!horizontalOffsetMap.isEmpty()) + offset.ry() = horizontalOffsetMap.begin().value(); + + return offset; +} + + +void MoveManipulator::generateSnappingLines(const QList<QRectF> &boundingRectList) +{ + m_graphicsLineList = m_snapper.generateSnappingLines(boundingRectList, + m_layerItem.data(), + m_snapper.transformtionSpaceFormEditorItem()->sceneTransform()); +} + + + +QList<QRectF> MoveManipulator::tanslatedBoundingRects(const QList<QRectF> &boundingRectList, const QPointF& offsetVector) +{ + QList<QRectF> translatedBoundingRectList; + foreach (const QRectF &boundingRect, boundingRectList) + translatedBoundingRectList.append(boundingRect.translated(offsetVector)); + + return translatedBoundingRectList; +} + + + +/* + /brief updates the position of the items. +*/ +void MoveManipulator::update(const QPointF& updatePoint, Snapping useSnapping) +{ + deleteSnapLines(); //Since they position is changed and the item is moved the snapping lines are + //are obsolete. The new updated snapping lines (color and visibility) will be + //calculated in snapPoint() called in moveNode() later + + if (m_itemList.isEmpty()) { + return; + } else { + QPointF updatePointInContainerSpace(m_snapper.containerFormEditorItem()->mapFromScene(updatePoint)); + QPointF beginPointInContainerSpace(m_snapper.containerFormEditorItem()->mapFromScene(m_beginPoint)); + + QPointF offsetVector(updatePointInContainerSpace - beginPointInContainerSpace); + if (useSnapping == UseSnapping) { + offsetVector -= findSnappingOffset(tanslatedBoundingRects(m_beginItemRectHash.values(), offsetVector)); + generateSnappingLines(tanslatedBoundingRects(m_beginItemRectHash.values(), offsetVector)); + } + + foreach (FormEditorItem* item, m_itemList) { + QPointF positionInContainerSpace(m_beginPositionHash.value(item) + offsetVector); + QmlAnchors anchors(item->qmlItemNode().anchors()); + + if (anchors.instanceHasAnchor(AnchorLine::Top)) { + anchors.setMargin(AnchorLine::Top, m_beginTopMarginHash.value(item) + offsetVector.y()); + } + + if (anchors.instanceHasAnchor(AnchorLine::Left)) { + anchors.setMargin(AnchorLine::Left, m_beginLeftMarginHash.value(item) + offsetVector.x()); + } + + if (anchors.instanceHasAnchor(AnchorLine::Bottom)) { + anchors.setMargin(AnchorLine::Bottom, m_beginBottomMarginHash.value(item) - offsetVector.y()); + } + + if (anchors.instanceHasAnchor(AnchorLine::Right)) { + anchors.setMargin(AnchorLine::Right, m_beginRightMarginHash.value(item) - offsetVector.x()); + } + + if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) { + anchors.setMargin(AnchorLine::HorizontalCenter, m_beginHorizontalCenterHash.value(item) + offsetVector.x()); + } + + if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) { + anchors.setMargin(AnchorLine::VerticalCenter, m_beginVerticalCenterHash.value(item) + offsetVector.y()); + } + + item->qmlItemNode().setPosition(positionInContainerSpace); + } + + + } +} + +void MoveManipulator::clear() +{ + deleteSnapLines(); + m_beginItemRectHash.clear(); + m_beginPositionHash.clear(); + m_beginPositionInSceneSpaceHash.clear(); + m_itemList.clear(); + + m_rewriterTransaction.commit(); + + m_beginTopMarginHash.clear(); + m_beginLeftMarginHash.clear(); + m_beginRightMarginHash.clear(); + m_beginBottomMarginHash.clear(); + m_beginHorizontalCenterHash.clear(); + m_beginVerticalCenterHash.clear(); +} + +void MoveManipulator::reparentTo(FormEditorItem *newParent) +{ + deleteSnapLines(); + + if (!newParent) + return; + + if (!itemsCanReparented()) + return; + + foreach (FormEditorItem* item, m_itemList) { + QmlItemNode parent(newParent->qmlItemNode()); + if (parent.isValid()) { + item->qmlItemNode().setParentProperty(parent.nodeAbstractProperty("data")); + } + } + + if (m_view->model()) { + m_snapper.setContainerFormEditorItem(newParent); + m_snapper.setTransformtionSpaceFormEditorItem(m_snapper.containerFormEditorItem()); + m_snapper.updateSnappingLines(m_itemList); + updateHashes(); + } +} + + +void MoveManipulator::end(const QPointF &/*endPoint*/) +{ + m_isActive = false; + deleteSnapLines(); +// setOpacityForAllElements(1.0); + clear(); +} + +void MoveManipulator::moveBy(double deltaX, double deltaY) +{ + foreach (FormEditorItem* item, m_itemList) { + QmlAnchors anchors(item->qmlItemNode().anchors()); + + if (anchors.instanceHasAnchor(AnchorLine::Top)) { + anchors.setMargin(AnchorLine::Top, anchors.instanceMargin(AnchorLine::Top) - deltaY); + } + + if (anchors.instanceHasAnchor(AnchorLine::Left)) { + anchors.setMargin(AnchorLine::Left, anchors.instanceMargin(AnchorLine::Left) + deltaX); + } + + if (anchors.instanceHasAnchor(AnchorLine::Bottom)) { + anchors.setMargin(AnchorLine::Bottom, anchors.instanceMargin(AnchorLine::Bottom) + deltaY); + } + + if (anchors.instanceHasAnchor(AnchorLine::Right)) { + anchors.setMargin(AnchorLine::Right, anchors.instanceMargin(AnchorLine::Right) - deltaX); + } + + if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) { + anchors.setMargin(AnchorLine::HorizontalCenter, anchors.instanceMargin(AnchorLine::HorizontalCenter) + deltaX); + } + + if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) { + anchors.setMargin(AnchorLine::VerticalCenter, anchors.instanceMargin(AnchorLine::VerticalCenter) + deltaY); + } + + item->qmlItemNode().setPosition(QPointF(item->qmlItemNode().instanceValue("x").toDouble() + deltaX, + item->qmlItemNode().instanceValue("y").toDouble() + deltaY)); + } +} + +void MoveManipulator::setOpacityForAllElements(qreal opacity) +{ + foreach (FormEditorItem* item, m_itemList) + item->setOpacity(opacity); +} + +void MoveManipulator::deleteSnapLines() +{ + if (m_layerItem) { + foreach (QGraphicsItem *item, m_graphicsLineList) + m_layerItem->scene()->removeItem(item); + } + m_graphicsLineList.clear(); + m_view->scene()->update(); +} + +bool MoveManipulator::isActive() const +{ + return m_isActive; +} + +} diff --git a/src/plugins/qmldesigner/components/formeditor/movemanipulator.h b/src/plugins/qmldesigner/components/formeditor/movemanipulator.h new file mode 100644 index 0000000000..3501625b4d --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/movemanipulator.h @@ -0,0 +1,114 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef MOVEMANIPULATOR_H +#define MOVEMANIPULATOR_H + +#include <QWeakPointer> +#include <QGraphicsItem> +#include <QGraphicsLineItem> +#include <QHash> +#include <QPointF> +#include <QRectF> + +#include "controlelement.h" +#include "formeditoritem.h" +#include "rewritertransaction.h" +#include "snapper.h" +#include "formeditorview.h" + +namespace QmlDesigner { + +class ModelNodeChangeSet; +class Model; + +class MoveManipulator +{ +public: + enum Snapping { + UseSnapping, + NoSnapping + }; + + MoveManipulator(LayerItem *layerItem, FormEditorView *view); + ~MoveManipulator(); + void setItems(const QList<FormEditorItem*> &itemList); + void setItem(FormEditorItem* item); + + void begin(const QPointF& beginPoint); + void update(const QPointF& updatePoint, Snapping useSnapping); + void reparentTo(FormEditorItem *newParent); + void end(const QPointF& endPoint); + + void moveBy(double deltaX, double deltaY); + + QPointF beginPoint() const; + + void clear(); + + bool isActive() const; + +protected: + void setOpacityForAllElements(qreal opacity); + + QPointF findSnappingOffset(const QList<QRectF> &boundingRectList); + + void deleteSnapLines(); + + QList<QRectF> tanslatedBoundingRects(const QList<QRectF> &boundingRectList, const QPointF& offset); + QPointF calculateBoundingRectMovementOffset(const QPointF& updatePoint); + QRectF boundingRect(FormEditorItem* item, const QPointF& updatePoint); + + void generateSnappingLines(const QList<QRectF> &boundingRectList); + void updateHashes(); + + bool itemsCanReparented() const; + +private: + Snapper m_snapper; + QWeakPointer<LayerItem> m_layerItem; + QWeakPointer<FormEditorView> m_view; + QList<FormEditorItem*> m_itemList; + QHash<FormEditorItem*, QRectF> m_beginItemRectHash; + QHash<FormEditorItem*, QPointF> m_beginPositionHash; + QHash<FormEditorItem*, QPointF> m_beginPositionInSceneSpaceHash; + QPointF m_beginPoint; + QHash<FormEditorItem*, double> m_beginTopMarginHash; + QHash<FormEditorItem*, double> m_beginLeftMarginHash; + QHash<FormEditorItem*, double> m_beginRightMarginHash; + QHash<FormEditorItem*, double> m_beginBottomMarginHash; + QHash<FormEditorItem*, double> m_beginHorizontalCenterHash; + QHash<FormEditorItem*, double> m_beginVerticalCenterHash; + QList<QGraphicsItem*> m_graphicsLineList; + bool m_isActive; + RewriterTransaction m_rewriterTransaction; +}; + +} +#endif // MOVEMANIPULATOR_H diff --git a/src/plugins/qmldesigner/components/formeditor/movetool.cpp b/src/plugins/qmldesigner/components/formeditor/movetool.cpp new file mode 100644 index 0000000000..09f5ec73c1 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/movetool.cpp @@ -0,0 +1,345 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "movetool.h" + +#include "formeditorscene.h" +#include "formeditorview.h" +#include "modelutilities.h" +#include "itemutilfunctions.h" + +#include "resizehandleitem.h" + +#include <QApplication> +#include <QGraphicsSceneMouseEvent> +#include <QtDebug> + +namespace QmlDesigner { + +MoveTool::MoveTool(FormEditorView *editorView) + : AbstractFormEditorTool(editorView), + m_moveManipulator(editorView->scene()->manipulatorLayerItem(), editorView), + m_selectionIndicator(editorView->scene()->manipulatorLayerItem()), + m_resizeIndicator(editorView->scene()->manipulatorLayerItem()) +{ +// view()->setCursor(Qt::SizeAllCursor); +} + + +MoveTool::~MoveTool() +{ + +} + +void MoveTool::clear() +{ + m_moveManipulator.clear(); + m_movingItems.clear(); + m_selectionIndicator.clear(); + m_resizeIndicator.clear(); +} + +void MoveTool::mousePressEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event) +{ + if (itemList.isEmpty()) + return; + m_movingItems = movingItems(items()); + if (m_movingItems.isEmpty()) + return; + + m_moveManipulator.setItems(m_movingItems); + m_moveManipulator.begin(event->scenePos()); +} + +void MoveTool::mouseMoveEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event) +{ + if (m_movingItems.isEmpty()) + return; + +// m_selectionIndicator.hide(); + m_resizeIndicator.hide(); + + FormEditorItem *containerItem = containerFormEditorItem(itemList, m_movingItems); + if (containerItem && + containerItem != m_movingItems.first()->parentItem() && + view()->currentState().isBaseState() && + !event->modifiers().testFlag(Qt::ShiftModifier)) { + + m_moveManipulator.reparentTo(containerItem); + } + + MoveManipulator::Snapping useSnapping = MoveManipulator::NoSnapping; + if (event->modifiers().testFlag(Qt::ControlModifier) != view()->isSnapButtonChecked()) + useSnapping = MoveManipulator::UseSnapping; + + m_moveManipulator.update(event->scenePos(), useSnapping); +} + +void MoveTool::hoverMoveEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent * /*event*/) +{ + if (itemList.isEmpty()) { + view()->changeToSelectionTool(); + return; + } + + ResizeHandleItem* resizeHandle = ResizeHandleItem::fromGraphicsItem(itemList.first()); + if (resizeHandle) { + view()->changeToResizeTool(); + return; + } + + if (!topSelectedItemIsMovable(itemList)) { + view()->changeToSelectionTool(); + return; + } +} + +void MoveTool::keyPressEvent(QKeyEvent *event) +{ + switch(event->key()) { + case Qt::Key_Shift: + case Qt::Key_Alt: + case Qt::Key_Control: + case Qt::Key_AltGr: + event->setAccepted(false); + return; + } + + double moveStep = 1.0; + + if (event->modifiers().testFlag(Qt::ShiftModifier)) + moveStep = 10.0; + + if (!event->isAutoRepeat()) { + QList<FormEditorItem*> movableItems(movingItems(items())); + if (movableItems.isEmpty()) + return; + + m_moveManipulator.setItems(movableItems); +// m_selectionIndicator.hide(); + m_resizeIndicator.hide(); + } + + switch(event->key()) { + case Qt::Key_Left: m_moveManipulator.moveBy(-moveStep, 0.0); break; + case Qt::Key_Right: m_moveManipulator.moveBy(moveStep, 0.0); break; + case Qt::Key_Up: m_moveManipulator.moveBy(0.0, -moveStep); break; + case Qt::Key_Down: m_moveManipulator.moveBy(0.0, moveStep); break; + } + + +} + +void MoveTool::keyReleaseEvent(QKeyEvent *keyEvent) +{ + switch(keyEvent->key()) { + case Qt::Key_Shift: + case Qt::Key_Alt: + case Qt::Key_Control: + case Qt::Key_AltGr: + keyEvent->setAccepted(false); + return; + } + + if (!keyEvent->isAutoRepeat()) { + m_moveManipulator.clear(); +// m_selectionIndicator.show(); + m_resizeIndicator.show(); + } +} + +void MoveTool::mouseReleaseEvent(const QList<QGraphicsItem*> &/*itemList*/, + QGraphicsSceneMouseEvent *event) +{ + if (m_movingItems.isEmpty()) + return; + + QLineF moveVector(event->scenePos(), m_moveManipulator.beginPoint()); + if (moveVector.length() < QApplication::startDragDistance()) + { + QPointF beginPoint(m_moveManipulator.beginPoint()); + + m_moveManipulator.end(beginPoint); + +// m_selectionIndicator.show(); + m_resizeIndicator.show(); + m_movingItems.clear(); + + view()->changeToSelectionTool(event); + } else { + m_moveManipulator.end(event->scenePos()); + + m_selectionIndicator.show(); + m_resizeIndicator.show(); + m_movingItems.clear(); + } +} + +void MoveTool::mouseDoubleClickEvent(const QList<QGraphicsItem*> & /*itemList*/, + QGraphicsSceneMouseEvent * /*event*/) +{ + +} + +void MoveTool::itemsAboutToRemoved(const QList<FormEditorItem*> &removedItemList) +{ + foreach (FormEditorItem* removedItem, removedItemList) + m_movingItems.removeOne(removedItem); +} + +void MoveTool::selectedItemsChanged(const QList<FormEditorItem*> &itemList) +{ + m_selectionIndicator.setItems(movingItems(itemList)); + m_resizeIndicator.setItems(itemList); + updateMoveManipulator(); +} + +bool MoveTool::haveSameParent(const QList<FormEditorItem*> &itemList) +{ + if (itemList.isEmpty()) + return false; + + QGraphicsItem *firstParent = itemList.first()->parentItem(); + foreach (FormEditorItem* item, itemList) + { + if (firstParent != item->parentItem()) + return false; + } + + return true; +} + +bool MoveTool::isAncestorOfAllItems(FormEditorItem* maybeAncestorItem, + const QList<FormEditorItem*> &itemList) +{ + foreach (FormEditorItem* item, itemList) + { + if (!maybeAncestorItem->isAncestorOf(item) && item != maybeAncestorItem) + return false; + } + + return true; +} + + +FormEditorItem* MoveTool::ancestorIfOtherItemsAreChild(const QList<FormEditorItem*> &itemList) +{ + if (itemList.isEmpty()) + return 0; + + + foreach (FormEditorItem* item, itemList) + { + if (isAncestorOfAllItems(item, itemList)) + return item; + } + + return 0; +} + +void MoveTool::updateMoveManipulator() +{ + if (m_moveManipulator.isActive()) + return; +} + +void MoveTool::beginWithPoint(const QPointF &beginPoint) +{ + m_movingItems = movingItems(items()); + if (m_movingItems.isEmpty()) + return; + + m_moveManipulator.setItems(m_movingItems); + m_moveManipulator.begin(beginPoint); +} + +static bool isNotAncestorOfItemInList(FormEditorItem *formEditorItem, const QList<FormEditorItem*> &itemList) +{ + foreach (FormEditorItem *item, itemList) { + if (item->qmlItemNode().isAncestorOf(formEditorItem->qmlItemNode())) + return false; + } + + return true; +} + +FormEditorItem* MoveTool::containerFormEditorItem(const QList<QGraphicsItem*> &itemUnderMouseList, + const QList<FormEditorItem*> &selectedItemList) +{ + Q_ASSERT(!selectedItemList.isEmpty()); + + foreach (QGraphicsItem* item, itemUnderMouseList) { + FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item); + if (formEditorItem + && !selectedItemList.contains(formEditorItem) + && isNotAncestorOfItemInList(formEditorItem, selectedItemList)) + if (formEditorItem->isContainer()) { + return formEditorItem; + } + + } + + return 0; +} + + +QList<FormEditorItem*> MoveTool::movingItems(const QList<FormEditorItem*> &selectedItemList) +{ + FormEditorItem* ancestorItem = ancestorIfOtherItemsAreChild(selectedItemList); + + if (ancestorItem != 0 && ancestorItem->qmlItemNode().isRootNode()) { +// view()->changeToSelectionTool(); + return QList<FormEditorItem*>(); + } + + + if (ancestorItem != 0 && ancestorItem->parentItem() != 0) { + QList<FormEditorItem*> ancestorItemList; + ancestorItemList.append(ancestorItem); + return ancestorItemList; + } + + if (!haveSameParent(selectedItemList)) { +// view()->changeToSelectionTool(); + return QList<FormEditorItem*>(); + } + + return selectedItemList; +} + +void MoveTool::formEditorItemsChanged(const QList<FormEditorItem*> &itemList) +{ + m_selectionIndicator.updateItems(itemList); + m_resizeIndicator.updateItems(itemList); +} + +} diff --git a/src/plugins/qmldesigner/components/formeditor/movetool.h b/src/plugins/qmldesigner/components/formeditor/movetool.h new file mode 100644 index 0000000000..df3c65b791 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/movetool.h @@ -0,0 +1,97 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef MOVETOOL_H +#define MOVETOOL_H + +#include "abstractformeditortool.h" +#include "movemanipulator.h" +#include "selectionindicator.h" +#include "resizeindicator.h" + +#include <QHash> + + +namespace QmlDesigner { + + +class MoveTool : public AbstractFormEditorTool +{ +public: + MoveTool(FormEditorView* editorView); + ~MoveTool(); + + void mousePressEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void mouseMoveEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void mouseDoubleClickEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void hoverMoveEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *keyEvent); + + void itemsAboutToRemoved(const QList<FormEditorItem*> &itemList); + + void selectedItemsChanged(const QList<FormEditorItem*> &itemList); + + void updateMoveManipulator(); + + + + void beginWithPoint(const QPointF &beginPoint); + + void clear(); + + void formEditorItemsChanged(const QList<FormEditorItem*> &itemList); + +protected: + static bool haveSameParent(const QList<FormEditorItem*> &itemList); + + static QList<FormEditorItem*> movingItems(const QList<FormEditorItem*> &selectedItemList); + + static FormEditorItem* containerFormEditorItem(const QList<QGraphicsItem*> &itemUnderMouseList, + const QList<FormEditorItem*> &selectedItemList); + + static bool isAncestorOfAllItems(FormEditorItem* maybeAncestorItem, + const QList<FormEditorItem*> &itemList); + static FormEditorItem* ancestorIfOtherItemsAreChild(const QList<FormEditorItem*> &itemList); + +private: + MoveManipulator m_moveManipulator; + SelectionIndicator m_selectionIndicator; + ResizeIndicator m_resizeIndicator; + QList<FormEditorItem*> m_movingItems; +}; + +} +#endif // MOVETOOL_H diff --git a/src/plugins/qmldesigner/components/formeditor/numberseriesaction.cpp b/src/plugins/qmldesigner/components/formeditor/numberseriesaction.cpp new file mode 100644 index 0000000000..ba6354f01d --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/numberseriesaction.cpp @@ -0,0 +1,88 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "numberseriesaction.h" +#include <QStandardItemModel> +#include <QComboBox> +#include <QtDebug> + + +namespace QmlDesigner { + +NumberSeriesAction::NumberSeriesAction(QObject *parent) : + QWidgetAction(parent), + m_comboBoxModelIndex(-1) +{ +} + +void NumberSeriesAction::addEntry(const QString &text, const QVariant &value) +{ + if (m_comboBoxModel.isNull()) + m_comboBoxModel = new QStandardItemModel(this); + + QStandardItem *newItem = new QStandardItem(text); + newItem->setData(value); + m_comboBoxModel->appendRow(newItem); +} + +QVariant NumberSeriesAction::currentValue() const +{ + return m_comboBoxModel->item(m_comboBoxModelIndex)->data(); +} + +QWidget *NumberSeriesAction::createWidget(QWidget *parent) +{ + QComboBox *comboBox = new QComboBox(parent); + + comboBox->setModel(m_comboBoxModel.data()); + + comboBox->setCurrentIndex(m_comboBoxModelIndex); + connect(comboBox, SIGNAL(currentIndexChanged(int)), SLOT(emitValueChanged(int))); + + return comboBox; +} + +void NumberSeriesAction::emitValueChanged(int index) +{ + if (index == -1) + return; + + m_comboBoxModelIndex = index; + + emit valueChanged(m_comboBoxModel.data()->item(index)->data()); +} + +void NumberSeriesAction::setCurrentEntryIndex(int index) +{ + Q_ASSERT(index < m_comboBoxModel->rowCount()); + + m_comboBoxModelIndex = index; +} + +} // namespace QKinecticDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/numberseriesaction.h b/src/plugins/qmldesigner/components/formeditor/numberseriesaction.h new file mode 100644 index 0000000000..e6a8c82f16 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/numberseriesaction.h @@ -0,0 +1,66 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef NUMBERSERIESACTION_H +#define NUMBERSERIESACTION_H + +#include <QWidgetAction> + +class QStandardItemModel; + +namespace QmlDesigner { + +class NumberSeriesAction : public QWidgetAction +{ +Q_OBJECT +public: + explicit NumberSeriesAction(QObject *parent = 0); + + void addEntry(const QString &text, const QVariant &value); + void setCurrentEntryIndex(int index); + + QVariant currentValue() const; + +protected: + QWidget *createWidget(QWidget *parent); + +signals: + void valueChanged(const QVariant &value); + +private slots: + void emitValueChanged(int index); + +private: + QWeakPointer<QStandardItemModel> m_comboBoxModel; + int m_comboBoxModelIndex; +}; + +} // namespace QKinecticDesigner + +#endif // NUMBERSERIESACTION_H diff --git a/src/plugins/qmldesigner/components/formeditor/onedimensionalcluster.cpp b/src/plugins/qmldesigner/components/formeditor/onedimensionalcluster.cpp new file mode 100644 index 0000000000..e77afe8a14 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/onedimensionalcluster.cpp @@ -0,0 +1,146 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "onedimensionalcluster.h" + +#include <QtDebug> + +namespace QmlDesigner { + +double sum(const QList<double> & list) +{ + double sum = 0.0; + for(QList<double>::const_iterator iterator = list.constBegin(); iterator != list.constEnd(); ++iterator) + { + sum += *iterator; + } + + return sum; +} + +OneDimensionalCluster::OneDimensionalCluster(const QList<double> & coordinateList ) + : m_coordinateList(coordinateList) +{ +} + +double OneDimensionalCluster::mean() const +{ + Q_ASSERT(!m_coordinateList.isEmpty()); + + if (m_coordinateList.size() == 1) + { + return m_coordinateList.first(); + } + + return sum(m_coordinateList) / m_coordinateList.size(); +} + +double OneDimensionalCluster::first() const +{ + Q_ASSERT(!m_coordinateList.isEmpty()); + + return m_coordinateList.first(); +} + +QList<OneDimensionalCluster> OneDimensionalCluster::createOneDimensionalClusterList(const QList<double> & oneDimensionalCoordinateList) +{ + QList<OneDimensionalCluster> oneDimensionalClusterList; + foreach (double coordinate, oneDimensionalCoordinateList) + { + QList<double> initialList; + initialList.append(coordinate); + OneDimensionalCluster cluster(initialList); + oneDimensionalClusterList.append(initialList); + } + + return oneDimensionalClusterList; +} + +QList<OneDimensionalCluster> OneDimensionalCluster::reduceOneDimensionalClusterList(const QList<OneDimensionalCluster> & unreducedClusterList, double maximumDistance) +{ + if (unreducedClusterList.size() < 2) + return unreducedClusterList; + + + QList<OneDimensionalCluster> workingList(unreducedClusterList); + QList<OneDimensionalCluster> reducedList; + while (true) + { + qSort(workingList); + reducedList.clear(); + bool clusterMerged = false; + QListIterator<OneDimensionalCluster> clusterIterator(workingList); + while (clusterIterator.hasNext()) + { + OneDimensionalCluster currentCluster = clusterIterator.next(); + if (clusterIterator.hasNext()) + { + OneDimensionalCluster nextCluster = clusterIterator.peekNext(); + if ((nextCluster.mean() - currentCluster.mean()) < maximumDistance) + { + reducedList.append(currentCluster + nextCluster); + clusterIterator.next(); + clusterMerged = true; + } + else + { + reducedList.append(currentCluster); + } + } + else + { + reducedList.append(currentCluster); + break; + } + + } + + workingList = reducedList; + + if (clusterMerged == false) + break; + } + + + return reducedList; +} + +QList<double> OneDimensionalCluster::reduceLines(const QList<double> & oneDimensionalCoordinateList, double maximumDistance) +{ + QList<OneDimensionalCluster> clusterList(createOneDimensionalClusterList(oneDimensionalCoordinateList)); + clusterList = reduceOneDimensionalClusterList(clusterList, maximumDistance); + + QList<double> lineList; + foreach (const OneDimensionalCluster &cluster, clusterList) + lineList.append(cluster.first()); + + return lineList; +} + +} diff --git a/src/plugins/qmldesigner/components/formeditor/onedimensionalcluster.h b/src/plugins/qmldesigner/components/formeditor/onedimensionalcluster.h new file mode 100644 index 0000000000..dcf179eb18 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/onedimensionalcluster.h @@ -0,0 +1,70 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef ONEDIMENSIONALCLUSTER_H +#define ONEDIMENSIONALCLUSTER_H + +#include <QList> + +namespace QmlDesigner { + +class OneDimensionalCluster +{ + friend inline OneDimensionalCluster operator+(const OneDimensionalCluster & firstCluster, const OneDimensionalCluster & secondCluster); + friend inline bool operator < (const OneDimensionalCluster & firstCluster, const OneDimensionalCluster & secondCluster); +public: + static QList<double> reduceLines(const QList<double> & oneDimensionalCoordinateList, double maximumDistance); + +private: + + OneDimensionalCluster(const QList<double> & coordinateList ); + double mean() const; + double first() const; + + + + static QList<OneDimensionalCluster> createOneDimensionalClusterList(const QList<double> & oneDimensionalCoordinateList); + static QList<OneDimensionalCluster> reduceOneDimensionalClusterList(const QList<OneDimensionalCluster> & unreducedClusterList, double maximumDistance); + + QList<double> m_coordinateList; +}; + +inline bool operator < (const OneDimensionalCluster & firstCluster, const OneDimensionalCluster & secondCluster) +{ + return firstCluster.mean() < secondCluster.mean(); +} + +inline OneDimensionalCluster operator+(const OneDimensionalCluster & firstCluster, const OneDimensionalCluster & secondCluster) +{ + + return OneDimensionalCluster(firstCluster.m_coordinateList + secondCluster.m_coordinateList); +} + +} +#endif // ONEDIMENSIONALCLUSTER_H diff --git a/src/plugins/qmldesigner/components/formeditor/resize_handle.png b/src/plugins/qmldesigner/components/formeditor/resize_handle.png Binary files differnew file mode 100644 index 0000000000..2934f25b74 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/resize_handle.png diff --git a/src/plugins/qmldesigner/components/formeditor/resizecontroller.cpp b/src/plugins/qmldesigner/components/formeditor/resizecontroller.cpp new file mode 100644 index 0000000000..9929df14ee --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/resizecontroller.cpp @@ -0,0 +1,273 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "resizecontroller.h" + +#include "formeditoritem.h" +#include "layeritem.h" + +#include <resizehandleitem.h> +#include <QCursor> +#include <QGraphicsScene> + +namespace QmlDesigner { + + + +ResizeControllerData::ResizeControllerData(LayerItem *layerItem, FormEditorItem *formEditorItem) + : layerItem(layerItem), + formEditorItem(formEditorItem), + topLeftItem(0), + topRightItem(0), + bottomLeftItem(0), + bottomRightItem(0), + topItem(0), + leftItem(0), + rightItem(0), + bottomItem(0) +{ + +} + +ResizeControllerData::ResizeControllerData(const ResizeControllerData &other) + : layerItem(other.layerItem), + formEditorItem(other.formEditorItem), + topLeftItem(other.topLeftItem), + topRightItem(other.topRightItem), + bottomLeftItem(other.bottomLeftItem), + bottomRightItem(other.bottomRightItem), + topItem(other.topItem), + leftItem(other.leftItem), + rightItem(other.rightItem), + bottomItem(other.bottomItem) +{} + +ResizeControllerData::~ResizeControllerData() +{ + if (layerItem) { + layerItem->scene()->removeItem(topLeftItem); + layerItem->scene()->removeItem(topRightItem); + layerItem->scene()->removeItem(bottomLeftItem); + layerItem->scene()->removeItem(bottomRightItem); + layerItem->scene()->removeItem(topItem); + layerItem->scene()->removeItem(leftItem); + layerItem->scene()->removeItem(rightItem); + layerItem->scene()->removeItem(bottomItem); + } +} + + +ResizeController::ResizeController() + : m_data(new ResizeControllerData(0, 0)) +{ + +} + +ResizeController::ResizeController(const QSharedPointer<ResizeControllerData> &data) + : m_data(data) +{ + +} + +ResizeController::ResizeController(LayerItem *layerItem, FormEditorItem *formEditorItem) + : m_data(new ResizeControllerData(layerItem, formEditorItem)) +{ + m_data->topLeftItem = new ResizeHandleItem(layerItem, *this); + m_data->topLeftItem->setZValue(302); + m_data->topLeftItem->setCursor(Qt::SizeFDiagCursor); + + m_data->topRightItem = new ResizeHandleItem(layerItem, *this); + m_data->topRightItem->setZValue(301); + m_data->topRightItem->setCursor(Qt::SizeBDiagCursor); + + m_data->bottomLeftItem = new ResizeHandleItem(layerItem, *this); + m_data->bottomLeftItem->setZValue(301); + m_data->bottomLeftItem->setCursor(Qt::SizeBDiagCursor); + + m_data->bottomRightItem = new ResizeHandleItem(layerItem, *this); + m_data->bottomRightItem->setZValue(305); + m_data->bottomRightItem->setCursor(Qt::SizeFDiagCursor); + + m_data->topItem = new ResizeHandleItem(layerItem, *this); + m_data->topItem->setZValue(300); + m_data->topItem->setCursor(Qt::SizeVerCursor); + + m_data->leftItem = new ResizeHandleItem(layerItem, *this); + m_data->leftItem->setZValue(300); + m_data->leftItem->setCursor(Qt::SizeHorCursor); + + m_data->rightItem = new ResizeHandleItem(layerItem, *this); + m_data->rightItem->setZValue(300); + m_data->rightItem->setCursor(Qt::SizeHorCursor); + + m_data->bottomItem = new ResizeHandleItem(layerItem, *this); + m_data->bottomItem->setZValue(300); + m_data->bottomItem->setCursor(Qt::SizeVerCursor); + + updatePosition(); +} + + +bool ResizeController::isValid() const +{ + return m_data->formEditorItem != 0; +} + +void ResizeController::show() +{ + m_data->topLeftItem->show(); + m_data->topRightItem->show(); + m_data->bottomLeftItem->show(); + m_data->bottomRightItem->show(); + m_data->topItem->show(); + m_data->leftItem->show(); + m_data->rightItem->show(); + m_data->bottomItem->show(); +} +void ResizeController::hide() +{ + m_data->topLeftItem->hide(); + m_data->topRightItem->hide(); + m_data->bottomLeftItem->hide(); + m_data->bottomRightItem->hide(); + m_data->topItem->hide(); + m_data->leftItem->hide(); + m_data->rightItem->hide(); + m_data->bottomItem->hide(); +} + + +static QPointF topCenter(const QRectF &rect) +{ + return QPointF(rect.center().x(), rect.top()); +} + +static QPointF leftCenter(const QRectF &rect) +{ + return QPointF(rect.left(), rect.center().y()); +} + +static QPointF rightCenter(const QRectF &rect) +{ + return QPointF(rect.right(), rect.center().y()); +} + +static QPointF bottomCenter(const QRectF &rect) +{ + return QPointF(rect.center().x(), rect.bottom()); +} + + +void ResizeController::updatePosition() +{ + QRectF originalBoundingRect = m_data->formEditorItem->qmlItemNode().instanceBoundingRect(); + QRectF boundingRect = m_data->formEditorItem->qmlItemNode().instanceBoundingRect().adjusted(0.49, 0.49, 0.49, 0.49); + QPointF topLeftPointInLayerSpace(m_data->formEditorItem->mapToItem(m_data->layerItem.data(), + boundingRect.topLeft())); + QPointF topRightPointInLayerSpace(m_data->formEditorItem->mapToItem(m_data->layerItem.data(), + boundingRect.topRight())); + QPointF bottomLeftPointInLayerSpace(m_data->formEditorItem->mapToItem(m_data->layerItem.data(), + boundingRect.bottomLeft())); + QPointF bottomRightPointInLayerSpace(m_data->formEditorItem->mapToItem(m_data->layerItem.data(), + boundingRect.bottomRight())); + + QPointF topPointInLayerSpace(m_data->formEditorItem->mapToItem(m_data->layerItem.data(), + topCenter(boundingRect))); + QPointF leftPointInLayerSpace(m_data->formEditorItem->mapToItem(m_data->layerItem.data(), + leftCenter(boundingRect))); + + QPointF rightPointInLayerSpace(m_data->formEditorItem->mapToItem(m_data->layerItem.data(), + rightCenter(boundingRect))); + QPointF bottomPointInLayerSpace(m_data->formEditorItem->mapToItem(m_data->layerItem.data(), + bottomCenter(boundingRect))); + + + + m_data->topRightItem->setHandlePosition(topRightPointInLayerSpace, originalBoundingRect.topRight()); + m_data->topLeftItem->setHandlePosition(topLeftPointInLayerSpace, originalBoundingRect.topLeft()); + m_data->bottomLeftItem->setHandlePosition(bottomLeftPointInLayerSpace, originalBoundingRect.bottomLeft()); + m_data->bottomRightItem->setHandlePosition(bottomRightPointInLayerSpace, originalBoundingRect.bottomRight()); + m_data->topItem->setHandlePosition(topPointInLayerSpace, topCenter(originalBoundingRect)); + m_data->leftItem->setHandlePosition(leftPointInLayerSpace, leftCenter(originalBoundingRect)); + m_data->rightItem->setHandlePosition(rightPointInLayerSpace, rightCenter(originalBoundingRect)); + m_data->bottomItem->setHandlePosition(bottomPointInLayerSpace, bottomCenter(originalBoundingRect)); +} + + +FormEditorItem* ResizeController::formEditorItem() const +{ + return m_data->formEditorItem; +} + +QWeakPointer<ResizeControllerData> ResizeController::weakPointer() const +{ + return m_data; +} + +bool ResizeController::isTopLeftHandle(const ResizeHandleItem *handle) const +{ + return handle == m_data->topLeftItem; +} + +bool ResizeController::isTopRightHandle(const ResizeHandleItem *handle) const +{ + return handle == m_data->topRightItem; +} + +bool ResizeController::isBottomLeftHandle(const ResizeHandleItem *handle) const +{ + return handle == m_data->bottomLeftItem; +} + +bool ResizeController::isBottomRightHandle(const ResizeHandleItem *handle) const +{ + return handle == m_data->bottomRightItem; +} + +bool ResizeController::isTopHandle(const ResizeHandleItem *handle) const +{ + return handle == m_data->topItem; +} + +bool ResizeController::isLeftHandle(const ResizeHandleItem *handle) const +{ + return handle == m_data->leftItem; +} + +bool ResizeController::isRightHandle(const ResizeHandleItem *handle) const +{ + return handle == m_data->rightItem; +} + +bool ResizeController::isBottomHandle(const ResizeHandleItem *handle) const +{ + return handle == m_data->bottomItem; +} + +} diff --git a/src/plugins/qmldesigner/components/formeditor/resizecontroller.h b/src/plugins/qmldesigner/components/formeditor/resizecontroller.h new file mode 100644 index 0000000000..be1e44824a --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/resizecontroller.h @@ -0,0 +1,104 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef RESIZECONTROLLER_H +#define RESIZECONTROLLER_H + +#include <QWeakPointer> +#include <QSharedPointer> + + +namespace QmlDesigner { + +class FormEditorItem; +class LayerItem; +class ResizeHandleItem; + + +class ResizeControllerData +{ +public: + ResizeControllerData(LayerItem *layerItem, + FormEditorItem *formEditorItem); + ResizeControllerData(const ResizeControllerData &other); + ~ResizeControllerData(); + + + QWeakPointer<LayerItem> layerItem; + FormEditorItem *formEditorItem; + ResizeHandleItem *topLeftItem; + ResizeHandleItem *topRightItem; + ResizeHandleItem *bottomLeftItem; + ResizeHandleItem *bottomRightItem; + ResizeHandleItem *topItem; + ResizeHandleItem *leftItem; + ResizeHandleItem *rightItem; + ResizeHandleItem *bottomItem; +}; + + + + +class ResizeController +{ +public: + friend class ResizeHandleItem; + + ResizeController(); + ResizeController(LayerItem *layerItem, FormEditorItem *formEditorItem); + + void show(); + void hide(); + + void updatePosition(); + + bool isValid() const; + + FormEditorItem *formEditorItem() const; + + bool isTopLeftHandle(const ResizeHandleItem *handle) const; + bool isTopRightHandle(const ResizeHandleItem *handle) const; + bool isBottomLeftHandle(const ResizeHandleItem *handle) const; + bool isBottomRightHandle(const ResizeHandleItem *handle) const; + + bool isTopHandle(const ResizeHandleItem *handle) const; + bool isLeftHandle(const ResizeHandleItem *handle) const; + bool isRightHandle(const ResizeHandleItem *handle) const; + bool isBottomHandle(const ResizeHandleItem *handle) const; + +private: // functions + ResizeController(const QSharedPointer<ResizeControllerData> &data); + QWeakPointer<ResizeControllerData> weakPointer() const; +private: // variables + QSharedPointer<ResizeControllerData> m_data; +}; + +} + +#endif // RESIZECONTROLLER_H diff --git a/src/plugins/qmldesigner/components/formeditor/resizehandleitem.cpp b/src/plugins/qmldesigner/components/formeditor/resizehandleitem.cpp new file mode 100644 index 0000000000..ae388cf2cd --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/resizehandleitem.cpp @@ -0,0 +1,118 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "resizehandleitem.h" + +#include <formeditoritem.h> +#include <QCursor> + +namespace QmlDesigner { + +ResizeHandleItem::ResizeHandleItem(QGraphicsItem *parent, const ResizeController &resizeController) + : QGraphicsPixmapItem(QPixmap(":/icon/handle/resize_handle.png"), parent), + m_resizeControllerData(resizeController.weakPointer()) +{ + setShapeMode(QGraphicsPixmapItem::BoundingRectShape); + setOffset(-pixmap().rect().center()); + setFlag(QGraphicsItem::ItemIsMovable, true); + setFlag(QGraphicsItem::ItemIgnoresTransformations, true); +} + +void ResizeHandleItem::setHandlePosition(const QPointF & globalPosition, const QPointF & itemSpacePosition) +{ + m_itemSpacePosition = itemSpacePosition; + setPos(globalPosition); +} + +QRectF ResizeHandleItem::boundingRect() const +{ + return QGraphicsPixmapItem::boundingRect().adjusted(-1, -1, 1, 1); +} + +QPainterPath ResizeHandleItem::shape() const +{ + return QGraphicsItem::shape(); +} + +ResizeController ResizeHandleItem::resizeController() const +{ + Q_ASSERT(!m_resizeControllerData.isNull()); + return ResizeController(m_resizeControllerData.toStrongRef()); +} + +ResizeHandleItem* ResizeHandleItem::fromGraphicsItem(QGraphicsItem *item) +{ + return qgraphicsitem_cast<ResizeHandleItem*>(item); +} + +bool ResizeHandleItem::isTopLeftHandle() const +{ + return resizeController().isTopLeftHandle(this); +} + +bool ResizeHandleItem::isTopRightHandle() const +{ + return resizeController().isTopRightHandle(this); +} + +bool ResizeHandleItem::isBottomLeftHandle() const +{ + return resizeController().isBottomLeftHandle(this); +} + +bool ResizeHandleItem::isBottomRightHandle() const +{ + return resizeController().isBottomRightHandle(this); +} + +bool ResizeHandleItem::isTopHandle() const +{ + return resizeController().isTopHandle(this); +} + +bool ResizeHandleItem::isLeftHandle() const +{ + return resizeController().isLeftHandle(this); +} + +bool ResizeHandleItem::isRightHandle() const +{ + return resizeController().isRightHandle(this); +} + +bool ResizeHandleItem::isBottomHandle() const +{ + return resizeController().isBottomHandle(this); +} + +QPointF ResizeHandleItem::itemSpacePosition() const +{ + return m_itemSpacePosition; +} +} diff --git a/src/plugins/qmldesigner/components/formeditor/resizehandleitem.h b/src/plugins/qmldesigner/components/formeditor/resizehandleitem.h new file mode 100644 index 0000000000..3177e3aa24 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/resizehandleitem.h @@ -0,0 +1,84 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef RESIZEHANDLEITEM_H +#define RESIZEHANDLEITEM_H + +#include <QGraphicsPixmapItem> + +#include "resizecontroller.h" + +namespace QmlDesigner { + +class ResizeHandleItem : public QGraphicsPixmapItem +{ +public: + enum + { + Type = 0xEAEA + }; + + + ResizeHandleItem(QGraphicsItem *parent, const ResizeController &resizeController); + + void setHandlePosition(const QPointF & globalPosition, const QPointF & itemSpacePosition); + + int type() const; + QRectF boundingRect() const; + QPainterPath shape() const; + + ResizeController resizeController() const; + + static ResizeHandleItem* fromGraphicsItem(QGraphicsItem *item); + + bool isTopLeftHandle() const; + bool isTopRightHandle() const; + bool isBottomLeftHandle() const; + bool isBottomRightHandle() const; + + bool isTopHandle() const; + bool isLeftHandle() const; + bool isRightHandle() const; + bool isBottomHandle() const; + + QPointF itemSpacePosition() const; + +private: + QWeakPointer<ResizeControllerData> m_resizeControllerData; + QPointF m_itemSpacePosition; +}; + +inline int ResizeHandleItem::type() const +{ + return Type; +} + +} + +#endif // RESIZEHANDLEITEM_H diff --git a/src/plugins/qmldesigner/components/formeditor/resizeindicator.cpp b/src/plugins/qmldesigner/components/formeditor/resizeindicator.cpp new file mode 100644 index 0000000000..9add9a65c7 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/resizeindicator.cpp @@ -0,0 +1,91 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "resizeindicator.h" + +#include "formeditoritem.h" + +namespace QmlDesigner { + +ResizeIndicator::ResizeIndicator(LayerItem *layerItem) + : m_layerItem(layerItem) +{ + Q_ASSERT(layerItem); +} + +ResizeIndicator::~ResizeIndicator() +{ + m_itemControllerHash.clear(); +} + +void ResizeIndicator::show() +{ + QHashIterator<FormEditorItem*, ResizeController> itemControllerIterator(m_itemControllerHash); + while (itemControllerIterator.hasNext()) { + ResizeController controller = itemControllerIterator.next().value(); + controller.show(); + } +} +void ResizeIndicator::hide() +{ + QHashIterator<FormEditorItem*, ResizeController> itemControllerIterator(m_itemControllerHash); + while (itemControllerIterator.hasNext()) { + ResizeController controller = itemControllerIterator.next().value(); + controller.hide(); + } +} + +void ResizeIndicator::clear() +{ + m_itemControllerHash.clear(); +} + +void ResizeIndicator::setItems(const QList<FormEditorItem*> &itemList) +{ + clear(); + + foreach (FormEditorItem* item, itemList) { + if (item->qmlItemNode().isRootNode()) + continue; + ResizeController controller(m_layerItem, item); + m_itemControllerHash.insert(item, controller); + } +} + +void ResizeIndicator::updateItems(const QList<FormEditorItem*> &itemList) +{ + foreach (FormEditorItem* item, itemList) { + if (m_itemControllerHash.contains(item)) { + ResizeController controller(m_itemControllerHash.value(item)); + controller.updatePosition(); + } + } +} + +} diff --git a/src/plugins/qmldesigner/components/formeditor/resizeindicator.h b/src/plugins/qmldesigner/components/formeditor/resizeindicator.h new file mode 100644 index 0000000000..e8881ec3e7 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/resizeindicator.h @@ -0,0 +1,81 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef RESIZEINDICATOR_H +#define RESIZEINDICATOR_H + +#include <QHash> +#include <QPair> + +#include "resizecontroller.h" + +class QGraphicsRectItem; + +namespace QmlDesigner { + +class FormEditorItem; +class LayerItem; + +class ResizeIndicator +{ +public: + enum Orientation { + Top = 1, + Right = 2, + Bottom = 4, + Left = 8 + }; + + ResizeIndicator(LayerItem *layerItem); + ~ResizeIndicator(); + + void show(); + void hide(); + + void clear(); + + void setItems(const QList<FormEditorItem*> &itemList); + void updateItems(const QList<FormEditorItem*> &itemList); + +// +// QPair<FormEditorItem*,Orientation> pick(QGraphicsRectItem* pickedItem) const; +// +// void show(); +// void hide(); + + + +private: + QHash<FormEditorItem*, ResizeController> m_itemControllerHash; + + LayerItem *m_layerItem; +}; + +} +#endif // SCALEINDICATOR_H diff --git a/src/plugins/qmldesigner/components/formeditor/resizemanipulator.cpp b/src/plugins/qmldesigner/components/formeditor/resizemanipulator.cpp new file mode 100644 index 0000000000..b0f2189646 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/resizemanipulator.cpp @@ -0,0 +1,504 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "resizemanipulator.h" + +#include "formeditoritem.h" +#include "formeditorscene.h" +#include "qmlanchors.h" +#include <QtDebug> +#include <model.h> +#include "mathutils.h" + +#include <limits> + +namespace QmlDesigner { + +ResizeManipulator::ResizeManipulator(LayerItem *layerItem, FormEditorView *view) + : m_view(view), + m_beginTopMargin(0.0), + m_beginLeftMargin(0.0), + m_beginRightMargin(0.0), + m_beginBottomMargin(0.0), + m_layerItem(layerItem), + m_resizeHandle(0) +{ +} + +ResizeManipulator::~ResizeManipulator() +{ + deleteSnapLines(); +} + +void ResizeManipulator::setHandle(ResizeHandleItem *resizeHandle) +{ + Q_ASSERT(resizeHandle); + m_resizeHandle = resizeHandle; + m_resizeController = resizeHandle->resizeController(); + m_snapper.setContainerFormEditorItem(m_resizeController.formEditorItem()->parentItem()); + m_snapper.setTransformtionSpaceFormEditorItem(m_resizeController.formEditorItem()); + Q_ASSERT(m_resizeController.isValid()); +} + +void ResizeManipulator::removeHandle() +{ + m_resizeController = ResizeController(); + m_resizeHandle = 0; +} + +void ResizeManipulator::begin(const QPointF &/*beginPoint*/) +{ + if (m_resizeController.isValid()) { + m_beginBoundingRect = m_resizeController.formEditorItem()->qmlItemNode().instanceBoundingRect(); + m_beginToSceneTransform = m_resizeController.formEditorItem()->qmlItemNode().instanceSceneTransform(); + m_beginFromSceneTransform = m_beginToSceneTransform.inverted(); + m_beginToParentTransform = m_resizeController.formEditorItem()->qmlItemNode().instanceTransform(); + m_rewriterTransaction = m_view->beginRewriterTransaction(); + m_snapper.updateSnappingLines(m_resizeController.formEditorItem()); + m_beginBottomRightPoint = m_beginToParentTransform.map(m_resizeController.formEditorItem()->qmlItemNode().instanceBoundingRect().bottomRight()); + + QmlAnchors anchors(m_resizeController.formEditorItem()->qmlItemNode().anchors()); + m_beginTopMargin = anchors.instanceMargin(AnchorLine::Top); + m_beginLeftMargin = anchors.instanceMargin(AnchorLine::Left); + m_beginRightMargin = anchors.instanceMargin(AnchorLine::Right); + m_beginBottomMargin = anchors.instanceMargin(AnchorLine::Bottom); + } +} + +//static QSizeF mapSizeToParent(const QSizeF &size, QGraphicsItem *item) +//{ +// QPointF sizeAsPoint(size.width(), size.height()); +// sizeAsPoint = item->mapToParent(sizeAsPoint); +// return QSizeF(sizeAsPoint.x(), sizeAsPoint.y()); +//} + +void ResizeManipulator::update(const QPointF& updatePoint, Snapping useSnapping) +{ + const double minimumWidth = 15.0; + const double minimumHeight = 15.0; + + deleteSnapLines(); + + if (m_resizeController.isValid()) { + + FormEditorItem *formEditorItem = m_resizeController.formEditorItem(); + FormEditorItem *containerItem = m_snapper.containerFormEditorItem(); + + if (!containerItem) + return; + + QPointF updatePointInLocalSpace = m_beginFromSceneTransform.map(updatePoint); + QmlAnchors anchors(formEditorItem->qmlItemNode().anchors()); + + QRectF boundingRect(m_beginBoundingRect); + if (m_resizeHandle->isBottomRightHandle()) { + boundingRect.setBottomRight(updatePointInLocalSpace); + + if (useSnapping == UseSnapping) { + double rightOffset = m_snapper.snapRightOffset(boundingRect); + if (rightOffset < std::numeric_limits<double>::max()) + updatePointInLocalSpace.rx() -= rightOffset; + + double bottomOffset = m_snapper.snapBottomOffset(boundingRect); + if (bottomOffset < std::numeric_limits<double>::max()) + updatePointInLocalSpace.ry() -= bottomOffset; + } + boundingRect.setBottomRight(updatePointInLocalSpace); + + if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) { + boundingRect.setLeft(boundingRect.left() - (updatePointInLocalSpace.x() - m_beginBoundingRect.right())); + } + + if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) { + boundingRect.setTop(boundingRect.top() - (updatePointInLocalSpace.y() - m_beginBoundingRect.bottom())); + } + + if (boundingRect.width() < minimumWidth) + boundingRect.setWidth(minimumWidth); + if (boundingRect.height() < minimumHeight) + boundingRect.setHeight(minimumHeight); + + formEditorItem->qmlItemNode().setSize(boundingRect.size()); + + + if (anchors.instanceHasAnchor(AnchorLine::Bottom)) { + anchors.setMargin(AnchorLine::Bottom, + m_beginBottomMargin - (m_beginToParentTransform.map(boundingRect.bottomRight()) - m_beginBottomRightPoint).y()); + } + + if (anchors.instanceHasAnchor(AnchorLine::Right)) { + anchors.setMargin(AnchorLine::Right, + m_beginRightMargin - (m_beginToParentTransform.map(boundingRect.bottomRight()) - m_beginBottomRightPoint).x()); + } + } else if (m_resizeHandle->isTopLeftHandle()) { + boundingRect.setTopLeft(updatePointInLocalSpace); + + if (useSnapping == UseSnapping) { + double leftOffset = m_snapper.snapLeftOffset(boundingRect); + if (leftOffset < std::numeric_limits<double>::max()) + updatePointInLocalSpace.rx() -= leftOffset; + + double topOffset = m_snapper.snapTopOffset(boundingRect); + if (topOffset < std::numeric_limits<double>::max()) + updatePointInLocalSpace.ry() -= topOffset; + } + boundingRect.setTopLeft(updatePointInLocalSpace); + + if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) { + boundingRect.setRight(boundingRect.right() - (updatePointInLocalSpace.x() - m_beginBoundingRect.left())); + } + + if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) { + boundingRect.setBottom(boundingRect.bottom() - (updatePointInLocalSpace.y() - m_beginBoundingRect.top())); + } + + + if (boundingRect.width() < minimumWidth) + boundingRect.setLeft(boundingRect.left() - minimumWidth + boundingRect.width()); + if (boundingRect.height() < minimumHeight) + boundingRect.setTop(boundingRect.top() - minimumHeight + boundingRect.height()); + + formEditorItem->qmlItemNode().setSize(boundingRect.size()); + formEditorItem->qmlItemNode().setPosition(m_beginToParentTransform.map(boundingRect.topLeft())); + + + if (anchors.instanceHasAnchor(AnchorLine::Top)) { + anchors.setMargin(AnchorLine::Top, + m_beginTopMargin + (-m_beginToParentTransform.map(m_beginBoundingRect.topLeft()).y() + m_beginToParentTransform.map(boundingRect.topLeft()).y())); + } + + if (anchors.instanceHasAnchor(AnchorLine::Left)) { + anchors.setMargin(AnchorLine::Left, + m_beginLeftMargin + (-m_beginToParentTransform.map(m_beginBoundingRect.topLeft()).x() + m_beginToParentTransform.map(boundingRect.topLeft()).x())); + } + + } else if (m_resizeHandle->isTopRightHandle()) { + boundingRect.setTopRight(updatePointInLocalSpace); + + if (useSnapping == UseSnapping) { + double rightOffset = m_snapper.snapRightOffset(boundingRect); + if (rightOffset < std::numeric_limits<double>::max()) + updatePointInLocalSpace.rx() -= rightOffset; + + double topOffset = m_snapper.snapTopOffset(boundingRect); + if (topOffset < std::numeric_limits<double>::max()) + updatePointInLocalSpace.ry() -= topOffset; + } + boundingRect.setTopRight(updatePointInLocalSpace); + + if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) { + boundingRect.setLeft(boundingRect.left() - (updatePointInLocalSpace.x() - m_beginBoundingRect.right())); + } + + if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) { + boundingRect.setBottom(boundingRect.bottom() - (updatePointInLocalSpace.y() - m_beginBoundingRect.top())); + } + + if (boundingRect.height() < minimumHeight) + boundingRect.setTop(boundingRect.top() - minimumHeight + boundingRect.height()); + if (boundingRect.width() < minimumWidth) + boundingRect.setWidth(minimumWidth); + + formEditorItem->qmlItemNode().setSize(boundingRect.size()); + formEditorItem->qmlItemNode().setPosition(m_beginToParentTransform.map(boundingRect.topLeft())); + + if (anchors.instanceHasAnchor(AnchorLine::Top)) { + anchors.setMargin(AnchorLine::Top, + m_beginTopMargin + (-m_beginToParentTransform.map(m_beginBoundingRect.topLeft()).y() + m_beginToParentTransform.map(boundingRect.topLeft()).y())); + } + + if (anchors.instanceHasAnchor(AnchorLine::Right)) { + anchors.setMargin(AnchorLine::Right, + m_beginRightMargin - (m_beginToParentTransform.map(boundingRect.bottomRight()) - m_beginBottomRightPoint).x()); + } + } else if (m_resizeHandle->isBottomLeftHandle()) { + boundingRect.setBottomLeft(updatePointInLocalSpace); + + if (useSnapping == UseSnapping) { + double leftOffset = m_snapper.snapLeftOffset(boundingRect); + if (leftOffset < std::numeric_limits<double>::max()) + updatePointInLocalSpace.rx() -= leftOffset; + + double bottomOffset = m_snapper.snapBottomOffset(boundingRect); + if (bottomOffset < std::numeric_limits<double>::max()) + updatePointInLocalSpace.ry() -= bottomOffset; + } + + boundingRect.setBottomLeft(updatePointInLocalSpace); + + if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) { + boundingRect.setRight(boundingRect.right() - (updatePointInLocalSpace.x() - m_beginBoundingRect.left())); + } + + if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) { + boundingRect.setTop(boundingRect.top() - (updatePointInLocalSpace.y() - m_beginBoundingRect.bottom())); + } + + if (boundingRect.height() < minimumHeight) + boundingRect.setHeight(minimumHeight); + if (boundingRect.width() < minimumWidth) + boundingRect.setLeft(boundingRect.left() - minimumWidth + boundingRect.width()); + + formEditorItem->qmlItemNode().setSize(boundingRect.size()); + formEditorItem->qmlItemNode().setPosition(m_beginToParentTransform.map(boundingRect.topLeft())); + + if (anchors.instanceHasAnchor(AnchorLine::Left)) { + anchors.setMargin(AnchorLine::Left, + m_beginLeftMargin + (-m_beginToParentTransform.map(m_beginBoundingRect.topLeft()).x() + m_beginToParentTransform.map(boundingRect.topLeft()).x())); + } + + if (anchors.instanceHasAnchor(AnchorLine::Bottom)) { + anchors.setMargin(AnchorLine::Bottom, + m_beginBottomMargin - (m_beginToParentTransform.map(boundingRect.bottomRight()) - m_beginBottomRightPoint).y()); + } + } else if (m_resizeHandle->isBottomHandle()) { + boundingRect.setBottom(updatePointInLocalSpace.y()); + + if (useSnapping == UseSnapping) { + double bottomOffset = m_snapper.snapBottomOffset(boundingRect); + if (bottomOffset < std::numeric_limits<double>::max()) + updatePointInLocalSpace.ry() -= bottomOffset; + } + + boundingRect.setBottom(updatePointInLocalSpace.y()); + + if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) { + boundingRect.setTop(boundingRect.top() - (updatePointInLocalSpace.y() - m_beginBoundingRect.bottom())); + } + + if (boundingRect.height() < minimumHeight) + boundingRect.setHeight(minimumHeight); + + formEditorItem->qmlItemNode().setSize(boundingRect.size()); + + if (anchors.instanceHasAnchor(AnchorLine::Bottom)) { + anchors.setMargin(AnchorLine::Bottom, + m_beginBottomMargin - (m_beginToParentTransform.map(boundingRect.bottomRight()) - m_beginBottomRightPoint).y()); + } + } else if (m_resizeHandle->isTopHandle()) { + boundingRect.setTop(updatePointInLocalSpace.y()); + + if (useSnapping == UseSnapping) { + double topOffset = m_snapper.snapTopOffset(boundingRect); + if (topOffset < std::numeric_limits<double>::max()) + updatePointInLocalSpace.ry() -= topOffset; + } + + boundingRect.setTop(updatePointInLocalSpace.y()); + + if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) { + boundingRect.setBottom(boundingRect.bottom() - (updatePointInLocalSpace.y() - m_beginBoundingRect.top())); + } + + if (boundingRect.height() < minimumHeight) + boundingRect.setTop(boundingRect.top() - minimumHeight + boundingRect.height()); + + formEditorItem->qmlItemNode().setSize(boundingRect.size()); + formEditorItem->qmlItemNode().setPosition(m_beginToParentTransform.map(boundingRect.topLeft())); + + if (anchors.instanceHasAnchor(AnchorLine::Top)) { + anchors.setMargin(AnchorLine::Top, + m_beginTopMargin + (-m_beginToParentTransform.map(m_beginBoundingRect.topLeft()).y() + m_beginToParentTransform.map(boundingRect.topLeft()).y())); + } + } else if (m_resizeHandle->isRightHandle()) { + boundingRect.setRight(updatePointInLocalSpace.x()); + + if (useSnapping == UseSnapping) { + double rightOffset = m_snapper.snapRightOffset(boundingRect); + if (rightOffset < std::numeric_limits<double>::max()) + updatePointInLocalSpace.rx() -= rightOffset; + } + + boundingRect.setRight(updatePointInLocalSpace.x()); + + if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) { + boundingRect.setLeft(boundingRect.left() - (updatePointInLocalSpace.x() - m_beginBoundingRect.right())); + } + + if (boundingRect.width() < minimumWidth) + boundingRect.setWidth(minimumWidth); + + formEditorItem->qmlItemNode().setSize(boundingRect.size()); + + + if (anchors.instanceHasAnchor(AnchorLine::Right)) { + anchors.setMargin(AnchorLine::Right, + m_beginRightMargin - (m_beginToParentTransform.map(boundingRect.bottomRight()) - m_beginBottomRightPoint).x()); + } + } else if (m_resizeHandle->isLeftHandle()) { + boundingRect.setLeft(updatePointInLocalSpace.x()); + + if (useSnapping == UseSnapping) { + double leftOffset = m_snapper.snapLeftOffset(boundingRect); + if (leftOffset < std::numeric_limits<double>::max()) + updatePointInLocalSpace.rx() -= leftOffset; + } + + boundingRect.setLeft(updatePointInLocalSpace.x()); + + if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) { + boundingRect.setRight(boundingRect.right() - (updatePointInLocalSpace.x() - m_beginBoundingRect.left())); + } + + if (boundingRect.width() < minimumWidth) + boundingRect.setLeft(boundingRect.left() - minimumWidth + boundingRect.width()); + + formEditorItem->qmlItemNode().setSize(boundingRect.size()); + formEditorItem->qmlItemNode().setPosition(m_beginToParentTransform.map(boundingRect.topLeft())); + + if (anchors.instanceHasAnchor(AnchorLine::Left)) { + anchors.setMargin(AnchorLine::Left, + m_beginLeftMargin + (-m_beginToParentTransform.map(m_beginBoundingRect.topLeft()).x() + m_beginToParentTransform.map(boundingRect.topLeft()).x())); + } + } + + if (useSnapping == UseSnapping) + m_graphicsLineList = m_snapper.generateSnappingLines(boundingRect, + m_layerItem.data(), + m_beginToSceneTransform); + } +} + +void ResizeManipulator::end() +{ + m_rewriterTransaction.commit(); + clear(); + removeHandle(); +} + +void ResizeManipulator::moveBy(double deltaX, double deltaY) +{ + if (resizeHandle()) { + QmlItemNode qmlItemNode(m_resizeController.formEditorItem()->qmlItemNode()); + QmlAnchors anchors(qmlItemNode.anchors()); + + if (m_resizeController.isLeftHandle(resizeHandle()) + || m_resizeController.isTopLeftHandle(resizeHandle()) + || m_resizeController.isBottomLeftHandle(resizeHandle())) { + qmlItemNode.setVariantProperty("x", round((qmlItemNode.instanceValue("x").toDouble() + deltaX), 4)); + qmlItemNode.setVariantProperty("width", round(qmlItemNode.instanceValue("width").toDouble() - deltaX, 4)); + + + if (anchors.instanceHasAnchor(AnchorLine::Left)) { + anchors.setMargin(AnchorLine::Left, anchors.instanceMargin(AnchorLine::Left) + deltaX); + } + + if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) { + qmlItemNode.setVariantProperty("width", round(qmlItemNode.instanceValue("width").toDouble() - (deltaX * 2), 4)); + } + } + + if (m_resizeController.isRightHandle(resizeHandle()) + || m_resizeController.isTopRightHandle(resizeHandle()) + || m_resizeController.isBottomRightHandle(resizeHandle())) { + qmlItemNode.setVariantProperty("width", round(qmlItemNode.instanceValue("width").toDouble() + deltaX, 4)); + + if (anchors.instanceHasAnchor(AnchorLine::Right)) { + anchors.setMargin(AnchorLine::Right, round(anchors.instanceMargin(AnchorLine::Right) - deltaX, 4)); + } + + if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) { + qmlItemNode.setVariantProperty("width", round(qmlItemNode.instanceValue("width").toDouble() + (deltaX * 2), 4)); + } + } + + + if (m_resizeController.isTopHandle(resizeHandle()) + || m_resizeController.isTopLeftHandle(resizeHandle()) + || m_resizeController.isTopRightHandle(resizeHandle())) { + qmlItemNode.setVariantProperty("y", round(qmlItemNode.instanceValue("y").toDouble() + deltaY, 4)); + qmlItemNode.setVariantProperty("height", round(qmlItemNode.instanceValue("height").toDouble() - deltaY, 4)); + + if (anchors.instanceHasAnchor(AnchorLine::Top)) { + anchors.setMargin(AnchorLine::Top, anchors.instanceMargin(AnchorLine::Top) + deltaY); + } + + if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) { + qmlItemNode.setVariantProperty("height", round(qmlItemNode.instanceValue("height").toDouble() - (deltaY * 2), 4)); + } + } + + if (m_resizeController.isBottomHandle(resizeHandle()) + || m_resizeController.isBottomLeftHandle(resizeHandle()) + || m_resizeController.isBottomRightHandle(resizeHandle())) { + qmlItemNode.setVariantProperty("height", round(qmlItemNode.instanceValue("height").toDouble() + deltaY, 4)); + + if (anchors.instanceHasAnchor(AnchorLine::Bottom)) { + anchors.setMargin(AnchorLine::Bottom, anchors.instanceMargin(AnchorLine::Bottom) - deltaY); + } + + if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) { + qmlItemNode.setVariantProperty("height", round(qmlItemNode.instanceValue("height").toDouble() + (deltaY * 2), 4)); + } + } + + } +} + +bool ResizeManipulator::isInvalidSize(const QSizeF & size) +{ + if (size.width() < 15 || size.height() < 15) + return true; + + return false; +} + +void ResizeManipulator::deleteSnapLines() +{ + if (m_layerItem) { + foreach (QGraphicsItem *item, m_graphicsLineList) + m_layerItem->scene()->removeItem(item); + } + + m_graphicsLineList.clear(); + m_view->scene()->update(); +} + +ResizeHandleItem *ResizeManipulator::resizeHandle() +{ + return m_resizeHandle; +} + +void ResizeManipulator::clear() +{ + m_rewriterTransaction.commit(); + + deleteSnapLines(); + m_beginBoundingRect = QRectF(); + m_beginFromSceneTransform = QTransform(); + m_beginToSceneTransform = QTransform(); + m_beginToParentTransform = QTransform(); + m_beginTopMargin = 0.0; + m_beginLeftMargin = 0.0; + m_beginRightMargin = 0.0; + m_beginBottomMargin = 0.0; + removeHandle(); +} + +} diff --git a/src/plugins/qmldesigner/components/formeditor/resizemanipulator.h b/src/plugins/qmldesigner/components/formeditor/resizemanipulator.h new file mode 100644 index 0000000000..913966537f --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/resizemanipulator.h @@ -0,0 +1,91 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef RESIZEMANIPULATOR_H +#define RESIZEMANIPULATOR_H + +#include <QWeakPointer> +#include "resizehandleitem.h" +#include <snapper.h> +#include "rewritertransaction.h" +#include "formeditorview.h" + +namespace QmlDesigner { + +class ResizeHandleItem; +class Model; + +class ResizeManipulator +{ +public: + enum Snapping { + UseSnapping, + NoSnapping + }; + + ResizeManipulator(LayerItem *layerItem, FormEditorView *view); + ~ResizeManipulator(); + + void setHandle(ResizeHandleItem *resizeHandle); + void removeHandle(); + + void begin(const QPointF& beginPoint); + void update(const QPointF& updatePoint, Snapping useSnapping); + void end(); + + void moveBy(double deltaX, double deltaY); + + void clear(); + +protected: + bool isInvalidSize(const QSizeF & size); + void deleteSnapLines(); + ResizeHandleItem *resizeHandle(); + +private: + Snapper m_snapper; + QWeakPointer<FormEditorView> m_view; + QList<QGraphicsItem*> m_graphicsLineList; + ResizeController m_resizeController; // hold the controller so that the handle cant be deleted + QTransform m_beginFromSceneTransform; + QTransform m_beginToSceneTransform; + QTransform m_beginToParentTransform; + QRectF m_beginBoundingRect; + QPointF m_beginBottomRightPoint; + double m_beginTopMargin; + double m_beginLeftMargin; + double m_beginRightMargin; + double m_beginBottomMargin; + QWeakPointer<LayerItem> m_layerItem; + ResizeHandleItem *m_resizeHandle; + RewriterTransaction m_rewriterTransaction; +}; + +} +#endif // RESIZEMANIPULATOR_H diff --git a/src/plugins/qmldesigner/components/formeditor/resizetool.cpp b/src/plugins/qmldesigner/components/formeditor/resizetool.cpp new file mode 100644 index 0000000000..bd7d5157e1 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/resizetool.cpp @@ -0,0 +1,177 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "resizetool.h" + +#include "formeditorscene.h" +#include "formeditorview.h" + +#include "resizehandleitem.h" + +#include <QApplication> +#include <QGraphicsSceneMouseEvent> +#include <QtDebug> + +namespace QmlDesigner { + +ResizeTool::ResizeTool(FormEditorView *editorView) + : AbstractFormEditorTool(editorView), + m_selectionIndicator(editorView->scene()->manipulatorLayerItem()), + m_resizeIndicator(editorView->scene()->manipulatorLayerItem()), + m_resizeManipulator(editorView->scene()->manipulatorLayerItem(), editorView) +{ +} + + +ResizeTool::~ResizeTool() +{ +} + +void ResizeTool::mousePressEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event) +{ + if (itemList.isEmpty()) + return; + + ResizeHandleItem *resizeHandle = ResizeHandleItem::fromGraphicsItem(itemList.first()); + if (resizeHandle) { + m_resizeManipulator.setHandle(resizeHandle); + m_resizeManipulator.begin(event->scenePos()); + m_selectionIndicator.hide(); + m_resizeIndicator.hide(); + } +} + +void ResizeTool::mouseMoveEvent(const QList<QGraphicsItem*> &, + QGraphicsSceneMouseEvent *event) +{ + + + ResizeManipulator::Snapping useSnapping = ResizeManipulator::NoSnapping; + if (event->modifiers().testFlag(Qt::ControlModifier) != view()->isSnapButtonChecked()) + useSnapping = ResizeManipulator::UseSnapping; + + m_resizeManipulator.update(event->scenePos(), useSnapping); +} + +void ResizeTool::hoverMoveEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent * /*event*/) +{ + if (itemList.isEmpty()) + return; + ResizeHandleItem* resizeHandle = ResizeHandleItem::fromGraphicsItem(itemList.first()); + if (resizeHandle) { + m_resizeManipulator.setHandle(resizeHandle); + } else { + view()->changeToSelectionTool(); + return; + } +} + +void ResizeTool::mouseReleaseEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent * /*event*/) +{ + if (itemList.isEmpty()) + return; + + m_selectionIndicator.show(); + m_resizeIndicator.show(); + m_resizeManipulator.end(); +} + +void ResizeTool::mouseDoubleClickEvent(const QList<QGraphicsItem*> & /*itemList*/, + QGraphicsSceneMouseEvent * /*event*/) +{ +} + +void ResizeTool::keyPressEvent(QKeyEvent * event) +{ + switch(event->key()) { + case Qt::Key_Shift: + case Qt::Key_Alt: + case Qt::Key_Control: + case Qt::Key_AltGr: + event->setAccepted(false); + return; + } + + double moveStep = 1.0; + + if (event->modifiers().testFlag(Qt::ShiftModifier)) + moveStep = 10.0; + + switch(event->key()) { + case Qt::Key_Left: m_resizeManipulator.moveBy(-moveStep, 0.0); break; + case Qt::Key_Right: m_resizeManipulator.moveBy(moveStep, 0.0); break; + case Qt::Key_Up: m_resizeManipulator.moveBy(0.0, -moveStep); break; + case Qt::Key_Down: m_resizeManipulator.moveBy(0.0, moveStep); break; + } + +} + +void ResizeTool::keyReleaseEvent(QKeyEvent * keyEvent) +{ + switch(keyEvent->key()) { + case Qt::Key_Shift: + case Qt::Key_Alt: + case Qt::Key_Control: + case Qt::Key_AltGr: + keyEvent->setAccepted(false); + return; + } + +// if (!keyEvent->isAutoRepeat()) +// m_resizeManipulator.clear(); +} + +void ResizeTool::itemsAboutToRemoved(const QList<FormEditorItem*> & /*itemList*/) +{ + +} + +void ResizeTool::selectedItemsChanged(const QList<FormEditorItem*> & /*itemList*/) +{ + m_selectionIndicator.setItems(items()); + m_resizeIndicator.setItems(items()); +} + +void ResizeTool::clear() +{ + m_selectionIndicator.clear(); + m_resizeIndicator.clear(); + m_resizeManipulator.clear(); +} + +void ResizeTool::formEditorItemsChanged(const QList<FormEditorItem*> &itemList) +{ + m_selectionIndicator.updateItems(itemList); + m_resizeIndicator.updateItems(itemList); +} + +} diff --git a/src/plugins/qmldesigner/components/formeditor/resizetool.h b/src/plugins/qmldesigner/components/formeditor/resizetool.h new file mode 100644 index 0000000000..f376748ac0 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/resizetool.h @@ -0,0 +1,76 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef RESIZETOOL_H +#define RESIZETOOL_H + +#include "abstractformeditortool.h" +#include "selectionindicator.h" +#include "resizeindicator.h" +#include "resizemanipulator.h" + + +namespace QmlDesigner { + +class ResizeTool : public AbstractFormEditorTool +{ +public: + ResizeTool(FormEditorView* editorView); + ~ResizeTool(); + + void mousePressEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void mouseMoveEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void mouseDoubleClickEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void hoverMoveEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *keyEvent); + + void itemsAboutToRemoved(const QList<FormEditorItem*> &itemList); + + void selectedItemsChanged(const QList<FormEditorItem*> &itemList); + + void clear(); + + void formEditorItemsChanged(const QList<FormEditorItem*> &itemList); + +private: + SelectionIndicator m_selectionIndicator; + ResizeIndicator m_resizeIndicator; + ResizeManipulator m_resizeManipulator; +}; + +} + +#endif // RESIZETOOL_H diff --git a/src/plugins/qmldesigner/components/formeditor/rubberbandselectionmanipulator.cpp b/src/plugins/qmldesigner/components/formeditor/rubberbandselectionmanipulator.cpp new file mode 100644 index 0000000000..f9ca6b0831 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/rubberbandselectionmanipulator.cpp @@ -0,0 +1,153 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "rubberbandselectionmanipulator.h" + +#include "model.h" +#include "formeditorscene.h" + +namespace QmlDesigner { + +RubberBandSelectionManipulator::RubberBandSelectionManipulator(LayerItem *layerItem, FormEditorView *editorView) + : m_selectionRectangleElement(layerItem), + m_editorView(editorView), + m_beginFormEditorItem(0), + m_isActive(false) +{ + m_selectionRectangleElement.hide(); +} + +void RubberBandSelectionManipulator::clear() +{ + m_selectionRectangleElement.clear(); + m_isActive = false; + m_beginPoint = QPointF(); + m_itemList.clear(); + m_oldSelectionList.clear(); +} + +FormEditorItem *RubberBandSelectionManipulator::topFormEditorItem(const QList<QGraphicsItem*> &itemList) +{ + foreach (QGraphicsItem *item, itemList) { + FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item); + + if (formEditorItem) + { + return formEditorItem; + } + } + + return m_editorView->scene()->rootFormEditorItem(); +} + +void RubberBandSelectionManipulator::begin(const QPointF& beginPoint) +{ + m_beginPoint = beginPoint; + m_selectionRectangleElement.setRect(m_beginPoint, m_beginPoint); + m_selectionRectangleElement.show(); + m_isActive = true; + m_beginFormEditorItem = topFormEditorItem(m_editorView->scene()->items(beginPoint)); + m_oldSelectionList = m_editorView->selectedQmlItemNodes(); +} + +void RubberBandSelectionManipulator::update(const QPointF& updatePoint) +{ + m_selectionRectangleElement.setRect(m_beginPoint, updatePoint); +} + +void RubberBandSelectionManipulator::end() +{ + m_oldSelectionList.clear(); + m_selectionRectangleElement.hide(); + m_isActive = false; +} + +void RubberBandSelectionManipulator::select(SelectionType selectionType) +{ + if (!m_beginFormEditorItem) + return; + + QList<QGraphicsItem*> itemList = m_editorView->scene()->items(m_selectionRectangleElement.rect(), + Qt::IntersectsItemBoundingRect); + QList<QmlItemNode> newNodeList; + + foreach (QGraphicsItem* item, itemList) + { + FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item); + + if (formEditorItem + && m_beginFormEditorItem->childItems().contains(formEditorItem) + && !formEditorItem->qmlItemNode().isRootNode()) + { + newNodeList.append(formEditorItem->qmlItemNode()); + } + } + + if (newNodeList.isEmpty() && !m_beginFormEditorItem->qmlItemNode().isRootNode()) + newNodeList.append(m_beginFormEditorItem->qmlItemNode()); + + QList<QmlItemNode> nodeList; + + switch(selectionType) { + case AddToSelection: { + nodeList.append(m_oldSelectionList); + nodeList.append(newNodeList); + } + break; + case ReplaceSelection: { + nodeList.append(newNodeList); + } + break; + case RemoveFromSelection: { + QSet<QmlItemNode> oldSelectionSet(m_oldSelectionList.toSet()); + QSet<QmlItemNode> newSelectionSet(newNodeList.toSet()); + nodeList.append(oldSelectionSet.subtract(newSelectionSet).toList()); + } + } + + m_editorView->setSelectedQmlItemNodes(nodeList); +} + + +void RubberBandSelectionManipulator::setItems(const QList<FormEditorItem*> &itemList) +{ + m_itemList = itemList; +} + +QPointF RubberBandSelectionManipulator::beginPoint() const +{ + return m_beginPoint; +} + +bool RubberBandSelectionManipulator::isActive() const +{ + return m_isActive; +} + +} diff --git a/src/plugins/qmldesigner/components/formeditor/rubberbandselectionmanipulator.h b/src/plugins/qmldesigner/components/formeditor/rubberbandselectionmanipulator.h new file mode 100644 index 0000000000..bd8d9b6b2a --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/rubberbandselectionmanipulator.h @@ -0,0 +1,83 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef RUBBERBANDSELECTIONMANIPULATOR_H +#define RUBBERBANDSELECTIONMANIPULATOR_H + + +#include "selectionrectangle.h" +#include "formeditorview.h" +#include "formeditoritem.h" + +namespace QmlDesigner { + + +class RubberBandSelectionManipulator +{ +public: + enum SelectionType { + ReplaceSelection, + AddToSelection, + RemoveFromSelection + }; + + + RubberBandSelectionManipulator(LayerItem *layerItem, FormEditorView *editorView); + + void setItems(const QList<FormEditorItem*> &itemList); + + void begin(const QPointF& beginPoint); + void update(const QPointF& updatePoint); + void end(); + + void clear(); + + void select(SelectionType selectionType); + + QPointF beginPoint() const; + + bool isActive() const; + +protected: + FormEditorItem *topFormEditorItem(const QList<QGraphicsItem*> &itemList); + + +private: + QList<FormEditorItem*> m_itemList; + QList<QmlItemNode> m_oldSelectionList; + SelectionRectangle m_selectionRectangleElement; + QPointF m_beginPoint; + FormEditorView *m_editorView; + FormEditorItem *m_beginFormEditorItem; + bool m_isActive; +}; + +} + +#endif // RUBBERBANDSELECTIONMANIPULATOR_H diff --git a/src/plugins/qmldesigner/components/formeditor/scaleitem.cpp b/src/plugins/qmldesigner/components/formeditor/scaleitem.cpp new file mode 100644 index 0000000000..def9aeb5ee --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/scaleitem.cpp @@ -0,0 +1,49 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "scaleitem.h" + +#include "layeritem.h" + +namespace QmlDesigner { + +ScaleItem::ScaleItem(LayerItem *layerItem, ScaleIndicator *indicator) + : QGraphicsRectItem(layerItem), + m_indicator(indicator) +{ + Q_ASSERT(layerItem); + Q_ASSERT(indicator); +} + +ScaleIndicator* ScaleItem::indicator() const +{ + return m_indicator; +} + +} diff --git a/src/plugins/qmldesigner/components/formeditor/scaleitem.h b/src/plugins/qmldesigner/components/formeditor/scaleitem.h new file mode 100644 index 0000000000..c06d2170e2 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/scaleitem.h @@ -0,0 +1,53 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef SCALEITEM_H +#define SCALEITEM_H + +#include <QGraphicsRectItem> + +namespace QmlDesigner { + +class LayerItem; +class ScaleIndicator; + +class ScaleItem : public QGraphicsRectItem +{ +public: + ScaleItem(LayerItem *layerItem, ScaleIndicator *indicator); + + ScaleIndicator* indicator() const; + +private: + ScaleIndicator* m_indicator; +}; + +}; + +#endif // SCALEITEM_H diff --git a/src/plugins/qmldesigner/components/formeditor/scalemanipulator.cpp b/src/plugins/qmldesigner/components/formeditor/scalemanipulator.cpp new file mode 100644 index 0000000000..0c329f22b9 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/scalemanipulator.cpp @@ -0,0 +1,45 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "scalemanipulator.h" + + +namespace QmlDesigner { + +ScaleManipulator::ScaleManipulator(LayerItem *layerItem, FormEditorItem *formEditorItem) + : m_layerItem(layerItem), + m_formEditorItem(formEditorItem) +{ +} + +ScaleManipulator::~ScaleManipulator() +{ +} + +} diff --git a/src/plugins/qmldesigner/components/formeditor/scalemanipulator.h b/src/plugins/qmldesigner/components/formeditor/scalemanipulator.h new file mode 100644 index 0000000000..9d853d7f35 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/scalemanipulator.h @@ -0,0 +1,63 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef SCALEMANIPULATOR_H +#define SCALEMANIPULATOR_H + +#include <QPointF> +#include <QList> + + + +class QGraphicsLineItem; + +namespace QmlDesigner { + +class LayerItem; +class FormEditorItem; + +class ScaleManipulator +{ +public: + ScaleManipulator(LayerItem *layerItem, FormEditorItem *formEditorItem); + virtual ~ScaleManipulator(); + + + void begin(const QPointF& beginPoint); + void update(const QPointF& updatePoint); + void reparentTo(FormEditorItem *newParent); + void end(const QPointF& updatePoint); + +private: + LayerItem *m_layerItem; + FormEditorItem *m_formEditorItem; +}; + +} +#endif // SCALEMANIPULATOR_H diff --git a/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp b/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp new file mode 100644 index 0000000000..d71ef6cca2 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp @@ -0,0 +1,118 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "selectionindicator.h" + +#include <QPen> +#include <cmath> +#include <QGraphicsScene> +#include <formeditorview.h> +#include <formeditorwidget.h> +#include <zoomaction.h> + +namespace QmlDesigner { + +SelectionIndicator::SelectionIndicator(LayerItem *layerItem) + : m_layerItem(layerItem) +{ +} + +SelectionIndicator::~SelectionIndicator() +{ + clear(); +} + +void SelectionIndicator::show() +{ + foreach (QGraphicsPolygonItem *item, m_indicatorShapeHash.values()) + item->show(); +} + +void SelectionIndicator::hide() +{ + foreach (QGraphicsPolygonItem *item, m_indicatorShapeHash.values()) + item->hide(); +} + +void SelectionIndicator::clear() +{ + if (m_layerItem) { + foreach (QGraphicsItem *item, m_indicatorShapeHash.values()) + m_layerItem->scene()->removeItem(item); + } + m_indicatorShapeHash.clear(); +} + +static void alignVertices(QPolygonF &polygon, double factor) +{ + QMutableVectorIterator<QPointF> iterator(polygon); + while (iterator.hasNext()) { + QPointF &vertex = iterator.next(); + vertex.setX(std::floor(vertex.x()) + factor); + vertex.setY(std::floor(vertex.y()) + factor); + } + +} + +void SelectionIndicator::setItems(const QList<FormEditorItem*> &itemList) +{ + clear(); + + foreach (FormEditorItem *item, itemList) { + QGraphicsPolygonItem *newSelectionIndicatorGraphicsItem = new QGraphicsPolygonItem(m_layerItem.data()); + m_indicatorShapeHash.insert(item, newSelectionIndicatorGraphicsItem); + QPolygonF boundingRectInSceneSpace(item->mapToScene(item->qmlItemNode().instanceBoundingRect())); + alignVertices(boundingRectInSceneSpace, 0.5 / item->formEditorView()->widget()->zoomAction()->zoomLevel()); + QPolygonF boundingRectInLayerItemSpace = m_layerItem->mapFromScene(boundingRectInSceneSpace); + newSelectionIndicatorGraphicsItem->setPolygon(boundingRectInLayerItemSpace); + newSelectionIndicatorGraphicsItem->setFlag(QGraphicsItem::ItemIsSelectable, false); + + QPen pen; + pen.setColor(QColor(108, 141, 221)); + newSelectionIndicatorGraphicsItem->setPen(pen); + } +} + + + +void SelectionIndicator::updateItems(const QList<FormEditorItem*> &itemList) +{ + foreach (FormEditorItem *item, itemList) { + if (m_indicatorShapeHash.contains(item)) { + QGraphicsPolygonItem *indicatorGraphicsItem = m_indicatorShapeHash.value(item); + QPolygonF boundingRectInSceneSpace(item->mapToScene(item->qmlItemNode().instanceBoundingRect())); + alignVertices(boundingRectInSceneSpace, 0.5 / item->formEditorView()->widget()->zoomAction()->zoomLevel()); + QPolygonF boundingRectInLayerItemSpace = m_layerItem->mapFromScene(boundingRectInSceneSpace); + indicatorGraphicsItem->setPolygon(boundingRectInLayerItemSpace); + } + } +} + +} + diff --git a/src/plugins/qmldesigner/components/formeditor/selectionindicator.h b/src/plugins/qmldesigner/components/formeditor/selectionindicator.h new file mode 100644 index 0000000000..27e641b0a8 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/selectionindicator.h @@ -0,0 +1,65 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef SELECTIONINDICATOR_H +#define SELECTIONINDICATOR_H + +#include <QWeakPointer> +#include <QGraphicsPolygonItem> +#include "layeritem.h" +#include "formeditoritem.h" + + + +namespace QmlDesigner { + + +class SelectionIndicator +{ +public: + SelectionIndicator(LayerItem *layerItem); + ~SelectionIndicator(); + + void show(); + void hide(); + + void clear(); + + void setItems(const QList<FormEditorItem*> &itemList); + void updateItems(const QList<FormEditorItem*> &itemList); + +private: + QHash<FormEditorItem*, QGraphicsPolygonItem *> m_indicatorShapeHash; + QWeakPointer<LayerItem> m_layerItem; + +}; + +} + +#endif // SELECTIONINDICATOR_H diff --git a/src/plugins/qmldesigner/components/formeditor/selectionrectangle.cpp b/src/plugins/qmldesigner/components/formeditor/selectionrectangle.cpp new file mode 100644 index 0000000000..058de243e0 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/selectionrectangle.cpp @@ -0,0 +1,87 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "selectionrectangle.h" + +#include <QPen> +#include <QGraphicsScene> +#include <QtDebug> +#include <cmath> +#include <QGraphicsScene> + +namespace QmlDesigner { + +SelectionRectangle::SelectionRectangle(LayerItem *layerItem) + : m_controlShape(new QGraphicsRectItem(layerItem)), + m_layerItem(layerItem) +{ + m_controlShape->setPen(QPen(Qt::black)); + m_controlShape->setBrush(QColor(128, 128, 128, 50)); +} + +SelectionRectangle::~SelectionRectangle() +{ + if (m_layerItem) + m_layerItem->scene()->removeItem(m_controlShape); +} + +void SelectionRectangle::clear() +{ + hide(); +} +void SelectionRectangle::show() +{ + m_controlShape->show(); +} + +void SelectionRectangle::hide() +{ + m_controlShape->hide(); +} + +QRectF SelectionRectangle::rect() const +{ + return m_controlShape->mapFromScene(m_controlShape->rect()).boundingRect(); +} + +void SelectionRectangle::setRect(const QPointF &firstPoint, + const QPointF &secondPoint) +{ + double firstX = std::floor(firstPoint.x()) + 0.5; + double firstY = std::floor(firstPoint.y()) + 0.5; + double secondX = std::floor(secondPoint.x()) + 0.5; + double secondY = std::floor(secondPoint.y()) + 0.5; + QPointF topLeftPoint(firstX < secondX ? firstX : secondX, firstY < secondY ? firstY : secondY); + QPointF bottomRightPoint(firstX > secondX ? firstX : secondX, firstY > secondY ? firstY : secondY); + + QRectF rect(topLeftPoint, bottomRightPoint); + m_controlShape->setRect(rect); +} + +} diff --git a/src/plugins/qmldesigner/components/formeditor/selectionrectangle.h b/src/plugins/qmldesigner/components/formeditor/selectionrectangle.h new file mode 100644 index 0000000000..91839be73f --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/selectionrectangle.h @@ -0,0 +1,63 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef SELECTIONRECTANGLE_H +#define SELECTIONRECTANGLE_H + +#include <QWeakPointer> +#include <QGraphicsRectItem> +#include "layeritem.h" + + +namespace QmlDesigner { + +class SelectionRectangle +{ +public: + SelectionRectangle(LayerItem *layerItem); + ~SelectionRectangle(); + + void show(); + void hide(); + + void clear(); + + void setRect(const QPointF &firstPoint, + const QPointF &secondPoint); + + QRectF rect() const; + +private: + QGraphicsRectItem *m_controlShape; + QWeakPointer<LayerItem> m_layerItem; +}; + +} + +#endif // SELECTIONRECTANGLE_H diff --git a/src/plugins/qmldesigner/components/formeditor/selectiontool.cpp b/src/plugins/qmldesigner/components/formeditor/selectiontool.cpp new file mode 100644 index 0000000000..a3e7c1ee60 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/selectiontool.cpp @@ -0,0 +1,280 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "selectiontool.h" +#include "formeditorscene.h" +#include "formeditorview.h" + +#include "resizehandleitem.h" + + +#include <QApplication> +#include <QGraphicsSceneMouseEvent> +#include <QtDebug> +#include <QClipboard> + +namespace QmlDesigner { + +SelectionTool::SelectionTool(FormEditorView *editorView) + : AbstractFormEditorTool(editorView), + m_rubberbandSelectionManipulator(editorView->scene()->manipulatorLayerItem(), editorView), + m_singleSelectionManipulator(editorView), + m_selectionIndicator(editorView->scene()->manipulatorLayerItem()), + m_resizeIndicator(editorView->scene()->manipulatorLayerItem()) + +{ +// view()->setCursor(Qt::CrossCursor); +} + + +SelectionTool::~SelectionTool() +{ +} + +void SelectionTool::mousePressEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event) +{ + m_mousePressTimer.start(); + FormEditorItem* formEditorItem = topFormEditorItem(itemList); + if (formEditorItem && !formEditorItem->qmlItemNode().hasChildren()) { + m_singleSelectionManipulator.begin(event->scenePos()); + + if (event->modifiers().testFlag(Qt::ControlModifier)) + m_singleSelectionManipulator.select(SingleSelectionManipulator::RemoveFromSelection); + else if (event->modifiers().testFlag(Qt::ShiftModifier)) + m_singleSelectionManipulator.select(SingleSelectionManipulator::AddToSelection); + else + m_singleSelectionManipulator.select(SingleSelectionManipulator::InvertSelection); + } else { + if (event->modifiers().testFlag(Qt::AltModifier)) { + m_singleSelectionManipulator.begin(event->scenePos()); + + if (event->modifiers().testFlag(Qt::ControlModifier)) + m_singleSelectionManipulator.select(SingleSelectionManipulator::RemoveFromSelection); + else if (event->modifiers().testFlag(Qt::ShiftModifier)) + m_singleSelectionManipulator.select(SingleSelectionManipulator::AddToSelection); + else + m_singleSelectionManipulator.select(SingleSelectionManipulator::InvertSelection); + + m_singleSelectionManipulator.end(event->scenePos()); + view()->changeToMoveTool(event->scenePos()); + } else { + m_rubberbandSelectionManipulator.begin(event->scenePos()); + } + } +} + +void SelectionTool::mouseMoveEvent(const QList<QGraphicsItem*> &/*itemList*/, + QGraphicsSceneMouseEvent *event) +{ + if (m_singleSelectionManipulator.isActive()) { + QPointF mouseMovementVector = m_singleSelectionManipulator.beginPoint() - event->scenePos(); + if ((mouseMovementVector.toPoint().manhattanLength() > QApplication::startDragDistance()) + && (m_mousePressTimer.elapsed() > QApplication::startDragTime())) { + m_singleSelectionManipulator.end(event->scenePos()); + view()->changeToMoveTool(m_singleSelectionManipulator.beginPoint()); + return; + } + } else if (m_rubberbandSelectionManipulator.isActive()) { + QPointF mouseMovementVector = m_rubberbandSelectionManipulator.beginPoint() - event->scenePos(); + if ((mouseMovementVector.toPoint().manhattanLength() > QApplication::startDragDistance()) + && (m_mousePressTimer.elapsed() > QApplication::startDragTime())) { + m_rubberbandSelectionManipulator.update(event->scenePos()); + + if (event->modifiers().testFlag(Qt::ControlModifier)) + m_rubberbandSelectionManipulator.select(RubberBandSelectionManipulator::RemoveFromSelection); + else if (event->modifiers().testFlag(Qt::ShiftModifier)) + m_rubberbandSelectionManipulator.select(RubberBandSelectionManipulator::AddToSelection); + else + m_rubberbandSelectionManipulator.select(RubberBandSelectionManipulator::ReplaceSelection); + } + } +} + +void SelectionTool::hoverMoveEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent * /*event*/) +{ + if (itemList.isEmpty()) + return; + + ResizeHandleItem* resizeHandle = ResizeHandleItem::fromGraphicsItem(itemList.first()); + if (resizeHandle) { + view()->changeToResizeTool(); + return; + } + + if (topSelectedItemIsMovable(itemList)) + view()->changeToMoveTool(); +} + +void SelectionTool::mouseReleaseEvent(const QList<QGraphicsItem*> &/*itemList*/, + QGraphicsSceneMouseEvent *event) +{ + if (m_singleSelectionManipulator.isActive()) { + qDebug() << __FUNCTION__ << "single"; + m_singleSelectionManipulator.end(event->scenePos()); + } + else if (m_rubberbandSelectionManipulator.isActive()) { + + QPointF mouseMovementVector = m_rubberbandSelectionManipulator.beginPoint() - event->scenePos(); + if (mouseMovementVector.toPoint().manhattanLength() < QApplication::startDragDistance()) { + m_singleSelectionManipulator.begin(event->scenePos()); + + if (event->modifiers().testFlag(Qt::ControlModifier)) + m_singleSelectionManipulator.select(SingleSelectionManipulator::RemoveFromSelection); + else if (event->modifiers().testFlag(Qt::ShiftModifier)) + m_singleSelectionManipulator.select(SingleSelectionManipulator::AddToSelection); + else + m_singleSelectionManipulator.select(SingleSelectionManipulator::InvertSelection); + + m_singleSelectionManipulator.end(event->scenePos()); + } else { + m_rubberbandSelectionManipulator.update(event->scenePos()); + + if (event->modifiers().testFlag(Qt::ControlModifier)) + m_rubberbandSelectionManipulator.select(RubberBandSelectionManipulator::RemoveFromSelection); + else if (event->modifiers().testFlag(Qt::ShiftModifier)) + m_rubberbandSelectionManipulator.select(RubberBandSelectionManipulator::AddToSelection); + else + m_rubberbandSelectionManipulator.select(RubberBandSelectionManipulator::ReplaceSelection); + + m_rubberbandSelectionManipulator.end(); + } + } + +} + +void SelectionTool::mouseDoubleClickEvent(const QList<QGraphicsItem*> &/*itemList*/, + QGraphicsSceneMouseEvent * /*event*/) +{ + +} + +void SelectionTool::keyPressEvent(QKeyEvent *event) +{ + switch(event->key()) { + case Qt::Key_Left: + case Qt::Key_Right: + case Qt::Key_Up: + case Qt::Key_Down: + view()->changeToMoveTool(); + view()->currentTool()->keyPressEvent(event); + break; + case Qt::Key_C: + if (event->modifiers().testFlag(Qt::ControlModifier)) { + copySelectedNodeToClipBoard(); + break; + } + case Qt::Key_V: + if (event->modifiers().testFlag(Qt::ControlModifier)) { + pasteClipBoard(); + break; + } + case Qt::Key_X: + if (event->modifiers().testFlag(Qt::ControlModifier)) { + cutSelectedNodeToClipBoard(); + break; + } + } +} + +void SelectionTool::keyReleaseEvent(QKeyEvent * /*keyEvent*/) +{ + +} + +void SelectionTool::copySelectedNodeToClipBoard() +{ + // QClipboard *clipboard = QApplication::clipboard(); +} + +void SelectionTool::cutSelectedNodeToClipBoard() +{ + // QClipboard *clipboard = QApplication::clipboard(); +} + +void SelectionTool::pasteClipBoard() +{ + // QClipboard *clipboard = QApplication::clipboard(); +} + +void SelectionTool::itemsAboutToRemoved(const QList<FormEditorItem*> &/*itemList*/) +{ + +} + +//QVariant SelectionTool::itemChange(const QList<QGraphicsItem*> &itemList, +// QGraphicsItem::GraphicsItemChange change, +// const QVariant &value ) +//{ +// qDebug() << Q_FUNC_INFO; +// return QVariant(); +//} + +//void SelectionTool::update() +//{ +// +//} + + +void SelectionTool::clear() +{ + m_rubberbandSelectionManipulator.clear(), + m_singleSelectionManipulator.clear(); + m_selectionIndicator.clear(); + m_resizeIndicator.clear(); +} + +void SelectionTool::selectedItemsChanged(const QList<FormEditorItem*> &itemList) +{ + m_selectionIndicator.setItems(itemList); + m_resizeIndicator.setItems(itemList); +} + +void SelectionTool::formEditorItemsChanged(const QList<FormEditorItem*> &itemList) +{ + m_selectionIndicator.updateItems(itemList); + m_resizeIndicator.updateItems(itemList); +} + +void SelectionTool::selectUnderPoint(QGraphicsSceneMouseEvent *event) +{ + m_singleSelectionManipulator.begin(event->scenePos()); + + if (event->modifiers().testFlag(Qt::ControlModifier)) + m_singleSelectionManipulator.select(SingleSelectionManipulator::RemoveFromSelection); + else if (event->modifiers().testFlag(Qt::ShiftModifier)) + m_singleSelectionManipulator.select(SingleSelectionManipulator::AddToSelection); + else + m_singleSelectionManipulator.select(SingleSelectionManipulator::ReplaceSelection); + + m_singleSelectionManipulator.end(event->scenePos()); +} + +} diff --git a/src/plugins/qmldesigner/components/formeditor/selectiontool.h b/src/plugins/qmldesigner/components/formeditor/selectiontool.h new file mode 100644 index 0000000000..062eb20fbc --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/selectiontool.h @@ -0,0 +1,93 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef SELECTIONTOOL_H +#define SELECTIONTOOL_H + + +#include "abstractformeditortool.h" +#include "movemanipulator.h" +#include "rubberbandselectionmanipulator.h" +#include "singleselectionmanipulator.h" +#include "selectionindicator.h" +#include "resizeindicator.h" + +#include <QHash> +#include <QTime> + +namespace QmlDesigner { + + +class SelectionTool : public AbstractFormEditorTool +{ +public: + SelectionTool(FormEditorView* editorView); + ~SelectionTool(); + + void mousePressEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void mouseMoveEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void mouseDoubleClickEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void hoverMoveEvent(const QList<QGraphicsItem*> &itemList, + QGraphicsSceneMouseEvent *event); + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *keyEvent); + + void itemsAboutToRemoved(const QList<FormEditorItem*> &itemList); + // QVariant itemChange(const QList<QGraphicsItem*> &itemList, +// QGraphicsItem::GraphicsItemChange change, +// const QVariant &value ); + +// void update(); + + void clear(); + + void selectedItemsChanged(const QList<FormEditorItem*> &itemList); + + void formEditorItemsChanged(const QList<FormEditorItem*> &itemList); + + void selectUnderPoint(QGraphicsSceneMouseEvent *event); + + void copySelectedNodeToClipBoard(); + void cutSelectedNodeToClipBoard(); + void pasteClipBoard(); +private: + RubberBandSelectionManipulator m_rubberbandSelectionManipulator; + SingleSelectionManipulator m_singleSelectionManipulator; + SelectionIndicator m_selectionIndicator; + ResizeIndicator m_resizeIndicator; + QTime m_mousePressTimer; +}; + +} +#endif // SELECTIONTOOL_H diff --git a/src/plugins/qmldesigner/components/formeditor/singleselectionmanipulator.cpp b/src/plugins/qmldesigner/components/formeditor/singleselectionmanipulator.cpp new file mode 100644 index 0000000000..43625eb955 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/singleselectionmanipulator.cpp @@ -0,0 +1,132 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "singleselectionmanipulator.h" + +#include "model.h" +#include "nodemetainfo.h" +#include "formeditorscene.h" +#include "formeditorview.h" +#include <QtDebug> + +namespace QmlDesigner { + +SingleSelectionManipulator::SingleSelectionManipulator(FormEditorView *editorView) + : m_editorView(editorView), + m_isActive(false) +{ +} + + +void SingleSelectionManipulator::begin(const QPointF &beginPoint) +{ + m_beginPoint = beginPoint; + m_isActive = true; + m_oldSelectionList = m_editorView->selectedQmlItemNodes(); +} + +void SingleSelectionManipulator::update(const QPointF &/*updatePoint*/) +{ + m_oldSelectionList.clear(); +} + +void SingleSelectionManipulator::clear() +{ + m_beginPoint = QPointF(); + m_oldSelectionList.clear(); +} + + +void SingleSelectionManipulator::end(const QPointF &/*updatePoint*/) +{ + m_oldSelectionList.clear(); + m_isActive = false; +} + +void SingleSelectionManipulator::select(SelectionType selectionType) +{ + QList<QGraphicsItem*> itemList = m_editorView->scene()->items(m_beginPoint); + + QmlItemNode selectedNode; + + foreach(QGraphicsItem* item, itemList) + { + FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item); + + if (formEditorItem + && !formEditorItem->qmlItemNode().isRootNode() + && (formEditorItem->qmlItemNode().hasShowContent())) + { + selectedNode = formEditorItem->qmlItemNode(); + break; + } + } + + QList<QmlItemNode> nodeList; + + switch(selectionType) { + case AddToSelection: { + nodeList.append(m_oldSelectionList); + if (selectedNode.isValid()) + nodeList.append(selectedNode); + } + break; + case ReplaceSelection: { + if (selectedNode.isValid()) + nodeList.append(selectedNode); + } + break; + case RemoveFromSelection: { + nodeList.append(m_oldSelectionList); + if (selectedNode.isValid()) + nodeList.removeAll(selectedNode); + } + break; + case InvertSelection: { + if (selectedNode.isValid() + && !m_oldSelectionList.contains(selectedNode)) + nodeList.append(selectedNode); + } + } + + m_editorView->setSelectedQmlItemNodes(nodeList); +} + + +bool SingleSelectionManipulator::isActive() const +{ + return m_isActive; +} + +QPointF SingleSelectionManipulator::beginPoint() const +{ + return m_beginPoint; +} + +} diff --git a/src/plugins/qmldesigner/components/formeditor/singleselectionmanipulator.h b/src/plugins/qmldesigner/components/formeditor/singleselectionmanipulator.h new file mode 100644 index 0000000000..a97abaa145 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/singleselectionmanipulator.h @@ -0,0 +1,72 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef SINGLESELECTIONMANIPULATOR_H +#define SINGLESELECTIONMANIPULATOR_H + +#include "selectionrectangle.h" +#include "formeditorview.h" + +namespace QmlDesigner { + +class SingleSelectionManipulator +{ +public: + SingleSelectionManipulator(FormEditorView *editorView); + +// void setItems(const QList<FormEditorItem*> &itemList); + + enum SelectionType { + ReplaceSelection, + AddToSelection, + RemoveFromSelection, + InvertSelection + }; + + void begin(const QPointF& beginPoint); + void update(const QPointF& updatePoint); + void end(const QPointF& updatePoint); + + void select(SelectionType selectionType); + + void clear(); + + QPointF beginPoint() const; + + bool isActive() const; + +private: + QList<QmlItemNode> m_oldSelectionList; + QPointF m_beginPoint; + FormEditorView *m_editorView; + bool m_isActive; +}; + +} +#endif // SINGLESELECTIONMANIPULATOR_H diff --git a/src/plugins/qmldesigner/components/formeditor/snapper.cpp b/src/plugins/qmldesigner/components/formeditor/snapper.cpp new file mode 100644 index 0000000000..506146836c --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/snapper.cpp @@ -0,0 +1,626 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "snapper.h" + +#include <QtDebug> + +#include <limits> +#include <cmath> +#include <QLineF> +#include <QPen> +#include <QApplication> + +namespace QmlDesigner { + +Snapper::Snapper() + : m_containerFormEditorItem(0), + m_transformtionSpaceFormEditorItem(0), + m_snappingDistance(5.0) +{ +} + +void Snapper::updateSnappingLines(const QList<FormEditorItem*> &exceptionList) +{ + if (m_containerFormEditorItem) + m_containerFormEditorItem->updateSnappingLines(exceptionList, m_transformtionSpaceFormEditorItem); +} + +void Snapper::updateSnappingLines(FormEditorItem* exceptionItem) +{ + QList<FormEditorItem*> exceptionList; + exceptionList.append(exceptionItem); + updateSnappingLines(exceptionList); +} + + +void Snapper::setContainerFormEditorItem(FormEditorItem *formEditorItem) +{ + m_containerFormEditorItem = formEditorItem; +} + + +void Snapper::setTransformtionSpaceFormEditorItem(FormEditorItem *formEditorItem) +{ + m_transformtionSpaceFormEditorItem = formEditorItem; +} + +FormEditorItem *Snapper::transformtionSpaceFormEditorItem() const +{ + return m_transformtionSpaceFormEditorItem; +} + +double Snapper::snappedVerticalOffset(const QRectF &boundingRect) const +{ + double offset = std::numeric_limits<double>::max(); + + offset = qMin(offset, snappedOffsetForLines(containerFormEditorItem()->leftSnappingLines(), + boundingRect.left())); + + offset = qMin(offset, snappedOffsetForOffsetLines(containerFormEditorItem()->rightSnappingOffsets(), + Qt::Vertical, + boundingRect.left(), + boundingRect.top(), + boundingRect.bottom())); + + offset = qMin(offset, snappedOffsetForLines(containerFormEditorItem()->rightSnappingLines(), + boundingRect.right())); + + offset = qMin(offset, snappedOffsetForOffsetLines(containerFormEditorItem()->leftSnappingOffsets(), + Qt::Vertical, + boundingRect.right(), + boundingRect.top(), + boundingRect.bottom())); + + offset = qMin(offset, snappedOffsetForLines(containerFormEditorItem()->verticalCenterSnappingLines(), + boundingRect.center().x())); + + return offset; +} + +double Snapper::snappedHorizontalOffset(const QRectF &boundingRect) const +{ + double offset = std::numeric_limits<double>::max(); + + offset = qMin(offset, snappedOffsetForLines(containerFormEditorItem()->topSnappingLines(), + boundingRect.top())); + + offset = qMin(offset, snappedOffsetForOffsetLines(containerFormEditorItem()->bottomSnappingOffsets(), + Qt::Horizontal, + boundingRect.top(), + boundingRect.left(), + boundingRect.right())); + + offset = qMin(offset, snappedOffsetForLines(containerFormEditorItem()->bottomSnappingLines(), + boundingRect.bottom())); + + offset = qMin(offset, snappedOffsetForOffsetLines(containerFormEditorItem()->topSnappingOffsets(), + Qt::Horizontal, + boundingRect.bottom(), + boundingRect.left(), + boundingRect.right())); + + offset = qMin(offset, snappedOffsetForLines(containerFormEditorItem()->horizontalCenterSnappingLines(), + boundingRect.center().y())); + return offset; +} + + +double Snapper::snapTopOffset(const QRectF &boundingRect) const +{ + double offset = std::numeric_limits<double>::max(); + + offset = qMin(offset, snappedOffsetForLines(containerFormEditorItem()->topSnappingLines(), + boundingRect.top())); + + offset = qMin(offset, snappedOffsetForOffsetLines(containerFormEditorItem()->bottomSnappingOffsets(), + Qt::Horizontal, + boundingRect.top(), + boundingRect.left(), + boundingRect.right())); + return offset; +} + +double Snapper::snapRightOffset(const QRectF &boundingRect) const +{ + double offset = std::numeric_limits<double>::max(); + + offset = qMin(offset, snappedOffsetForLines(containerFormEditorItem()->rightSnappingLines(), + boundingRect.right())); + + offset = qMin(offset, snappedOffsetForOffsetLines(containerFormEditorItem()->leftSnappingOffsets(), + Qt::Vertical, + boundingRect.right(), + boundingRect.top(), + boundingRect.bottom())); + return offset; +} + +double Snapper::snapLeftOffset(const QRectF &boundingRect) const +{ + double offset = std::numeric_limits<double>::max(); + + offset = qMin(offset, snappedOffsetForLines(containerFormEditorItem()->leftSnappingLines(), + boundingRect.left())); + + offset = qMin(offset, snappedOffsetForOffsetLines(containerFormEditorItem()->rightSnappingOffsets(), + Qt::Vertical, + boundingRect.left(), + boundingRect.top(), + boundingRect.bottom())); + return offset; +} + +double Snapper::snapBottomOffset(const QRectF &boundingRect) const +{ + double offset = std::numeric_limits<double>::max(); + + offset = qMin(offset, snappedOffsetForLines(containerFormEditorItem()->bottomSnappingLines(), + boundingRect.bottom())); + + offset = qMin(offset, snappedOffsetForOffsetLines(containerFormEditorItem()->topSnappingOffsets(), + Qt::Horizontal, + boundingRect.bottom(), + boundingRect.left(), + boundingRect.right())); + return offset; + +} + + +QList<QLineF> Snapper::verticalSnappedLines(const QRectF &boundingRect, QList<QRectF> *boundingRects) const +{ + QList<QLineF> lineList = findSnappingLines(containerFormEditorItem()->leftSnappingLines(), + Qt::Vertical, + boundingRect.left(), + boundingRect.top(), + boundingRect.bottom(), + boundingRects); + + lineList += findSnappingOffsetLines(containerFormEditorItem()->rightSnappingOffsets(), + Qt::Vertical, + boundingRect.left(), + boundingRect.top(), + boundingRect.bottom(), + boundingRects); + + + lineList += findSnappingLines(containerFormEditorItem()->rightSnappingLines(), + Qt::Vertical, + boundingRect.right(), + boundingRect.top(), + boundingRect.bottom(), + boundingRects); + + lineList += findSnappingOffsetLines(containerFormEditorItem()->leftSnappingOffsets(), + Qt::Vertical, + boundingRect.right(), + boundingRect.top(), + boundingRect.bottom(), + boundingRects); + + lineList += findSnappingLines(containerFormEditorItem()->verticalCenterSnappingLines(), + Qt::Vertical, + boundingRect.center().x(), + boundingRect.top(), + boundingRect.bottom(), + boundingRects); + + return lineList; +} + +QList<QLineF> Snapper::horizontalSnappedLines(const QRectF &boundingRect, QList<QRectF> *boundingRects) const +{ + QList<QLineF> lineList = findSnappingLines(containerFormEditorItem()->topSnappingLines(), + Qt::Horizontal, + boundingRect.top(), + boundingRect.left(), + boundingRect.right()); + + lineList += findSnappingOffsetLines(containerFormEditorItem()->bottomSnappingOffsets(), + Qt::Horizontal, + boundingRect.top(), + boundingRect.left(), + boundingRect.right(), + boundingRects); + + + lineList += findSnappingLines(containerFormEditorItem()->bottomSnappingLines(), + Qt::Horizontal, + boundingRect.bottom(), + boundingRect.left(), + boundingRect.right(), + boundingRects); + + lineList += findSnappingOffsetLines(containerFormEditorItem()->topSnappingOffsets(), + Qt::Horizontal, + boundingRect.bottom(), + boundingRect.left(), + boundingRect.right(), + boundingRects); + + lineList += findSnappingLines(containerFormEditorItem()->horizontalCenterSnappingLines(), + Qt::Horizontal, + boundingRect.center().y(), + boundingRect.left(), + boundingRect.right(), + boundingRects); + + return lineList; +} + + + +FormEditorItem *Snapper::containerFormEditorItem() const +{ + return m_containerFormEditorItem; +} + +QLineF Snapper::createSnapLine(Qt::Orientation orientation, + double snapLine, + double lowerLimit, + double upperLimit, + const QRectF &itemRect) const +{ + if (orientation == Qt::Horizontal) { + double lowerX(qMin(lowerLimit, itemRect.left())); + double upperX(qMax(upperLimit, itemRect.right())); + return QLineF(lowerX, snapLine, upperX, snapLine); + } else { + double lowerY(qMin(lowerLimit, itemRect.top())); + double upperY(qMax(upperLimit, itemRect.bottom())); + return QLineF(snapLine, lowerY, snapLine, upperY); + } +} + +static bool compareLines(double snapLine, double lineToSnap) +{ +// if (qAbs(snapLine - lineToSnap) < 1.0) +// return true; +// +// return false; + return qFuzzyCompare(snapLine, lineToSnap); +} + +QList<QLineF> Snapper::findSnappingLines(const SnapLineMap &snappingLineMap, + Qt::Orientation orientation, + double snapLine, + double lowerLimit, + double upperLimit, + QList<QRectF> *boundingRects) const +{ + QList<QLineF> lineList; + + SnapLineMapIterator snappingLineIterator(snappingLineMap); + while (snappingLineIterator.hasNext()) { + snappingLineIterator.next(); + + if (compareLines(snapLine, snappingLineIterator.key())) { // near distance snapping lines + lineList += createSnapLine(orientation, + snappingLineIterator.key(), + lowerLimit, + upperLimit, + snappingLineIterator.value().first); + if (boundingRects != 0) + boundingRects->append(snappingLineIterator.value().first); + } + } + + return lineList; +} + + +QList<QLineF> Snapper::findSnappingOffsetLines(const SnapLineMap &snappingOffsetMap, + Qt::Orientation orientation, + double snapLine, + double lowerLimit, + double upperLimit, + QList<QRectF> *boundingRects) const +{ + QList<QLineF> lineList; + + SnapLineMapIterator snappingOffsetIterator(snappingOffsetMap); + while (snappingOffsetIterator.hasNext()) { + snappingOffsetIterator.next(); + + const QRectF &formEditorItemRect(snappingOffsetIterator.value().first); + double formEditorItemRectLowerLimit; + double formEditorItemRectUpperLimit; + if (orientation == Qt::Horizontal) { + formEditorItemRectLowerLimit = formEditorItemRect.left(); + formEditorItemRectUpperLimit = formEditorItemRect.right(); + } else { + formEditorItemRectLowerLimit = formEditorItemRect.top(); + formEditorItemRectUpperLimit = formEditorItemRect.bottom(); + } + + + if (qFuzzyCompare(snapLine, snappingOffsetIterator.key()) && + !(lowerLimit > formEditorItemRectUpperLimit || + upperLimit < formEditorItemRectLowerLimit)) { + lineList += createSnapLine(orientation, + snapLine, + lowerLimit, + upperLimit, + formEditorItemRect); + if (boundingRects != 0) + boundingRects->append(snappingOffsetIterator.value().first); + } + } + + + return lineList; +} + +double Snapper::snappedOffsetForLines(const SnapLineMap &snappingLineMap, + double value) const +{ + QMultiMap<double, double> minimumSnappingLineMap; + + SnapLineMapIterator snappingLineIterator(snappingLineMap); + while (snappingLineIterator.hasNext()) { + snappingLineIterator.next(); + double snapLine = snappingLineIterator.key(); + double offset = value - snapLine; + double distance = qAbs(offset); + + if (distance < snappingDistance()) { + minimumSnappingLineMap.insert(distance, offset); + } + } + + if (!minimumSnappingLineMap.isEmpty()) { + return minimumSnappingLineMap.begin().value(); + } + + return std::numeric_limits<double>::max(); +} + + +double Snapper::snappedOffsetForOffsetLines(const SnapLineMap &snappingOffsetMap, + Qt::Orientation orientation, + double value, + double lowerLimit, + double upperLimit) const +{ + QMultiMap<double, double> minimumSnappingLineMap; + + SnapLineMapIterator snappingOffsetIterator(snappingOffsetMap); + while (snappingOffsetIterator.hasNext()) { + snappingOffsetIterator.next(); + double snapLine = snappingOffsetIterator.key(); + const QRectF &formEditorItemRect(snappingOffsetIterator.value().first); + double formEditorItemRectLowerLimit; + double formEditorItemRectUpperLimit; + if (orientation == Qt::Horizontal) { + formEditorItemRectLowerLimit = formEditorItemRect.left(); + formEditorItemRectUpperLimit = formEditorItemRect.right(); + } else { + formEditorItemRectLowerLimit = formEditorItemRect.top(); + formEditorItemRectUpperLimit = formEditorItemRect.bottom(); + } + + double offset = value - snapLine; + double distance = qAbs(offset); + + if (distance < snappingDistance() && + !(lowerLimit > formEditorItemRectUpperLimit || + upperLimit < formEditorItemRectLowerLimit)) { + + minimumSnappingLineMap.insert(distance, offset); + } + } + + if (!minimumSnappingLineMap.isEmpty()) { + return minimumSnappingLineMap.begin().value(); + } + + return std::numeric_limits<double>::max(); +} + + +void Snapper::setSnappingDistance(double snappingDistance) +{ + m_snappingDistance = snappingDistance; +} + +double Snapper::snappingDistance() const +{ + return m_snappingDistance; +} + +static bool lineXLessThan(const QLineF &firstLine, const QLineF &secondLine) +{ + return firstLine.x1() < secondLine.x2(); +} + +static bool lineYLessThan(const QLineF &firstLine, const QLineF &secondLine) +{ + return firstLine.y1() < secondLine.y2(); +} + + +static QLineF mergedHorizontalLine(const QList<QLineF> &lineList) +{ + if (lineList.count() == 1) + return lineList.first(); + + double minimumX = std::numeric_limits<double>::max(); + double maximumX = std::numeric_limits<double>::min(); + foreach(const QLineF &line, lineList) { + minimumX = qMin(minimumX, line.x1()); + minimumX = qMin(minimumX, line.x2()); + maximumX = qMax(maximumX, line.x1()); + maximumX = qMax(maximumX, line.x2()); + } + + double y(lineList.first().y1()); + return QLineF(minimumX, y, maximumX, y);; +} + +static QLineF mergedVerticalLine(const QList<QLineF> &lineList) +{ + if (lineList.count() == 1) + return lineList.first(); + + double minimumY = std::numeric_limits<double>::max(); + double maximumY = std::numeric_limits<double>::min(); + foreach(const QLineF &line, lineList) { + minimumY = qMin(minimumY, line.y1()); + minimumY = qMin(minimumY, line.y2()); + maximumY = qMax(maximumY, line.y1()); + maximumY = qMax(maximumY, line.y2()); + } + + double x(lineList.first().x1()); + return QLineF(x, minimumY, x, maximumY);; +} + +static QList<QLineF> mergedHorizontalLines(const QList<QLineF> &lineList) +{ + QList<QLineF> mergedLineList; + + QList<QLineF> sortedLineList(lineList); + qSort(sortedLineList.begin(), sortedLineList.end(), lineYLessThan); + + QList<QLineF> lineWithTheSameY; + QListIterator<QLineF> sortedLineListIterator(sortedLineList); + while (sortedLineListIterator.hasNext()) { + QLineF line = sortedLineListIterator.next(); + lineWithTheSameY.append(line); + + if (sortedLineListIterator.hasNext()) { + QLineF nextLine = sortedLineListIterator.peekNext(); + if (!qFuzzyCompare(line.y1(), nextLine.y1())) { + mergedLineList.append(mergedHorizontalLine(lineWithTheSameY)); + lineWithTheSameY.clear(); + } + } else { + mergedLineList.append(mergedHorizontalLine(lineWithTheSameY)); + } + } + + return mergedLineList; +} + + + + + + +static QList<QLineF> mergedVerticalLines(const QList<QLineF> &lineList) +{ + QList<QLineF> mergedLineList; + + QList<QLineF> sortedLineList(lineList); + qSort(sortedLineList.begin(), sortedLineList.end(), lineXLessThan); + + QList<QLineF> lineWithTheSameX; + QListIterator<QLineF> sortedLineListIterator(sortedLineList); + while (sortedLineListIterator.hasNext()) { + QLineF line = sortedLineListIterator.next(); + lineWithTheSameX.append(line); + + if (sortedLineListIterator.hasNext()) { + QLineF nextLine = sortedLineListIterator.peekNext(); + if (!qFuzzyCompare(line.x1(), nextLine.x1())) { + mergedLineList.append(mergedVerticalLine(lineWithTheSameX)); + lineWithTheSameX.clear(); + } + } else { + mergedLineList.append(mergedVerticalLine(lineWithTheSameX)); + } + } + + return mergedLineList; +} + +QList<QGraphicsItem*> Snapper::generateSnappingLines(const QRectF &boundingRect, + QGraphicsItem *layerItem, + const QTransform &transform) +{ + QList<QRectF> boundingRectList; + boundingRectList.append(boundingRect); + + return generateSnappingLines(boundingRectList, layerItem, transform); +} + +static void alignLine(QLineF &line) +{ + line.setP1(QPointF(std::floor(line.p1().x()) + 0.5, + std::floor(line.p1().y()) + 0.5)); + line.setP2(QPointF(std::floor(line.p2().x()) + 0.5, + std::floor(line.p2().y()) + 0.5)); +} + +QList<QGraphicsItem*> Snapper::generateSnappingLines(const QList<QRectF> &boundingRectList, + QGraphicsItem *layerItem, + const QTransform &transform) +{ + QList<QGraphicsItem*> graphicsItemList; + QList<QLineF> lineList; + foreach(const QRectF &boundingRect, boundingRectList) { + QList<QRectF> snappedBoundingRectList; + lineList += mergedHorizontalLines(horizontalSnappedLines(boundingRect, &snappedBoundingRectList)); + lineList += mergedVerticalLines(verticalSnappedLines(boundingRect, &snappedBoundingRectList)); + +// snappedBoundingRectList.append(boundingRect); +// foreach(const QRectF &snappedBoundingRect, snappedBoundingRectList) { +// QPolygonF rect = transform.map(snappedBoundingRect); +// alignVertices(rect); +// QGraphicsPolygonItem * item = new QGraphicsPolygonItem(rect, layerItem); +// item->setZValue(20); + +// QColor brushColor(QApplication::palette().highlight().color()); +// QColor brushColor(Qt::gray); +// brushColor.setAlphaF(0.25); +// QBrush brush(brushColor); +// item->setBrush(brush); +// item->setPen(Qt::NoPen); +// graphicsItemList.append(item); +// } + } + + foreach(const QLineF &line, lineList) { + QLineF lineInTransformationSpace = transform.map(line); + alignLine(lineInTransformationSpace); + QGraphicsLineItem * lineItem = new QGraphicsLineItem(lineInTransformationSpace, layerItem); + lineItem->setZValue(40); + QPen linePen; +// linePen.setStyle(Qt::DashLine); + linePen.setColor("#5d2dd7"); + lineItem->setPen(linePen); + + graphicsItemList.append(lineItem); + } + + return graphicsItemList; +} + +} diff --git a/src/plugins/qmldesigner/components/formeditor/snapper.h b/src/plugins/qmldesigner/components/formeditor/snapper.h new file mode 100644 index 0000000000..a176b4e6e1 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/snapper.h @@ -0,0 +1,112 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef SNAPPER_H +#define SNAPPER_H + +#include "formeditoritem.h" + +class QLineF; + +namespace QmlDesigner { + + +class Snapper +{ +public: + Snapper(); + + void setContainerFormEditorItem(FormEditorItem *formEditorItem); + FormEditorItem *containerFormEditorItem() const; + + void setTransformtionSpaceFormEditorItem(FormEditorItem *formEditorItem); + FormEditorItem *transformtionSpaceFormEditorItem() const; + + double snappedVerticalOffset(const QRectF &boundingRect) const; + double snappedHorizontalOffset(const QRectF &boundingRect) const; + + double snapTopOffset(const QRectF &boundingRect) const; + double snapRightOffset(const QRectF &boundingRect) const; + double snapLeftOffset(const QRectF &boundingRect) const; + double snapBottomOffset(const QRectF &boundingRect) const; + + QList<QLineF> horizontalSnappedLines(const QRectF &boundingRect, QList<QRectF> *boundingRects = 0) const; + QList<QLineF> verticalSnappedLines(const QRectF &boundingRect, QList<QRectF> *boundingRects = 0) const; + + void setSnappingDistance(double snappingDistance); + double snappingDistance() const; + + void updateSnappingLines(const QList<FormEditorItem*> &exceptionList); + void updateSnappingLines(FormEditorItem* exceptionItem); + + QList<QGraphicsItem*> generateSnappingLines(const QList<QRectF> &boundingRectList, + QGraphicsItem *layerItem, + const QTransform &transform); + QList<QGraphicsItem*> generateSnappingLines(const QRectF &boundingRect, + QGraphicsItem *layerItem, + const QTransform &transform); +protected: + double snappedOffsetForLines(const SnapLineMap &snappingLineMap, + double value) const; + + double snappedOffsetForOffsetLines(const SnapLineMap &snappingOffsetMap, + Qt::Orientation orientation, + double value, + double lowerLimit, + double upperLimit) const; + + QList<QLineF> findSnappingLines(const SnapLineMap &snappingLineMap, + Qt::Orientation orientation, + double snapLine, + double lowerLimit, + double upperLimit, + QList<QRectF> *boundingRects = 0) const; + + QList<QLineF> findSnappingOffsetLines(const SnapLineMap &snappingOffsetMap, + Qt::Orientation orientation, + double snapLine, + double lowerLimit, + double upperLimit, + QList<QRectF> *boundingRects = 0) const; + + QLineF createSnapLine(Qt::Orientation orientation, + double snapLine, + double lowerEdge, + double upperEdge, + const QRectF &itemRect) const; + +// bool canSnap(QList<double> snappingLineList, double value) const; +private: + FormEditorItem *m_containerFormEditorItem; + FormEditorItem *m_transformtionSpaceFormEditorItem; + double m_snappingDistance; +}; + +} +#endif // SNAPPER_H diff --git a/src/plugins/qmldesigner/components/formeditor/snapping.png b/src/plugins/qmldesigner/components/formeditor/snapping.png Binary files differnew file mode 100644 index 0000000000..ceee8b94bb --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/snapping.png diff --git a/src/plugins/qmldesigner/components/formeditor/snappinglinecreator.cpp b/src/plugins/qmldesigner/components/formeditor/snappinglinecreator.cpp new file mode 100644 index 0000000000..7c3b9e36a3 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/snappinglinecreator.cpp @@ -0,0 +1,190 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "snappinglinecreator.h" + +#include <QGraphicsItem> +#include "onedimensionalcluster.h" +#include "formeditoritem.h" +#include "formeditorview.h" + +namespace QmlDesigner { + +SnappingLineCreator::SnappingLineCreator(FormEditorItem *formEditorItem) + : m_formEditorItem(formEditorItem), + m_topOffset(formEditorItem->formEditorView()->spacing()), + m_bottomOffset(formEditorItem->formEditorView()->spacing()), + m_leftOffset(formEditorItem->formEditorView()->spacing()), + m_rightOffset(formEditorItem->formEditorView()->spacing()), + m_topMargin(formEditorItem->formEditorView()->margins()), + m_bottomMargin(formEditorItem->formEditorView()->margins()), + m_leftMargin(formEditorItem->formEditorView()->margins()), + m_rightMargin(formEditorItem->formEditorView()->margins()) +{ + Q_ASSERT(m_formEditorItem); +} + +void SnappingLineCreator::clearLines() +{ + m_topLineMap.clear(); + m_bottomLineMap.clear(); + m_leftLineMap.clear(); + m_rightLineMap.clear(); + m_horizontalCenterLineMap.clear(); + m_verticalCenterLineMap.clear(); + + m_topOffsetMap.clear(); + m_bottomOffsetMap.clear(); + m_leftOffsetMap.clear(); + m_rightOffsetMap.clear(); + +} + +void SnappingLineCreator::addLines(const QRectF &rectInSceneSpace, FormEditorItem *item) +{ + m_topLineMap.insert(rectInSceneSpace.top(), qMakePair(rectInSceneSpace, item)); + m_bottomLineMap.insert(rectInSceneSpace.bottom(), qMakePair(rectInSceneSpace, item)); + m_leftLineMap.insert(rectInSceneSpace.left(), qMakePair(rectInSceneSpace, item)); + m_rightLineMap.insert(rectInSceneSpace.right(), qMakePair(rectInSceneSpace, item)); + QPointF centerPoint(rectInSceneSpace.center()); + m_horizontalCenterLineMap.insert(centerPoint.y(), qMakePair(rectInSceneSpace, item)); + m_verticalCenterLineMap.insert(centerPoint.x(), qMakePair(rectInSceneSpace, item)); +} + +void SnappingLineCreator::addOffsets(const QRectF &rectInSceneSpace, FormEditorItem *item) +{ + m_topOffsetMap.insert(rectInSceneSpace.top() - m_topOffset, qMakePair(rectInSceneSpace, item)); + m_bottomOffsetMap.insert(rectInSceneSpace.bottom() + m_bottomOffset, qMakePair(rectInSceneSpace, item)); + m_leftOffsetMap.insert(rectInSceneSpace.left() - m_leftOffset, qMakePair(rectInSceneSpace, item)); + m_rightOffsetMap.insert(rectInSceneSpace.right() + m_rightOffset, qMakePair(rectInSceneSpace, item)); +} + +void SnappingLineCreator::generateLines(const QList<FormEditorItem*> &exceptionList, + FormEditorItem *transformationSpaceItem) +{ + Q_ASSERT(transformationSpaceItem); + { + QRectF containerBoundingRectInTransformationSpace = m_formEditorItem->mapRectToItem(transformationSpaceItem, + m_formEditorItem->boundingRect()); + + addLines(containerBoundingRectInTransformationSpace, m_formEditorItem); + containerBoundingRectInTransformationSpace.adjust(m_leftMargin, m_topMargin, -m_rightMargin, -m_rightMargin); + addLines(containerBoundingRectInTransformationSpace, m_formEditorItem); + } + + foreach (FormEditorItem *item, m_formEditorItem->childFormEditorItems()) { + if (exceptionList.contains(item)) + continue; + QRectF boundingRectInContainerSpace; + + boundingRectInContainerSpace = item->mapRectToItem(transformationSpaceItem, item->boundingRect()); + + boundingRectInContainerSpace = boundingRectInContainerSpace.toRect(); // round to integer + + addLines(boundingRectInContainerSpace, item); + addOffsets(boundingRectInContainerSpace, item); + } +} + +void SnappingLineCreator::setMargins(double margin) +{ + m_topMargin = margin; + m_bottomMargin = margin; + m_leftMargin = margin; + m_rightMargin = margin; +} + +void SnappingLineCreator::setSpacing(double spacing) +{ + m_topOffset = spacing; + m_bottomOffset = spacing; + m_leftOffset = spacing; + m_rightOffset = spacing; +} + +void SnappingLineCreator::update(const QList<FormEditorItem*> &exceptionList, + FormEditorItem *transformationSpaceItem) +{ + clearLines(); + setMargins(m_formEditorItem->formEditorView()->margins()); + setSpacing(m_formEditorItem->formEditorView()->spacing()); + generateLines(exceptionList, transformationSpaceItem); +} + +SnapLineMap SnappingLineCreator::topLines() const +{ + return m_topLineMap; +} + +SnapLineMap SnappingLineCreator::bottomLines() const +{ + return m_bottomLineMap; +} + +SnapLineMap SnappingLineCreator::leftLines() const +{ + return m_leftLineMap; +} + +SnapLineMap SnappingLineCreator::rightLines() const +{ + return m_rightLineMap; +} + +SnapLineMap SnappingLineCreator::horizontalCenterLines() const +{ + return m_horizontalCenterLineMap; +} + +SnapLineMap SnappingLineCreator::verticalCenterLines() const +{ + return m_verticalCenterLineMap; +} + +SnapLineMap SnappingLineCreator::topOffsets() const +{ + return m_topOffsetMap; +} + +SnapLineMap SnappingLineCreator::bottomOffsets() const +{ + return m_bottomOffsetMap; +} + +SnapLineMap SnappingLineCreator::leftOffsets() const +{ + return m_leftOffsetMap; +} + +SnapLineMap SnappingLineCreator::rightOffsets() const +{ + return m_rightOffsetMap; +} + +} diff --git a/src/plugins/qmldesigner/components/formeditor/snappinglinecreator.h b/src/plugins/qmldesigner/components/formeditor/snappinglinecreator.h new file mode 100644 index 0000000000..7d8eb3b51b --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/snappinglinecreator.h @@ -0,0 +1,102 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef SNAPPINGLINECREATOR_H +#define SNAPPINGLINECREATOR_H + +#include "layeritem.h" +#include <QPair> + +namespace QmlDesigner { + +class FormEditorItem; + +typedef QMultiMap<double, QPair<QRectF, FormEditorItem*> > SnapLineMap; +typedef QMapIterator<double, QPair<QRectF, FormEditorItem*> > SnapLineMapIterator; + +class FormEditorItem; + +class SnappingLineCreator +{ +public: + SnappingLineCreator(FormEditorItem *formEditorItem); + + void update(const QList<FormEditorItem*> &exceptionList, + FormEditorItem *transformationSpaceItem); + + + SnapLineMap topLines() const; + SnapLineMap bottomLines() const; + SnapLineMap leftLines() const; + SnapLineMap rightLines() const; + SnapLineMap horizontalCenterLines() const; + SnapLineMap verticalCenterLines() const; + + SnapLineMap topOffsets() const; + SnapLineMap bottomOffsets() const; + SnapLineMap leftOffsets() const; + SnapLineMap rightOffsets() const; + + void setMargins(double margin); + void setSpacing(double spacing); + +protected: + void addLines(const QRectF &rectInSceneSpace, FormEditorItem *item); + void addOffsets(const QRectF &rectInSceneSpace, FormEditorItem *item); + + void clearLines(); + void generateLines(const QList<FormEditorItem*> &exceptionList, + FormEditorItem *transformationSpaceItem); + +private: + SnapLineMap m_topLineMap; + SnapLineMap m_bottomLineMap; + SnapLineMap m_leftLineMap; + SnapLineMap m_rightLineMap; + SnapLineMap m_horizontalCenterLineMap; + SnapLineMap m_verticalCenterLineMap; + + SnapLineMap m_topOffsetMap; + SnapLineMap m_bottomOffsetMap; + SnapLineMap m_leftOffsetMap; + SnapLineMap m_rightOffsetMap; + + FormEditorItem *m_formEditorItem; + double m_topOffset; + double m_bottomOffset; + double m_leftOffset; + double m_rightOffset; + double m_topMargin; + double m_bottomMargin; + double m_leftMargin; + double m_rightMargin; +}; + +} +#endif // SNAPPINGLINECREATOR_H diff --git a/src/plugins/qmldesigner/components/formeditor/toolbox.cpp b/src/plugins/qmldesigner/components/formeditor/toolbox.cpp new file mode 100644 index 0000000000..04d4486b78 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/toolbox.cpp @@ -0,0 +1,81 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "toolbox.h" + +#include <QToolBar> +#include <QHBoxLayout> +#include <QPainter> +#include <QtDebug> +#include <QFile> + +namespace QmlDesigner { + +ToolBox::ToolBox(QWidget *parentWidget) + : QWidget(parentWidget), + m_toolBar(new QToolBar("Sidebar", this)) +{ + QHBoxLayout *fillLayout = new QHBoxLayout(this); + fillLayout->setMargin(0); + setLayout(fillLayout); + //setContentsMargins(4, 12, 4, 4); + + m_toolBar->setFloatable(true); + m_toolBar->setMovable(true); + m_toolBar->setOrientation(Qt::Horizontal); + m_toolBar->setIconSize(QSize(24, 24)); + fillLayout->addWidget(m_toolBar); + + +// QPalette toolPalette(palette()); +// QColor newColor(palette().color(QPalette::Window)); +// newColor.setAlphaF(0.7); +// toolPalette.setColor(QPalette::Window, newColor); +// setPalette(toolPalette); +// setBackgroundRole(QPalette::Window); +// setAutoFillBackground(true); +// setAttribute(Qt::WA_NoSystemBackground, true); + +} + + + +void ToolBox::setActions(const QList<QAction*> &actions) +{ + m_toolBar->clear(); + m_toolBar->addActions(actions); + resize(sizeHint()); +} + +void ToolBox::addAction(QAction *action) +{ + m_toolBar->addAction(action); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/toolbox.h b/src/plugins/qmldesigner/components/formeditor/toolbox.h new file mode 100644 index 0000000000..98fed3a271 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/toolbox.h @@ -0,0 +1,52 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef TOOLBOX_H +#define TOOLBOX_H + +#include <QWidget> + +class QToolBar; + +namespace QmlDesigner { + +class ToolBox : public QWidget +{ +public: + ToolBox(QWidget *parentWidget); + void setActions(const QList<QAction*> &actions); + void addAction(QAction *action); + +private: + QToolBar *m_toolBar; +}; + +} // namespace QmlDesigner + +#endif // TOOLBOX_H diff --git a/src/plugins/qmldesigner/components/formeditor/transform.png b/src/plugins/qmldesigner/components/formeditor/transform.png Binary files differnew file mode 100644 index 0000000000..e9e7662b3a --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/transform.png diff --git a/src/plugins/qmldesigner/components/formeditor/zoomaction.cpp b/src/plugins/qmldesigner/components/formeditor/zoomaction.cpp new file mode 100644 index 0000000000..9a6560927f --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/zoomaction.cpp @@ -0,0 +1,116 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "zoomaction.h" + +#include <QComboBox> +#include <QLineEdit> +#include <QEvent> +#include <QCoreApplication> + +namespace QmlDesigner { + + +ZoomAction::ZoomAction(QObject *parent) + : QWidgetAction(parent), + m_zoomLevel(1.0), + m_currentComboBoxIndex(-1) +{ + +} + +double ZoomAction::zoomLevel() const +{ + return m_zoomLevel; +} + +void ZoomAction::zoomIn() +{ + if (m_currentComboBoxIndex > 0) + emit indexChanged(m_currentComboBoxIndex - 1); +} + +void ZoomAction::zoomOut() +{ + if (m_currentComboBoxIndex < (m_comboBoxModel->rowCount() - 1)) + emit indexChanged(m_currentComboBoxIndex + 1); +} + +void ZoomAction::setZoomLevel(double zoomLevel) +{ + if (zoomLevel < .1) { + m_zoomLevel = 0.1; + } else if (zoomLevel > 16.0) { + m_zoomLevel = 16.0; + } else { + m_zoomLevel = zoomLevel; + } + + emit zoomLevelChanged(m_zoomLevel); +} + + +QWidget *ZoomAction::createWidget(QWidget *parent) +{ + QComboBox *comboBox = new QComboBox(parent); + + if (m_comboBoxModel.isNull()) { + m_comboBoxModel = comboBox->model(); + comboBox->addItem("10 %", 0.1); + comboBox->addItem("25 %", 0.25); + comboBox->addItem("50 %", 0.5); + comboBox->addItem("100 %", 1.0); + comboBox->addItem("200 %", 2.0); + comboBox->addItem("400 %", 4.0); + comboBox->addItem("800 %", 8.0); + comboBox->addItem("1600 %", 16.0); + + } else { + comboBox->setModel(m_comboBoxModel.data()); + } + + comboBox->setCurrentIndex(3); + connect(comboBox, SIGNAL(currentIndexChanged(int)), SLOT(emitZoomLevelChanged(int))); + connect(this, SIGNAL(indexChanged(int)), comboBox, SLOT(setCurrentIndex(int))); + + return comboBox; +} + +void ZoomAction::emitZoomLevelChanged(int index) +{ + m_currentComboBoxIndex = index; + + if (index == -1) + return; + + QModelIndex modelIndex(m_comboBoxModel.data()->index(index, 0)); + setZoomLevel(m_comboBoxModel.data()->data(modelIndex, Qt::UserRole).toDouble()); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/zoomaction.h b/src/plugins/qmldesigner/components/formeditor/zoomaction.h new file mode 100644 index 0000000000..02ceb9acc0 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/zoomaction.h @@ -0,0 +1,68 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef ZOOMACTION_H +#define ZOOMACTION_H + +#include <QWidgetAction> + +class QAbstractItemModel; + +namespace QmlDesigner { + +class ZoomAction : public QWidgetAction +{ + Q_OBJECT + +public: + ZoomAction(QObject *parent); + + double zoomLevel() const; + + void zoomIn(); + void zoomOut(); + +protected: + QWidget *createWidget(QWidget *parent); + void setZoomLevel(double zoomLevel); +signals: + void zoomLevelChanged(double zoom); + void indexChanged(int); +private slots: + void emitZoomLevelChanged(int index); + +private: + QWeakPointer<QAbstractItemModel> m_comboBoxModel; + double m_zoomLevel; + int m_currentComboBoxIndex; +}; + +} // namespace QmlDesigner + +#endif // ZOOMACTION_H |