Drag a shape onto the grid by its corner, not its hidden origin (#1145)

A dragged shape put its pos() on the grid. pos() cannot be seen, and it
is off the drawn corner whenever the shape was drawn or resized with
Ctrl held, or rotated, so such a shape stayed off the grid however it
was dragged. Worse, Snap to grid (previous commit) moves pos() off the
grid to put the corner on it, so the next drag undid the snap.

QetShapeItem now overrides setPos(), which only the drag calls through
the virtual: dragged alone or with other shapes only, the top-left
corner of the drawn outline goes on the grid. Dragged together with
anything else it snaps by pos() as before, because the rest of the
selection follows this shape's movement and a corner correction would
take the symbols off the grid. Ctrl still drags freely: the snap goes
through Diagram::snapToGrid(), which reads it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
ispyisail
2026-09-29 23:39:23 +13:00
parent 795484ff4f
commit cc0521bfe5
2 changed files with 32 additions and 0 deletions
+29
View File
@@ -33,6 +33,7 @@
#include "../undocommand/promoteshapecommand.h"
#include <QActionGroup>
#include <algorithm>
#include <QCursor>
#include <QMenu>
#include <QStatusBar>
@@ -613,6 +614,34 @@ QRectF QetShapeItem::sceneOutlineRect() const
return mapToScene(outline()).boundingRect();
}
/**
@brief QetShapeItem::setPos
Called with the unsnapped position while the shape is dragged. Dragged
on its own, or with other shapes only, the shape goes on the grid by the
top-left corner of what is drawn, as Snap to grid does: its pos() cannot
be seen, and it is off the corner whenever the shape was drawn or
resized with Ctrl held, or rotated. Dragged together with anything
else, it snaps by pos() as before: the whole selection follows this
shape's movement, and correcting the corner would take the symbols off
the grid instead.
@param p the new position of the item
*/
void QetShapeItem::setPos(const QPointF &p)
{
const auto selection = scene() ? scene()->selectedItems() : QList<QGraphicsItem *>();
const bool shapes_only = std::all_of(selection.cbegin(), selection.cend(),
[](const QGraphicsItem *item) { return item->type() == QetShapeItem::Type; });
if (!shapes_only || !isMovable()) {
QetGraphicsItem::setPos(p);
return;
}
const QPointF corner = sceneOutlineRect().topLeft() + (p - pos());
const QPointF snapped = p + Diagram::snapToGrid(corner) - corner;
if (snapped != pos())
QGraphicsItem::setPos(snapped);
}
/**
@brief QetShapeItem::shape
@return the shape of this item
+3
View File
@@ -221,6 +221,9 @@ class QetShapeItem : public QetGraphicsItem
QPainterPath shape() const override;
QRectF sceneOutlineRect() const;
using QetGraphicsItem::setPos;
void setPos(const QPointF &p) override;
protected:
void paint(
QPainter *painter,