QmlDesigner: Rotation Tool

- Added Rotation Tool to Form Editor
 - Rotation Tool is activated on items corners
 - Supports alt and shift modifiers
 - Works with MCU projects
 - Uses new rotation icon

Task: QDS-2881

Change-Id: I9905968b7ac31d008184e343294fbd33cdb45c1c
Reviewed-by: Marco Bubke <marco.bubke@qt.io>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Aleksei German
2020-10-22 17:13:58 +02:00
parent 1dd7595e60
commit 3d78fef4ef
24 changed files with 1462 additions and 16 deletions

View File

@@ -265,6 +265,11 @@ extend_qtc_plugin(QmlDesigner
resizeindicator.cpp resizeindicator.h
resizemanipulator.cpp resizemanipulator.h
resizetool.cpp resizetool.h
rotationtool.cpp rotationtool.h
rotationindicator.cpp rotationindicator.h
rotationcontroller.cpp rotationcontroller.h
rotationhandleitem.cpp rotationhandleitem.h
rotationmanipulator.cpp rotationmanipulator.h
rubberbandselectionmanipulator.cpp rubberbandselectionmanipulator.h
scaleitem.cpp scaleitem.h
scalemanipulator.cpp scalemanipulator.h

View File

@@ -24,6 +24,11 @@ SOURCES += formeditoritem.cpp \
scaleitem.cpp \
resizecontroller.cpp \
resizehandleitem.cpp \
rotationtool.cpp \
rotationindicator.cpp \
rotationcontroller.cpp \
rotationhandleitem.cpp \
rotationmanipulator.cpp \
dragtool.cpp \
toolbox.cpp \
formeditorgraphicsview.cpp \
@@ -64,6 +69,11 @@ HEADERS += formeditorscene.h \
scaleitem.h \
resizecontroller.h \
resizehandleitem.h \
rotationtool.h \
rotationindicator.h \
rotationcontroller.h \
rotationhandleitem.h \
rotationmanipulator.h \
dragtool.h \
toolbox.h \
formeditorgraphicsview.h \

View File

@@ -26,6 +26,7 @@
#include "formeditorview.h"
#include "nodeinstanceview.h"
#include "selectiontool.h"
#include "rotationtool.h"
#include "movetool.h"
#include "resizetool.h"
#include "dragtool.h"
@@ -207,6 +208,7 @@ void FormEditorView::createFormEditorWidget()
m_moveTool = std::make_unique<MoveTool>(this);
m_selectionTool = std::make_unique<SelectionTool>(this);
m_rotationTool = std::make_unique<RotationTool>(this);
m_resizeTool = std::make_unique<ResizeTool>(this);
m_dragTool = std::make_unique<DragTool>(this);
@@ -248,6 +250,7 @@ void FormEditorView::cleanupToolsAndScene()
{
m_currentTool->setItems(QList<FormEditorItem *>());
m_selectionTool->clear();
m_rotationTool->clear();
m_moveTool->clear();
m_resizeTool->clear();
m_dragTool->clear();
@@ -548,6 +551,12 @@ void FormEditorView::resetToSelectionTool()
changeCurrentToolTo(m_selectionTool.get());
}
void FormEditorView::changeToRotationTool() {
if (m_currentTool == m_rotationTool.get())
return;
changeCurrentToolTo(m_rotationTool.get());
}
void FormEditorView::changeToResizeTool()
{
if (m_currentTool == m_resizeTool.get())
@@ -559,6 +568,7 @@ void FormEditorView::changeToTransformTools()
{
if (m_currentTool == m_moveTool.get() ||
m_currentTool == m_resizeTool.get() ||
m_currentTool == m_rotationTool.get() ||
m_currentTool == m_selectionTool.get())
return;
changeToSelectionTool();
@@ -854,6 +864,7 @@ void FormEditorView::reset()
void FormEditorView::delayedReset()
{
m_selectionTool->clear();
m_rotationTool->clear();
m_moveTool->clear();
m_resizeTool->clear();
m_dragTool->clear();

View File

@@ -47,6 +47,7 @@ class AbstractFormEditorTool;
class AbstractCustomTool;
class MoveTool;
class SelectionTool;
class RotationTool;
class ResizeTool;
class DragTool;
class ItemLibraryEntry;
@@ -104,6 +105,7 @@ public:
void changeToSelectionTool();
void changeToSelectionTool(QGraphicsSceneMouseEvent *event);
void resetToSelectionTool();
void changeToRotationTool();
void changeToResizeTool();
void changeToTransformTools();
void changeToCustomTool();
@@ -152,6 +154,7 @@ private:
QList<AbstractCustomTool*> m_customToolList;
std::unique_ptr<MoveTool> m_moveTool;
std::unique_ptr<SelectionTool> m_selectionTool;
std::unique_ptr<RotationTool> m_rotationTool;
std::unique_ptr<ResizeTool> m_resizeTool;
std::unique_ptr<DragTool> m_dragTool;
AbstractFormEditorTool *m_currentTool = nullptr;

View File

@@ -31,6 +31,7 @@
#include "formeditorgraphicsview.h"
#include "resizehandleitem.h"
#include "rotationhandleitem.h"
#include <utils/algorithm.h>
@@ -46,6 +47,7 @@ MoveTool::MoveTool(FormEditorView *editorView)
m_moveManipulator(editorView->scene()->manipulatorLayerItem(), editorView),
m_selectionIndicator(editorView->scene()->manipulatorLayerItem()),
m_resizeIndicator(editorView->scene()->manipulatorLayerItem()),
m_rotationIndicator(editorView->scene()->manipulatorLayerItem()),
m_anchorIndicator(editorView->scene()->manipulatorLayerItem()),
m_bindingIndicator(editorView->scene()->manipulatorLayerItem()),
m_contentNotEditableIndicator(editorView->scene()->manipulatorLayerItem())
@@ -61,6 +63,7 @@ void MoveTool::clear()
m_movingItems.clear();
m_selectionIndicator.clear();
m_resizeIndicator.clear();
m_rotationIndicator.clear();
m_anchorIndicator.clear();
m_bindingIndicator.clear();
m_contentNotEditableIndicator.clear();
@@ -100,6 +103,7 @@ void MoveTool::mouseMoveEvent(const QList<QGraphicsItem*> &itemList,
m_selectionIndicator.hide();
m_resizeIndicator.hide();
m_rotationIndicator.hide();
m_anchorIndicator.hide();
m_bindingIndicator.hide();
@@ -135,6 +139,12 @@ void MoveTool::hoverMoveEvent(const QList<QGraphicsItem*> &itemList,
return;
}
RotationHandleItem* rotationHandle = RotationHandleItem::fromGraphicsItem(itemList.constFirst());
if (rotationHandle) {
view()->changeToRotationTool();
return;
}
if (view()->hasSingleSelectedModelNode() && selectedItemCursorInMovableArea(event->scenePos()))
return;
@@ -182,6 +192,7 @@ void MoveTool::keyPressEvent(QKeyEvent *event)
m_moveManipulator.setItems(movableItems);
// m_selectionIndicator.hide();
m_resizeIndicator.hide();
m_rotationIndicator.hide();
m_anchorIndicator.hide();
m_bindingIndicator.hide();
m_moveManipulator.beginRewriterTransaction();
@@ -215,6 +226,7 @@ void MoveTool::keyReleaseEvent(QKeyEvent *keyEvent)
m_moveManipulator.clear();
// m_selectionIndicator.show();
m_resizeIndicator.show();
m_rotationIndicator.show();
m_anchorIndicator.show();
m_bindingIndicator.show();
}
@@ -241,6 +253,7 @@ void MoveTool::mouseReleaseEvent(const QList<QGraphicsItem*> &itemList,
m_selectionIndicator.show();
m_resizeIndicator.show();
m_rotationIndicator.show();
m_anchorIndicator.show();
m_bindingIndicator.show();
m_movingItems.clear();
@@ -266,6 +279,7 @@ void MoveTool::selectedItemsChanged(const QList<FormEditorItem*> &itemList)
{
m_selectionIndicator.setItems(movingItems(itemList));
m_resizeIndicator.setItems(itemList);
m_rotationIndicator.setItems(itemList);
m_anchorIndicator.setItems(itemList);
m_bindingIndicator.setItems(itemList);
updateMoveManipulator();
@@ -386,6 +400,7 @@ void MoveTool::formEditorItemsChanged(const QList<FormEditorItem*> &itemList)
m_selectionIndicator.updateItems(selectedItemList);
m_resizeIndicator.updateItems(selectedItemList);
m_rotationIndicator.updateItems(selectedItemList);
m_anchorIndicator.updateItems(selectedItemList);
m_bindingIndicator.updateItems(selectedItemList);
m_contentNotEditableIndicator.updateItems(selectedItemList);

View File

@@ -28,6 +28,7 @@
#include "movemanipulator.h"
#include "selectionindicator.h"
#include "resizeindicator.h"
#include "rotationindicator.h"
#include "anchorindicator.h"
#include "bindingindicator.h"
#include "contentnoteditableindicator.h"
@@ -84,6 +85,7 @@ private:
MoveManipulator m_moveManipulator;
SelectionIndicator m_selectionIndicator;
ResizeIndicator m_resizeIndicator;
RotationIndicator m_rotationIndicator;
AnchorIndicator m_anchorIndicator;
BindingIndicator m_bindingIndicator;
ContentNotEditableIndicator m_contentNotEditableIndicator;

View File

@@ -57,7 +57,7 @@ void ResizeIndicator::clear()
m_itemControllerHash.clear();
}
bool itemIsResizable(const QmlItemNode &qmlItemNode)
static bool itemIsResizable(const QmlItemNode &qmlItemNode)
{
return qmlItemNode.isValid()
&& qmlItemNode.instanceIsResizable()

View File

@@ -38,11 +38,12 @@
namespace QmlDesigner {
ResizeTool::ResizeTool(FormEditorView *editorView)
: AbstractFormEditorTool(editorView),
m_selectionIndicator(editorView->scene()->manipulatorLayerItem()),
m_resizeIndicator(editorView->scene()->manipulatorLayerItem()),
m_anchorIndicator(editorView->scene()->manipulatorLayerItem()),
m_resizeManipulator(editorView->scene()->manipulatorLayerItem(), editorView)
: AbstractFormEditorTool(editorView)
, m_selectionIndicator(editorView->scene()->manipulatorLayerItem())
, m_resizeIndicator(editorView->scene()->manipulatorLayerItem())
, m_anchorIndicator(editorView->scene()->manipulatorLayerItem())
, m_rotationIndicator(editorView->scene()->manipulatorLayerItem())
, m_resizeManipulator(editorView->scene()->manipulatorLayerItem(), editorView)
{
}
@@ -61,6 +62,7 @@ void ResizeTool::mousePressEvent(const QList<QGraphicsItem*> &itemList,
m_resizeManipulator.begin(event->scenePos());
m_resizeIndicator.hide();
m_anchorIndicator.hide();
m_rotationIndicator.hide();
}
}
@@ -113,6 +115,7 @@ void ResizeTool::mouseReleaseEvent(const QList<QGraphicsItem*> &itemList,
m_selectionIndicator.show();
m_resizeIndicator.show();
m_anchorIndicator.show();
m_rotationIndicator.show();
m_resizeManipulator.end(generateUseSnapping(event->modifiers()));
}
@@ -171,6 +174,7 @@ void ResizeTool::selectedItemsChanged(const QList<FormEditorItem*> & /*itemList*
m_selectionIndicator.setItems(items());
m_resizeIndicator.setItems(items());
m_anchorIndicator.setItems(items());
m_rotationIndicator.setItems(items());
}
void ResizeTool::clear()
@@ -178,6 +182,7 @@ void ResizeTool::clear()
m_selectionIndicator.clear();
m_resizeIndicator.clear();
m_anchorIndicator.clear();
m_rotationIndicator.clear();
m_resizeManipulator.clear();
}
@@ -188,6 +193,7 @@ void ResizeTool::formEditorItemsChanged(const QList<FormEditorItem*> &itemList)
m_selectionIndicator.updateItems(selectedItemList);
m_resizeIndicator.updateItems(selectedItemList);
m_anchorIndicator.updateItems(selectedItemList);
m_rotationIndicator.updateItems(selectedItemList);
}
void ResizeTool::instancesCompleted(const QList<FormEditorItem*> &/*itemList*/)

View File

@@ -28,6 +28,7 @@
#include "selectionindicator.h"
#include "resizeindicator.h"
#include "anchorindicator.h"
#include "rotationindicator.h"
#include "resizemanipulator.h"
namespace QmlDesigner {
@@ -69,6 +70,7 @@ private:
SelectionIndicator m_selectionIndicator;
ResizeIndicator m_resizeIndicator;
AnchorIndicator m_anchorIndicator;
RotationIndicator m_rotationIndicator;
ResizeManipulator m_resizeManipulator;
};

View File

@@ -0,0 +1,244 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "rotationcontroller.h"
#include "formeditoritem.h"
#include "layeritem.h"
#include <rotationhandleitem.h>
#include <QCursor>
#include <QGraphicsScene>
#include <utils/stylehelper.h>
#include <theme.h>
namespace QmlDesigner {
class RotationControllerData
{
public:
RotationControllerData(LayerItem *layerItem,
FormEditorItem *formEditorItem);
RotationControllerData(const RotationControllerData &other);
~RotationControllerData();
QPointer<LayerItem> layerItem;
FormEditorItem *formEditorItem = nullptr;
QSharedPointer<RotationHandleItem> topLeftItem;
QSharedPointer<RotationHandleItem> topRightItem;
QSharedPointer<RotationHandleItem> bottomLeftItem;
QSharedPointer<RotationHandleItem> bottomRightItem;
};
RotationControllerData::RotationControllerData(LayerItem *layerItem, FormEditorItem *formEditorItem)
: layerItem(layerItem)
, formEditorItem(formEditorItem)
{
}
RotationControllerData::RotationControllerData(const RotationControllerData &other) = default;
RotationControllerData::~RotationControllerData()
{
if (layerItem) {
QGraphicsScene *scene = layerItem->scene();
scene->removeItem(topLeftItem.data());
scene->removeItem(topRightItem.data());
scene->removeItem(bottomLeftItem.data());
scene->removeItem(bottomRightItem.data());
}
}
RotationController::RotationController()
: m_data(new RotationControllerData(nullptr, nullptr))
{
}
RotationController::RotationController(const QSharedPointer<RotationControllerData> &data)
: m_data(data)
{
}
RotationController::RotationController(LayerItem *layerItem, FormEditorItem *formEditorItem)
: m_data(new RotationControllerData(layerItem, formEditorItem))
{
QCursor rotationCursor = getRotationCursor();
m_data->topLeftItem = QSharedPointer<RotationHandleItem>(new RotationHandleItem(layerItem, *this));
m_data->topLeftItem->setZValue(302);
m_data->topLeftItem->setCursor(rotationCursor);
m_data->topRightItem = QSharedPointer<RotationHandleItem>(new RotationHandleItem(layerItem, *this));
m_data->topRightItem->setZValue(301);
m_data->topRightItem->setCursor(rotationCursor);
m_data->bottomLeftItem = QSharedPointer<RotationHandleItem>(new RotationHandleItem(layerItem, *this));
m_data->bottomLeftItem->setZValue(301);
m_data->bottomLeftItem->setCursor(rotationCursor);
m_data->bottomRightItem = QSharedPointer<RotationHandleItem>(new RotationHandleItem(layerItem, *this));
m_data->bottomRightItem->setZValue(305);
m_data->bottomRightItem->setCursor(rotationCursor);
updatePosition();
}
RotationController::RotationController(const RotationController &other) = default;
RotationController::RotationController(const WeakRotationController &rotationController)
: m_data(rotationController.m_data.toStrongRef())
{
}
RotationController::~RotationController() = default;
RotationController &RotationController::operator =(const RotationController &other)
{
if (this != &other)
m_data = other.m_data;
return *this;
}
bool RotationController::isValid() const
{
return m_data->formEditorItem && m_data->formEditorItem->qmlItemNode().isValid();
}
void RotationController::show()
{
m_data->topLeftItem->show();
m_data->topRightItem->show();
m_data->bottomLeftItem->show();
m_data->bottomRightItem->show();
}
void RotationController::hide()
{
m_data->topLeftItem->hide();
m_data->topRightItem->hide();
m_data->bottomLeftItem->hide();
m_data->bottomRightItem->hide();
}
void RotationController::updatePosition()
{
if (isValid()) {
QRectF boundingRect = m_data->formEditorItem->qmlItemNode().instanceBoundingRect();
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()));
const qreal rotation = m_data->formEditorItem->qmlItemNode().rotation();
m_data->topRightItem->setHandlePosition(topRightPointInLayerSpace, boundingRect.topRight(), rotation);
m_data->topLeftItem->setHandlePosition(topLeftPointInLayerSpace, boundingRect.topLeft(), rotation);
m_data->bottomLeftItem->setHandlePosition(bottomLeftPointInLayerSpace, boundingRect.bottomLeft(), rotation);
m_data->bottomRightItem->setHandlePosition(bottomRightPointInLayerSpace, boundingRect.bottomRight(), rotation);
}
}
FormEditorItem* RotationController::formEditorItem() const
{
return m_data->formEditorItem;
}
bool RotationController::isTopLeftHandle(const RotationHandleItem *handle) const
{
return handle == m_data->topLeftItem;
}
bool RotationController::isTopRightHandle(const RotationHandleItem *handle) const
{
return handle == m_data->topRightItem;
}
bool RotationController::isBottomLeftHandle(const RotationHandleItem *handle) const
{
return handle == m_data->bottomLeftItem;
}
bool RotationController::isBottomRightHandle(const RotationHandleItem *handle) const
{
return handle == m_data->bottomRightItem;
}
QCursor RotationController::getRotationCursor() const
{
const QString fontName = "qtds_propertyIconFont.ttf";
const int cursorSize = 32; //32 is cursor recommended size
QIcon rotationIcon = Utils::StyleHelper::getIconFromIconFont(
fontName,
Theme::getIconUnicode(Theme::rotation),
cursorSize, cursorSize,
Qt::white);
return QCursor(rotationIcon.pixmap(cursorSize, cursorSize));
}
WeakRotationController RotationController::toWeakRotationController() const
{
return WeakRotationController(*this);
}
WeakRotationController::WeakRotationController() = default;
WeakRotationController::WeakRotationController(const WeakRotationController &rotationController) = default;
WeakRotationController::WeakRotationController(const RotationController &rotationController)
: m_data(rotationController.m_data.toWeakRef())
{
}
WeakRotationController::~WeakRotationController() = default;
WeakRotationController &WeakRotationController::operator =(const WeakRotationController &other)
{
if (m_data != other.m_data)
m_data = other.m_data;
return *this;
}
RotationController WeakRotationController::toRotationController() const
{
return RotationController(*this);
}
}

View File

@@ -0,0 +1,92 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QWeakPointer>
#include <QSharedPointer>
namespace QmlDesigner {
class FormEditorItem;
class LayerItem;
class RotationHandleItem;
class RotationControllerData;
class WeakRotationController;
class RotationController
{
friend class WeakRotationController;
public:
RotationController();
RotationController(LayerItem *layerItem, FormEditorItem *formEditorItem);
RotationController(const RotationController &rotationController);
RotationController(const WeakRotationController &rotationController);
~RotationController();
RotationController& operator=(const RotationController &other);
void show();
void hide();
void updatePosition();
bool isValid() const;
FormEditorItem *formEditorItem() const;
bool isTopLeftHandle(const RotationHandleItem *handle) const;
bool isTopRightHandle(const RotationHandleItem *handle) const;
bool isBottomLeftHandle(const RotationHandleItem *handle) const;
bool isBottomRightHandle(const RotationHandleItem *handle) const;
WeakRotationController toWeakRotationController() const;
private:
RotationController(const QSharedPointer<RotationControllerData> &data);
QCursor getRotationCursor() const;
private:
QSharedPointer<RotationControllerData> m_data;
};
class WeakRotationController
{
friend class RotationController;
public:
WeakRotationController();
WeakRotationController(const WeakRotationController &rotationController);
WeakRotationController(const RotationController &rotationController);
~WeakRotationController();
WeakRotationController& operator=(const WeakRotationController &other);
RotationController toRotationController() const;
private: // variables
QWeakPointer<RotationControllerData> m_data;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,119 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "rotationhandleitem.h"
#include <QPainter>
#include <QDebug>
namespace QmlDesigner {
RotationHandleItem::RotationHandleItem(QGraphicsItem *parent, const RotationController &rotationController)
: QGraphicsItem(parent)
, m_weakRotationController(rotationController.toWeakRotationController())
{
setFlag(QGraphicsItem::ItemIsMovable, true);
setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
setAcceptedMouseButtons(Qt::NoButton);
}
RotationHandleItem::~RotationHandleItem() = default;
void RotationHandleItem::setHandlePosition(const QPointF & globalPosition, const QPointF & itemSpacePosition, const qreal rotation)
{
m_itemSpacePosition = itemSpacePosition;
setRotation(rotation);
setPos(globalPosition);
}
QRectF RotationHandleItem::boundingRect() const
{
QRectF rectangle;
if (isTopLeftHandle()) {
rectangle = { -30., -30., 27., 27.};
}
else if (isTopRightHandle()) {
rectangle = { 3., -30., 27., 27.};
}
else if (isBottomLeftHandle()) {
rectangle = { -30., 3., 27., 27.};
}
else if (isBottomRightHandle()) {
rectangle = { 3., 3., 27., 27.};
}
return rectangle;
}
void RotationHandleItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /* option */, QWidget * /* widget */)
{
painter->save();
QPen pen = painter->pen();
pen.setWidth(1);
pen.setCosmetic(true);
painter->setPen(pen);
painter->setRenderHint(QPainter::Antialiasing, false);
painter->setBrush(QColor(255, 255, 255));
painter->drawRect(QRectF(-3., -3., 5., 5.));
painter->restore();
}
RotationController RotationHandleItem::rotationController() const
{
return RotationController(m_weakRotationController.toRotationController());
}
RotationHandleItem* RotationHandleItem::fromGraphicsItem(QGraphicsItem *item)
{
return qgraphicsitem_cast<RotationHandleItem*>(item);
}
bool RotationHandleItem::isTopLeftHandle() const
{
return rotationController().isTopLeftHandle(this);
}
bool RotationHandleItem::isTopRightHandle() const
{
return rotationController().isTopRightHandle(this);
}
bool RotationHandleItem::isBottomLeftHandle() const
{
return rotationController().isBottomLeftHandle(this);
}
bool RotationHandleItem::isBottomRightHandle() const
{
return rotationController().isBottomRightHandle(this);
}
QPointF RotationHandleItem::itemSpacePosition() const
{
return m_itemSpacePosition;
}
}

View File

@@ -0,0 +1,72 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "rotationcontroller.h"
#include <qmldesignercorelib_global.h>
#include <QGraphicsItem>
namespace QmlDesigner {
class QMLDESIGNERCORE_EXPORT RotationHandleItem : public QGraphicsItem
{
public:
enum
{
Type = 0xEBEB
};
RotationHandleItem(QGraphicsItem *parent, const RotationController &rotationController);
~RotationHandleItem() override;
void setHandlePosition(const QPointF & globalPosition, const QPointF & itemSpacePosition, const qreal rotation);
int type() const override;
QRectF boundingRect() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
RotationController rotationController() const;
static RotationHandleItem* fromGraphicsItem(QGraphicsItem *item);
bool isTopLeftHandle() const;
bool isTopRightHandle() const;
bool isBottomLeftHandle() const;
bool isBottomRightHandle() const;
QPointF itemSpacePosition() const;
private:
WeakRotationController m_weakRotationController;
QPointF m_itemSpacePosition;
};
inline int RotationHandleItem::type() const
{
return Type;
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,98 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "rotationindicator.h"
#include "formeditoritem.h"
namespace QmlDesigner {
RotationIndicator::RotationIndicator(LayerItem *layerItem)
: m_layerItem(layerItem)
{
Q_ASSERT(layerItem);
}
RotationIndicator::~RotationIndicator()
{
m_itemControllerHash.clear();
}
void RotationIndicator::show()
{
for (RotationController controller : m_itemControllerHash)
controller.show();
}
void RotationIndicator::hide()
{
for (RotationController controller : m_itemControllerHash)
controller.hide();
}
void RotationIndicator::clear()
{
m_itemControllerHash.clear();
}
static bool itemIsRotatable(const QmlItemNode &qmlItemNode)
{
return qmlItemNode.isValid()
&& qmlItemNode.instanceIsResizable()
&& qmlItemNode.modelIsMovable()
&& qmlItemNode.modelIsRotatable()
&& !qmlItemNode.instanceIsInLayoutable();
}
void RotationIndicator::setItems(const QList<FormEditorItem*> &itemList)
{
clear();
for (FormEditorItem *item : itemList) {
if (item && itemIsRotatable(item->qmlItemNode())) {
RotationController controller(m_layerItem, item);
m_itemControllerHash.insert(item, controller);
}
}
}
void RotationIndicator::updateItems(const QList<FormEditorItem*> &itemList)
{
for (FormEditorItem *item : itemList) {
if (m_itemControllerHash.contains(item)) {
if (!item || !itemIsRotatable(item->qmlItemNode())) {
m_itemControllerHash.take(item);
} else {
RotationController controller(m_itemControllerHash.value(item));
controller.updatePosition();
}
} else if (item && itemIsRotatable(item->qmlItemNode())) {
RotationController controller(m_layerItem, item);
m_itemControllerHash.insert(item, controller);
}
}
}
}

View File

@@ -0,0 +1,62 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "rotationcontroller.h"
#include <QHash>
#include <QPair>
namespace QmlDesigner {
class FormEditorItem;
class LayerItem;
class RotationIndicator
{
public:
enum Orientation {
Top = 1,
Right = 2,
Bottom = 4,
Left = 8
};
explicit RotationIndicator(LayerItem *layerItem);
~RotationIndicator();
void show();
void hide();
void clear();
void setItems(const QList<FormEditorItem*> &itemList);
void updateItems(const QList<FormEditorItem*> &itemList);
private:
QHash<FormEditorItem*, RotationController> m_itemControllerHash;
LayerItem *m_layerItem;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,260 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "rotationmanipulator.h"
#include "formeditoritem.h"
#include "formeditorscene.h"
#include "qmlanchors.h"
#include <QDebug>
#include <QtMath>
#include "enumeration.h"
#include "mathutils.h"
#include <limits>
namespace QmlDesigner {
RotationManipulator::RotationManipulator(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)
{
}
RotationManipulator::~RotationManipulator()
{
deleteSnapLines();
}
void RotationManipulator::setHandle(RotationHandleItem *rotationHandle)
{
Q_ASSERT(rotationHandle);
m_rotationHandle = rotationHandle;
m_rotationController = rotationHandle->rotationController();
Q_ASSERT(m_rotationController.isValid());
}
void RotationManipulator::removeHandle()
{
m_rotationController = RotationController();
m_rotationHandle = nullptr;
}
void RotationManipulator::begin(const QPointF &/*beginPoint*/)
{
if (m_rotationController.isValid()) {
m_isActive = true;
m_beginBoundingRect = m_rotationController.formEditorItem()->qmlItemNode().instanceBoundingRect();
m_beginFromContentItemToSceneTransform = m_rotationController.formEditorItem()->instanceSceneContentItemTransform();
m_beginFromSceneToContentItemTransform = m_beginFromContentItemToSceneTransform.inverted();
m_beginFromItemToSceneTransform = m_rotationController.formEditorItem()->instanceSceneTransform();
m_beginToParentTransform = m_rotationController.formEditorItem()->qmlItemNode().instanceTransform();
m_rewriterTransaction = m_view->beginRewriterTransaction(QByteArrayLiteral("RotationManipulator::begin"));
m_rewriterTransaction.ignoreSemanticChecks();
m_beginBottomRightPoint = m_beginToParentTransform.map(m_rotationController.formEditorItem()->qmlItemNode().instanceBoundingRect().bottomRight());
QmlAnchors anchors(m_rotationController.formEditorItem()->qmlItemNode().anchors());
m_beginTopMargin = anchors.instanceMargin(AnchorLineTop);
m_beginLeftMargin = anchors.instanceMargin(AnchorLineLeft);
m_beginRightMargin = anchors.instanceMargin(AnchorLineRight);
m_beginBottomMargin = anchors.instanceMargin(AnchorLineBottom);
m_beginRotation = m_rotationController.formEditorItem()->qmlItemNode().rotation();
deleteSnapLines();
}
}
void RotationManipulator::update(const QPointF& updatePoint, Qt::KeyboardModifiers keyMods)
{
if (m_rotationController.isValid()) {
FormEditorItem *formEditorItem = m_rotationController.formEditorItem();
const bool degreeStep5 = keyMods.testFlag(Qt::ShiftModifier);
const bool degreeStep45 = keyMods.testFlag(Qt::AltModifier);
QPointF updatePointInLocalSpace = m_beginFromSceneToContentItemTransform.map(updatePoint);
QRectF boundingRect(m_beginBoundingRect);
QPointF transformOrigin;
QVariant transformOriginVar = formEditorItem->qmlItemNode().transformOrigin();
if (transformOriginVar.isValid()) {
QmlDesigner::Enumeration a = transformOriginVar.value<QmlDesigner::Enumeration>();
const QString originStr = a.nameToString();
if (originStr == "TopLeft") {
transformOrigin = boundingRect.topLeft();
}
else if (originStr == "Top") {
transformOrigin.setX(boundingRect.center().x());
transformOrigin.setY(boundingRect.top());
}
else if (originStr == "TopRight") {
transformOrigin = boundingRect.topRight();
}
else if (originStr == "Right") {
transformOrigin.setX(boundingRect.right());
transformOrigin.setY(boundingRect.center().y());
}
else if (originStr == "BottomRight") {
transformOrigin = boundingRect.bottomRight();
}
else if (originStr == "Bottom") {
transformOrigin.setX(boundingRect.center().x());
transformOrigin.setY(boundingRect.bottom());
}
else if (originStr == "BottomLeft") {
transformOrigin = boundingRect.bottomLeft();
}
else if (originStr == "Left") {
transformOrigin.setX(boundingRect.left());
transformOrigin.setY(boundingRect.center().y());
}
else {
//center and anything else
transformOrigin = boundingRect.center();
}
}
else {
transformOrigin = boundingRect.center();
}
auto angleCalc = [](const QPointF &origin, const QPointF &position){
const qreal deltaX = origin.x() - position.x();
const qreal deltaY = origin.y() - position.y();
return qRadiansToDegrees(qAtan2(deltaY, deltaX));
};
auto snapCalc = [](const qreal angle, const qreal snap){
return qRound(angle/snap)*snap;
};
auto resultCalc = [&](qreal cursorAngle, qreal handleAngle) {
qreal result = 0.0;
const qreal rotateBy = cursorAngle - handleAngle;
if (degreeStep45)
result = snapCalc(rotateBy, 45.0);
else if (degreeStep5)
result = snapCalc(rotateBy, 5.0);
else
result = rotateBy;
while (result > 360.)
result -= 360.;
while (result < -360.)
result += 360.;
return result;
};
const qreal cursorAngle = angleCalc(transformOrigin, updatePointInLocalSpace);
const QPointF topLeftHandle = boundingRect.topLeft();
const QPointF topRightHandle = boundingRect.topRight();
const QPointF bottomRightHandle = boundingRect.bottomRight();
const QPointF bottomLeftHandle = boundingRect.bottomLeft();
if (m_rotationHandle->isTopLeftHandle()) {
//we need to change origin coords, otherwise item will rotate unpredictably:
if (transformOrigin == topLeftHandle)
transformOrigin = boundingRect.center();
const qreal handleAngle = angleCalc(transformOrigin, topLeftHandle);
formEditorItem->qmlItemNode().setRotation(resultCalc(cursorAngle + m_beginRotation, handleAngle));
}
else if (m_rotationHandle->isTopRightHandle()) {
if (transformOrigin == topRightHandle)
transformOrigin = boundingRect.center();
const qreal handleAngle = angleCalc(transformOrigin, topRightHandle);
formEditorItem->qmlItemNode().setRotation(resultCalc(cursorAngle + m_beginRotation, handleAngle));
}
else if (m_rotationHandle->isBottomRightHandle()) {
if (transformOrigin == bottomRightHandle)
transformOrigin = boundingRect.center();
const qreal handleAngle = angleCalc(transformOrigin, bottomRightHandle);
formEditorItem->qmlItemNode().setRotation(resultCalc(cursorAngle + m_beginRotation, handleAngle));
}
else if (m_rotationHandle->isBottomLeftHandle()) {
if (transformOrigin == bottomLeftHandle)
transformOrigin = boundingRect.center();
const qreal handleAngle = angleCalc(transformOrigin, bottomLeftHandle);
formEditorItem->qmlItemNode().setRotation(resultCalc(cursorAngle + m_beginRotation, handleAngle));
}
}
}
void RotationManipulator::end()
{
m_isActive = false;
m_rewriterTransaction.commit();
clear();
removeHandle();
}
void RotationManipulator::deleteSnapLines()
{
if (m_layerItem) {
foreach (QGraphicsItem *item, m_graphicsLineList) {
m_layerItem->scene()->removeItem(item);
delete item;
}
}
m_graphicsLineList.clear();
m_view->scene()->update();
}
RotationHandleItem *RotationManipulator::rotationHandle()
{
return m_rotationHandle;
}
void RotationManipulator::clear()
{
m_rewriterTransaction.commit();
deleteSnapLines();
m_beginBoundingRect = QRectF();
m_beginFromSceneToContentItemTransform = QTransform();
m_beginFromContentItemToSceneTransform = QTransform();
m_beginFromItemToSceneTransform = QTransform();
m_beginToParentTransform = QTransform();
m_beginTopMargin = 0.0;
m_beginLeftMargin = 0.0;
m_beginRightMargin = 0.0;
m_beginBottomMargin = 0.0;
removeHandle();
}
bool RotationManipulator::isActive() const
{
return m_isActive;
}
}

View File

@@ -0,0 +1,82 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "rotationhandleitem.h"
#include <snapper.h>
#include "rewritertransaction.h"
#include "formeditorview.h"
#include <QPointer>
namespace QmlDesigner {
class RotationHandleItem;
class Model;
class RotationManipulator
{
public:
RotationManipulator(LayerItem *layerItem, FormEditorView *view);
~RotationManipulator();
void setHandle(RotationHandleItem *rotationHandle);
void removeHandle();
void begin(const QPointF& beginPoint);
void update(const QPointF& updatePoint, Qt::KeyboardModifiers keyMods = Qt::NoModifier);
void end();
void clear();
bool isActive() const;
protected:
void deleteSnapLines();
RotationHandleItem *rotationHandle();
private:
QPointer<FormEditorView> m_view;
QList<QGraphicsItem*> m_graphicsLineList;
RotationController m_rotationController; // hold the controller so that the handle cant be deleted
QTransform m_beginFromSceneToContentItemTransform;
QTransform m_beginFromContentItemToSceneTransform;
QTransform m_beginFromItemToSceneTransform;
QTransform m_beginToParentTransform;
QRectF m_beginBoundingRect;
QPointF m_beginBottomRightPoint;
double m_beginTopMargin;
double m_beginLeftMargin;
double m_beginRightMargin;
double m_beginBottomMargin;
QPointer<LayerItem> m_layerItem;
RotationHandleItem *m_rotationHandle = nullptr;
RewriterTransaction m_rewriterTransaction;
bool m_isActive = false;
qreal m_beginRotation;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,203 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "rotationtool.h"
#include "formeditorscene.h"
#include "formeditorview.h"
#include "formeditorwidget.h"
#include "rotationhandleitem.h"
#include <QGraphicsSceneMouseEvent>
#include <QAction>
#include <QDebug>
namespace QmlDesigner {
RotationTool::RotationTool(FormEditorView *editorView)
: AbstractFormEditorTool(editorView)
, m_selectionIndicator(editorView->scene()->manipulatorLayerItem())
, m_rotationIndicator(editorView->scene()->manipulatorLayerItem())
, m_anchorIndicator(editorView->scene()->manipulatorLayerItem())
, m_rotationManipulator(editorView->scene()->manipulatorLayerItem(), editorView)
{
}
RotationTool::~RotationTool() = default;
void RotationTool::mousePressEvent(const QList<QGraphicsItem*> &itemList,
QGraphicsSceneMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
if (itemList.isEmpty())
return;
RotationHandleItem *rotationHandle = RotationHandleItem::fromGraphicsItem(itemList.constFirst());
if (rotationHandle && rotationHandle->rotationController().isValid()) {
m_rotationManipulator.setHandle(rotationHandle);
m_rotationManipulator.begin(event->scenePos());
m_rotationIndicator.hide();
m_anchorIndicator.hide();
}
}
AbstractFormEditorTool::mousePressEvent(itemList, event);
}
void RotationTool::mouseMoveEvent(const QList<QGraphicsItem*> &,
QGraphicsSceneMouseEvent *event)
{
if (m_rotationManipulator.isActive())
m_rotationManipulator.update(event->scenePos(), event->modifiers());
}
void RotationTool::hoverMoveEvent(const QList<QGraphicsItem*> &itemList,
QGraphicsSceneMouseEvent * /*event*/)
{
if (itemList.isEmpty()) {
view()->changeToSelectionTool();
return;
}
RotationHandleItem* rotationHandle = RotationHandleItem::fromGraphicsItem(itemList.constFirst());
if (rotationHandle && rotationHandle->rotationController().isValid()) {
m_rotationManipulator.setHandle(rotationHandle);
} else {
view()->changeToSelectionTool();
return;
}
}
void RotationTool::dragLeaveEvent(const QList<QGraphicsItem*> &/*itemList*/, QGraphicsSceneDragDropEvent * /*event*/)
{
}
void RotationTool::dragMoveEvent(const QList<QGraphicsItem*> &/*itemList*/, QGraphicsSceneDragDropEvent * /*event*/)
{
}
void RotationTool::mouseReleaseEvent(const QList<QGraphicsItem*> &itemList,
QGraphicsSceneMouseEvent *event)
{
if (m_rotationManipulator.isActive()) {
if (itemList.isEmpty())
return;
m_selectionIndicator.show();
m_rotationIndicator.show();
m_anchorIndicator.show();
m_rotationManipulator.end();
}
AbstractFormEditorTool::mouseReleaseEvent(itemList, event);
}
void RotationTool::mouseDoubleClickEvent(const QList<QGraphicsItem*> & /*itemList*/,
QGraphicsSceneMouseEvent * /*event*/)
{
}
void RotationTool::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;
}
void RotationTool::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;
}
}
void RotationTool::itemsAboutToRemoved(const QList<FormEditorItem*> & /*itemList*/)
{
}
void RotationTool::selectedItemsChanged(const QList<FormEditorItem*> & /*itemList*/)
{
m_selectionIndicator.setItems(items());
m_rotationIndicator.setItems(items());
m_anchorIndicator.setItems(items());
}
void RotationTool::clear()
{
m_selectionIndicator.clear();
m_rotationIndicator.clear();
m_anchorIndicator.clear();
m_rotationManipulator.clear();
}
void RotationTool::formEditorItemsChanged(const QList<FormEditorItem*> &itemList)
{
const QList<FormEditorItem*> selectedItemList = filterSelectedModelNodes(itemList);
m_selectionIndicator.updateItems(selectedItemList);
m_rotationIndicator.updateItems(selectedItemList);
m_anchorIndicator.updateItems(selectedItemList);
}
void RotationTool::instancesCompleted(const QList<FormEditorItem*> &/*itemList*/)
{
}
void RotationTool::instancePropertyChange(const QList<QPair<ModelNode, PropertyName> > & /*propertyList*/)
{
}
void RotationTool::focusLost()
{
}
void RotationTool::instancesParentChanged(const QList<FormEditorItem *> &/*itemList*/)
{
}
} //namespace QmlDesigner

View File

@@ -0,0 +1,75 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "abstractformeditortool.h"
#include "selectionindicator.h"
#include "rotationindicator.h"
#include "anchorindicator.h"
#include "rotationmanipulator.h"
namespace QmlDesigner {
class RotationTool : public AbstractFormEditorTool
{
public:
RotationTool(FormEditorView* editorView);
~RotationTool() override;
void mousePressEvent(const QList<QGraphicsItem*> &itemList, QGraphicsSceneMouseEvent *event) override;
void mouseMoveEvent(const QList<QGraphicsItem*> &itemList, QGraphicsSceneMouseEvent *event) override;
void mouseReleaseEvent(const QList<QGraphicsItem*> &itemList, QGraphicsSceneMouseEvent *event) override;
void mouseDoubleClickEvent(const QList<QGraphicsItem*> &itemList, QGraphicsSceneMouseEvent *event) override;
void hoverMoveEvent(const QList<QGraphicsItem*> &itemList, QGraphicsSceneMouseEvent *event) override;
void dragLeaveEvent(const QList<QGraphicsItem*> &itemList, QGraphicsSceneDragDropEvent *event) override;
void dragMoveEvent(const QList<QGraphicsItem*> &itemList, QGraphicsSceneDragDropEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
void keyReleaseEvent(QKeyEvent *keyEvent) override;
void itemsAboutToRemoved(const QList<FormEditorItem*> &itemList) override;
void selectedItemsChanged(const QList<FormEditorItem*> &itemList) override;
void clear() override;
void formEditorItemsChanged(const QList<FormEditorItem*> &itemList) override;
void instancesParentChanged(const QList<FormEditorItem *> &itemList) override;
void instancesCompleted(const QList<FormEditorItem*> &itemList) override;
void instancePropertyChange(const QList<QPair<ModelNode, PropertyName> > &propertyList) override;
void focusLost() override;
private:
SelectionIndicator m_selectionIndicator;
RotationIndicator m_rotationIndicator;
AnchorIndicator m_anchorIndicator;
RotationManipulator m_rotationManipulator;
};
} // namespace QmlDesigner

View File

@@ -30,6 +30,7 @@
#include "formeditorgraphicsview.h"
#include "resizehandleitem.h"
#include "rotationhandleitem.h"
#include <nodemetainfo.h>
@@ -42,14 +43,15 @@ const int s_startDragDistance = 20;
const int s_startDragTime = 50;
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()),
m_anchorIndicator(editorView->scene()->manipulatorLayerItem()),
m_bindingIndicator(editorView->scene()->manipulatorLayerItem()),
m_contentNotEditableIndicator(editorView->scene()->manipulatorLayerItem())
: AbstractFormEditorTool(editorView)
, m_rubberbandSelectionManipulator(editorView->scene()->manipulatorLayerItem(), editorView)
, m_singleSelectionManipulator(editorView)
, m_selectionIndicator(editorView->scene()->manipulatorLayerItem())
, m_resizeIndicator(editorView->scene()->manipulatorLayerItem())
, m_rotationIndicator(editorView->scene()->manipulatorLayerItem())
, m_anchorIndicator(editorView->scene()->manipulatorLayerItem())
, m_bindingIndicator(editorView->scene()->manipulatorLayerItem())
, m_contentNotEditableIndicator(editorView->scene()->manipulatorLayerItem())
{
m_selectionIndicator.setCursor(Qt::ArrowCursor);
}
@@ -135,6 +137,12 @@ void SelectionTool::hoverMoveEvent(const QList<QGraphicsItem*> &itemList,
return;
}
RotationHandleItem* rotationHandle = RotationHandleItem::fromGraphicsItem(itemList.constFirst());
if (rotationHandle) {
view()->changeToRotationTool();
return;
}
if ((topSelectedItemIsMovable(itemList) && !view()->hasSingleSelectedModelNode())
|| (selectedItemCursorInMovableArea(event->scenePos())
&& !event->modifiers().testFlag(Qt::ControlModifier)
@@ -245,6 +253,7 @@ void SelectionTool::clear()
m_singleSelectionManipulator.clear();
m_selectionIndicator.clear();
m_resizeIndicator.clear();
m_rotationIndicator.clear();
m_anchorIndicator.clear();
m_bindingIndicator.clear();
m_contentNotEditableIndicator.clear();
@@ -256,6 +265,7 @@ void SelectionTool::selectedItemsChanged(const QList<FormEditorItem*> &itemList)
{
m_selectionIndicator.setItems(itemList);
m_resizeIndicator.setItems(itemList);
m_rotationIndicator.setItems(itemList);
m_anchorIndicator.setItems(itemList);
m_bindingIndicator.setItems(itemList);
}
@@ -266,6 +276,7 @@ void SelectionTool::formEditorItemsChanged(const QList<FormEditorItem*> &itemLis
m_selectionIndicator.updateItems(selectedItemList);
m_resizeIndicator.updateItems(selectedItemList);
m_rotationIndicator.updateItems(selectedItemList);
m_anchorIndicator.updateItems(selectedItemList);
m_bindingIndicator.updateItems(selectedItemList);
m_contentNotEditableIndicator.updateItems(selectedItemList);

View File

@@ -29,6 +29,7 @@
#include "singleselectionmanipulator.h"
#include "selectionindicator.h"
#include "resizeindicator.h"
#include "rotationindicator.h"
#include "anchorindicator.h"
#include "bindingindicator.h"
#include "contentnoteditableindicator.h"
@@ -85,6 +86,7 @@ private:
SingleSelectionManipulator m_singleSelectionManipulator;
SelectionIndicator m_selectionIndicator;
ResizeIndicator m_resizeIndicator;
RotationIndicator m_rotationIndicator;
AnchorIndicator m_anchorIndicator;
BindingIndicator m_bindingIndicator;
ContentNotEditableIndicator m_contentNotEditableIndicator;

View File

@@ -90,6 +90,7 @@ public:
bool modelIsMovable() const;
bool modelIsResizable() const;
bool modelIsRotatable() const;
bool modelIsInLayout() const;
QRectF instanceBoundingRect() const;
@@ -123,6 +124,10 @@ public:
bool isInLayout() const;
bool canBereparentedTo(const ModelNode &potentialParent) const;
void setRotation(const qreal &angle);
qreal rotation() const;
QVariant transformOrigin();
bool isInStackedContainer() const;
bool isFlowView() const;

View File

@@ -38,6 +38,7 @@
#include "rewriterview.h"
#include "modelmerger.h"
#include "rewritingexception.h"
#include "designermcumanager.h"
#include <QUrl>
#include <QPlainTextEdit>
@@ -286,6 +287,38 @@ bool QmlItemNode::modelIsResizable() const
&& !modelIsInLayout();
}
static bool isMcuRotationAllowed(QString itemName, bool hasChildren) {
const QString propName = "rotation";
const DesignerMcuManager &manager = DesignerMcuManager::instance();
if (manager.isMCUProject()) {
if (manager.allowedItemProperties().contains(itemName)) {
const DesignerMcuManager::ItemProperties properties =
manager.allowedItemProperties().value(itemName);
if (properties.properties.contains(propName)) {
if (hasChildren)
return properties.allowChildren;
return true;
}
}
if (manager.bannedItems().contains(itemName))
return false;
if (manager.bannedProperties().contains(propName))
return false;
}
return true;
}
bool QmlItemNode::modelIsRotatable() const
{
return !modelNode().hasBindingProperty("rotation")
&& itemIsResizable(modelNode())
&& !modelIsInLayout()
&& isMcuRotationAllowed(QString::fromUtf8(modelNode().type()), hasChildren());
}
bool QmlItemNode::modelIsInLayout() const
{
if (modelNode().hasParentProperty()) {
@@ -535,6 +568,30 @@ void QmlItemNode::setSize(const QSizeF &size)
setVariantProperty("height", qRound(size.height()));
}
void QmlItemNode::setRotation(const qreal &angle)
{
if (!hasBindingProperty("rotation"))
setVariantProperty("rotation", angle);
}
qreal QmlItemNode::rotation() const
{
if (hasProperty("rotation") && !hasBindingProperty("rotation")) {
return modelNode().variantProperty("rotation").value().toReal();
}
return 0.0;
}
QVariant QmlItemNode::transformOrigin()
{
if (hasProperty("transformOrigin")) {
return modelNode().variantProperty("transformOrigin").value();
}
return {};
}
bool QmlFlowItemNode::isValid() const
{
return isValidQmlFlowItemNode(modelNode());

View File

@@ -548,6 +548,16 @@ Project {
"formeditor/resizemanipulator.h",
"formeditor/resizetool.cpp",
"formeditor/resizetool.h",
"formeditor/rotationtool.cpp",
"formeditor/rotationtool.h",
"formeditor/rotationindicator.cpp",
"formeditor/rotationindicator.h",
"formeditor/rotationcontroller.cpp",
"formeditor/rotationcontroller.h",
"formeditor/rotationhandleitem.cpp",
"formeditor/rotationhandleitem.h",
"formeditor/rotationmanipulator.cpp",
"formeditor/rotationmanipulator.h",
"formeditor/rubberbandselectionmanipulator.cpp",
"formeditor/rubberbandselectionmanipulator.h",
"formeditor/scaleitem.cpp",