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 <tim.jenssen@qt.io>
This commit is contained in:
Thomas Hartmann
2017-06-30 18:20:56 +02:00
committed by Tim Jenssen
parent 04f19cf573
commit 9c2f2bed3a
9 changed files with 82 additions and 8 deletions

View File

@@ -131,7 +131,31 @@ bool AbstractFormEditorTool::topSelectedItemIsMovable(const QList<QGraphicsItem*
}
return false;
}
bool AbstractFormEditorTool::selectedItemCursorInMovableArea(const QPointF &pos)
{
if (!view()->hasSingleSelectedModelNode())
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<QGraphicsItem*> &/*itemList*/)
@@ -328,4 +352,9 @@ void AbstractFormEditorTool::clear()
{
m_itemList.clear();
}
void AbstractFormEditorTool::start()
{
}
}

View File

@@ -67,6 +67,7 @@ public:
// const QVariant &value ) = 0;
// virtual void update() = 0;
virtual void clear();
virtual void start();
virtual void formEditorItemsChanged(const QList<FormEditorItem*> &itemList) = 0;
@@ -84,6 +85,7 @@ public:
static FormEditorItem* topMovableFormEditorItem(const QList<QGraphicsItem*> &itemList, bool selectOnlyContentItems);
bool topItemIsMovable(const QList<QGraphicsItem*> &itemList);
bool topSelectedItemIsMovable(const QList<QGraphicsItem*> &itemList);
bool selectedItemCursorInMovableArea(const QPointF &pos);
bool topItemIsResizeHandle(const QList<QGraphicsItem*> &itemList);
QList<FormEditorItem*> filterSelectedModelNodes(const QList<FormEditorItem*> &itemList) const;

View File

@@ -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)

View File

@@ -27,6 +27,8 @@
#include "layeritem.h"
#include "formeditoritem.h"
#include "formeditorscene.h"
#include "formeditorwidget.h"
#include "formeditorgraphicsview.h"
#include <qmlanchors.h>
#include <nodehints.h>
@@ -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();

View File

@@ -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<QGraphicsItem*> &itemList,
@@ -115,7 +122,7 @@ void MoveTool::mouseMoveEvent(const QList<QGraphicsItem*> &itemList,
}
void MoveTool::hoverMoveEvent(const QList<QGraphicsItem*> &itemList,
QGraphicsSceneMouseEvent * /*event*/)
QGraphicsSceneMouseEvent * event)
{
if (itemList.isEmpty()) {
view()->changeToSelectionTool();
@@ -133,6 +140,18 @@ void MoveTool::hoverMoveEvent(const QList<QGraphicsItem*> &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<QGraphicsItem*> &itemList,
m_movingItems.clear();
}
view()->changeToSelectionTool();
AbstractFormEditorTool::mouseReleaseEvent(itemList, event);
}

View File

@@ -64,6 +64,7 @@ public:
void beginWithPoint(const QPointF &beginPoint);
void clear() override;
void start() override;
void formEditorItemsChanged(const QList<FormEditorItem*> &itemList) override;

View File

@@ -109,7 +109,6 @@ void SelectionIndicator::setItems(const QList<FormEditorItem*> &itemList)
pen.setJoinStyle(Qt::MiterJoin);
pen.setColor(selectionColor);
newSelectionIndicatorGraphicsItem->setPen(pen);
newSelectionIndicatorGraphicsItem->setCursor(m_cursor);
}
if (checkSingleSelection(itemList)) {

View File

@@ -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<QGraphicsItem*> &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,6 +108,7 @@ void SelectionTool::mouseMoveEvent(const QList<QGraphicsItem*> &/*itemList*/,
if ((mouseMovementVector.toPoint().manhattanLength() > s_startDragDistance)
&& (m_mousePressTimer.elapsed() > s_startDragTime)) {
m_singleSelectionManipulator.end(event->scenePos());
if (m_itemAlreadySelected)
view()->changeToMoveTool(m_singleSelectionManipulator.beginPoint());
return;
}
@@ -134,7 +139,10 @@ void SelectionTool::hoverMoveEvent(const QList<QGraphicsItem*> &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<QGraphicsItem*> &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));

View File

@@ -89,6 +89,7 @@ private:
ContentNotEditableIndicator m_contentNotEditableIndicator;
QTime m_mousePressTimer;
QCursor m_cursor;
bool m_itemAlreadySelected = false;
};
} // namespace QmlDesigner