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 resizeindicator.cpp resizeindicator.h
resizemanipulator.cpp resizemanipulator.h resizemanipulator.cpp resizemanipulator.h
resizetool.cpp resizetool.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 rubberbandselectionmanipulator.cpp rubberbandselectionmanipulator.h
scaleitem.cpp scaleitem.h scaleitem.cpp scaleitem.h
scalemanipulator.cpp scalemanipulator.h scalemanipulator.cpp scalemanipulator.h

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -38,6 +38,7 @@
#include "rewriterview.h" #include "rewriterview.h"
#include "modelmerger.h" #include "modelmerger.h"
#include "rewritingexception.h" #include "rewritingexception.h"
#include "designermcumanager.h"
#include <QUrl> #include <QUrl>
#include <QPlainTextEdit> #include <QPlainTextEdit>
@@ -286,6 +287,38 @@ bool QmlItemNode::modelIsResizable() const
&& !modelIsInLayout(); && !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 bool QmlItemNode::modelIsInLayout() const
{ {
if (modelNode().hasParentProperty()) { if (modelNode().hasParentProperty()) {
@@ -535,6 +568,30 @@ void QmlItemNode::setSize(const QSizeF &size)
setVariantProperty("height", qRound(size.height())); 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 bool QmlFlowItemNode::isValid() const
{ {
return isValidQmlFlowItemNode(modelNode()); return isValidQmlFlowItemNode(modelNode());

View File

@@ -548,6 +548,16 @@ Project {
"formeditor/resizemanipulator.h", "formeditor/resizemanipulator.h",
"formeditor/resizetool.cpp", "formeditor/resizetool.cpp",
"formeditor/resizetool.h", "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.cpp",
"formeditor/rubberbandselectionmanipulator.h", "formeditor/rubberbandselectionmanipulator.h",
"formeditor/scaleitem.cpp", "formeditor/scaleitem.cpp",