From 9c2f2bed3a5187b259f51a3138baf220b9f3a148 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 30 Jun 2017 18:20:56 +0200 Subject: [PATCH] QmlDesigner: Refine selection This is a major overhaul of the slection logic. We do not change to the move tool automatically once the curser enters the selected item. This allows selection of items that are at the same position as the current selected item. The selected item can still be moved if there is no pissible candidate for selection. Also the border and gizmo always allows an item to be moved, if the item is fully covered by another item. Change-Id: Ic97a2bf23f33fcc5e209248aeb2f97df67bd23e1 Reviewed-by: Tim Jenssen --- .../formeditor/abstractformeditortool.cpp | 29 +++++++++++++++++++ .../formeditor/abstractformeditortool.h | 2 ++ .../components/formeditor/formeditorview.cpp | 1 + .../components/formeditor/movemanipulator.cpp | 4 +++ .../components/formeditor/movetool.cpp | 23 ++++++++++++++- .../components/formeditor/movetool.h | 1 + .../formeditor/selectionindicator.cpp | 1 - .../components/formeditor/selectiontool.cpp | 28 ++++++++++++++---- .../components/formeditor/selectiontool.h | 1 + 9 files changed, 82 insertions(+), 8 deletions(-) diff --git a/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp index f743814bc76..291f17fad50 100644 --- a/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp +++ b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp @@ -131,7 +131,31 @@ bool AbstractFormEditorTool::topSelectedItemIsMovable(const QListhasSingleSelectedModelNode()) + return false; + + const ModelNode selectedNode = view()->singleSelectedModelNode(); + + FormEditorItem *item = scene()->itemForQmlItemNode(selectedNode); + + if (!item) + return false; + + if (!topSelectedItemIsMovable({item})) + return false; + + const QPolygonF boundingRectInSceneSpace(item->mapToScene(item->qmlItemNode().instanceBoundingRect())); + QRectF boundingRect = boundingRectInSceneSpace.boundingRect(); + QRectF innerRect = boundingRect; + + innerRect.adjust(10, 10, -10, -10); + boundingRect.adjust(-10, -20, 10, 10); + + return !innerRect.contains(pos) && boundingRect.contains(pos); } bool AbstractFormEditorTool::topItemIsResizeHandle(const QList &/*itemList*/) @@ -328,4 +352,9 @@ void AbstractFormEditorTool::clear() { m_itemList.clear(); } + +void AbstractFormEditorTool::start() +{ + +} } diff --git a/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.h b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.h index e62975e21c9..02cbc5a289a 100644 --- a/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.h +++ b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.h @@ -67,6 +67,7 @@ public: // const QVariant &value ) = 0; // virtual void update() = 0; virtual void clear(); + virtual void start(); virtual void formEditorItemsChanged(const QList &itemList) = 0; @@ -84,6 +85,7 @@ public: static FormEditorItem* topMovableFormEditorItem(const QList &itemList, bool selectOnlyContentItems); bool topItemIsMovable(const QList &itemList); bool topSelectedItemIsMovable(const QList &itemList); + bool selectedItemCursorInMovableArea(const QPointF &pos); bool topItemIsResizeHandle(const QList &itemList); QList filterSelectedModelNodes(const QList &itemList) const; diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp index 3833c3682c8..1ec725d6cd6 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp @@ -411,6 +411,7 @@ void FormEditorView::changeCurrentToolTo(AbstractFormEditorTool *newTool) m_currentTool->clear(); m_currentTool->setItems(scene()->itemsForQmlItemNodes(toQmlItemNodeList( selectedModelNodes()))); + m_currentTool->start(); } void FormEditorView::registerTool(AbstractCustomTool *tool) diff --git a/src/plugins/qmldesigner/components/formeditor/movemanipulator.cpp b/src/plugins/qmldesigner/components/formeditor/movemanipulator.cpp index 52c782eaa44..ecca77a73d3 100644 --- a/src/plugins/qmldesigner/components/formeditor/movemanipulator.cpp +++ b/src/plugins/qmldesigner/components/formeditor/movemanipulator.cpp @@ -27,6 +27,8 @@ #include "layeritem.h" #include "formeditoritem.h" #include "formeditorscene.h" +#include "formeditorwidget.h" +#include "formeditorgraphicsview.h" #include #include @@ -129,6 +131,7 @@ void MoveManipulator::setDirectUpdateInNodeInstances(bool directUpdate) void MoveManipulator::begin(const QPointF &beginPoint) { + m_view->formEditorWidget()->graphicsView()->viewport()->setCursor(Qt::SizeAllCursor); m_isActive = true; m_snapper.updateSnappingLines(m_itemList); @@ -377,6 +380,7 @@ void MoveManipulator::reparentTo(FormEditorItem *newParent) void MoveManipulator::end() { + m_view->formEditorWidget()->graphicsView()->viewport()->unsetCursor(); setDirectUpdateInNodeInstances(false); m_isActive = false; deleteSnapLines(); diff --git a/src/plugins/qmldesigner/components/formeditor/movetool.cpp b/src/plugins/qmldesigner/components/formeditor/movetool.cpp index ebd32c1bba6..fba74d9b3cb 100644 --- a/src/plugins/qmldesigner/components/formeditor/movetool.cpp +++ b/src/plugins/qmldesigner/components/formeditor/movetool.cpp @@ -28,6 +28,7 @@ #include "formeditorscene.h" #include "formeditorview.h" #include "formeditorwidget.h" +#include "formeditorgraphicsview.h" #include "resizehandleitem.h" @@ -66,6 +67,12 @@ void MoveTool::clear() m_contentNotEditableIndicator.clear(); AbstractFormEditorTool::clear(); + view()->formEditorWidget()->graphicsView()->viewport()->unsetCursor(); +} + +void MoveTool::start() +{ + view()->formEditorWidget()->graphicsView()->viewport()->setCursor(Qt::SizeAllCursor); } void MoveTool::mousePressEvent(const QList &itemList, @@ -115,7 +122,7 @@ void MoveTool::mouseMoveEvent(const QList &itemList, } void MoveTool::hoverMoveEvent(const QList &itemList, - QGraphicsSceneMouseEvent * /*event*/) + QGraphicsSceneMouseEvent * event) { if (itemList.isEmpty()) { view()->changeToSelectionTool(); @@ -133,6 +140,18 @@ void MoveTool::hoverMoveEvent(const QList &itemList, return; } + if (view()->hasSingleSelectedModelNode() && !selectedItemCursorInMovableArea(event->scenePos())) { + view()->changeToSelectionTool(); + return; + } + + if (event->modifiers().testFlag(Qt::ShiftModifier) + || event->modifiers().testFlag(Qt::ControlModifier) ) { + view()->changeToSelectionTool(); + return; + } + + m_contentNotEditableIndicator.setItems(toFormEditorItemList(itemList)); } @@ -224,6 +243,8 @@ void MoveTool::mouseReleaseEvent(const QList &itemList, m_movingItems.clear(); } + view()->changeToSelectionTool(); + AbstractFormEditorTool::mouseReleaseEvent(itemList, event); } diff --git a/src/plugins/qmldesigner/components/formeditor/movetool.h b/src/plugins/qmldesigner/components/formeditor/movetool.h index 8aab108eb53..0092d6757d3 100644 --- a/src/plugins/qmldesigner/components/formeditor/movetool.h +++ b/src/plugins/qmldesigner/components/formeditor/movetool.h @@ -64,6 +64,7 @@ public: void beginWithPoint(const QPointF &beginPoint); void clear() override; + void start() override; void formEditorItemsChanged(const QList &itemList) override; diff --git a/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp b/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp index fc9d338affb..c1b26877ad2 100644 --- a/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp +++ b/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp @@ -109,7 +109,6 @@ void SelectionIndicator::setItems(const QList &itemList) pen.setJoinStyle(Qt::MiterJoin); pen.setColor(selectionColor); newSelectionIndicatorGraphicsItem->setPen(pen); - newSelectionIndicatorGraphicsItem->setCursor(m_cursor); } if (checkSingleSelection(itemList)) { diff --git a/src/plugins/qmldesigner/components/formeditor/selectiontool.cpp b/src/plugins/qmldesigner/components/formeditor/selectiontool.cpp index a187682bf48..3aa1c2c1fd7 100644 --- a/src/plugins/qmldesigner/components/formeditor/selectiontool.cpp +++ b/src/plugins/qmldesigner/components/formeditor/selectiontool.cpp @@ -26,6 +26,8 @@ #include "selectiontool.h" #include "formeditorscene.h" #include "formeditorview.h" +#include "formeditorwidget.h" +#include "formeditorgraphicsview.h" #include "resizehandleitem.h" @@ -64,14 +66,16 @@ void SelectionTool::mousePressEvent(const QList &itemList, m_mousePressTimer.start(); FormEditorItem* formEditorItem = nearestFormEditorItem(event->scenePos(), itemList); if (formEditorItem - && formEditorItem->qmlItemNode().isValid() - && !formEditorItem->qmlItemNode().hasChildren()) { + && formEditorItem->qmlItemNode().isValid()) { m_singleSelectionManipulator.begin(event->scenePos()); + m_itemAlreadySelected = toQmlItemNodeList(view()->selectedModelNodes()).contains(formEditorItem->qmlItemNode()) + || !view()->hasSingleSelectedModelNode(); + if (event->modifiers().testFlag(Qt::ControlModifier)) - m_singleSelectionManipulator.select(SingleSelectionManipulator::RemoveFromSelection); + m_singleSelectionManipulator.select(SingleSelectionManipulator::InvertSelection); else if (event->modifiers().testFlag(Qt::ShiftModifier)) - m_singleSelectionManipulator.select(SingleSelectionManipulator::AddToSelection); + m_singleSelectionManipulator.select(SingleSelectionManipulator::InvertSelection); else m_singleSelectionManipulator.select(SingleSelectionManipulator::ReplaceSelection); } else { @@ -104,7 +108,8 @@ void SelectionTool::mouseMoveEvent(const QList &/*itemList*/, if ((mouseMovementVector.toPoint().manhattanLength() > s_startDragDistance) && (m_mousePressTimer.elapsed() > s_startDragTime)) { m_singleSelectionManipulator.end(event->scenePos()); - view()->changeToMoveTool(m_singleSelectionManipulator.beginPoint()); + if (m_itemAlreadySelected) + view()->changeToMoveTool(m_singleSelectionManipulator.beginPoint()); return; } } else if (m_rubberbandSelectionManipulator.isActive()) { @@ -134,7 +139,10 @@ void SelectionTool::hoverMoveEvent(const QList &itemList, return; } - if (topSelectedItemIsMovable(itemList)) { + if ((topSelectedItemIsMovable(itemList) && !view()->hasSingleSelectedModelNode()) + || selectedItemCursorInMovableArea(event->scenePos()) + && !event->modifiers().testFlag(Qt::ControlModifier) + && !event->modifiers().testFlag(Qt::ShiftModifier)) { view()->changeToMoveTool(); return; } @@ -142,6 +150,14 @@ void SelectionTool::hoverMoveEvent(const QList &itemList, FormEditorItem *topSelectableItem = nearestFormEditorItem(event->scenePos(), itemList); + + if (topSelectableItem && toQmlItemNodeList(view()->selectedModelNodes()).contains(topSelectableItem->qmlItemNode()) + && topSelectedItemIsMovable({topSelectableItem})) { + view()->formEditorWidget()->graphicsView()->viewport()->setCursor(Qt::SizeAllCursor); + } else { + view()->formEditorWidget()->graphicsView()->viewport()->unsetCursor(); + } + scene()->highlightBoundingRect(topSelectableItem); m_contentNotEditableIndicator.setItems(toFormEditorItemList(itemList)); diff --git a/src/plugins/qmldesigner/components/formeditor/selectiontool.h b/src/plugins/qmldesigner/components/formeditor/selectiontool.h index 0a5945c7356..154a57f2239 100644 --- a/src/plugins/qmldesigner/components/formeditor/selectiontool.h +++ b/src/plugins/qmldesigner/components/formeditor/selectiontool.h @@ -89,6 +89,7 @@ private: ContentNotEditableIndicator m_contentNotEditableIndicator; QTime m_mousePressTimer; QCursor m_cursor; + bool m_itemAlreadySelected = false; }; } // namespace QmlDesigner