From cc0521bfe54cbcaab832dfb06b225370feb7b127 Mon Sep 17 00:00:00 2001 From: ispyisail Date: Tue, 29 Sep 2026 23:39:23 +1300 Subject: [PATCH] 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) --- sources/qetgraphicsitem/qetshapeitem.cpp | 29 ++++++++++++++++++++++++ sources/qetgraphicsitem/qetshapeitem.h | 3 +++ 2 files changed, 32 insertions(+) diff --git a/sources/qetgraphicsitem/qetshapeitem.cpp b/sources/qetgraphicsitem/qetshapeitem.cpp index e1d610603..a6d0202a9 100644 --- a/sources/qetgraphicsitem/qetshapeitem.cpp +++ b/sources/qetgraphicsitem/qetshapeitem.cpp @@ -33,6 +33,7 @@ #include "../undocommand/promoteshapecommand.h" #include +#include #include #include #include @@ -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(); + 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 diff --git a/sources/qetgraphicsitem/qetshapeitem.h b/sources/qetgraphicsitem/qetshapeitem.h index cf1c823fd..610f06bf5 100644 --- a/sources/qetgraphicsitem/qetshapeitem.h +++ b/sources/qetgraphicsitem/qetshapeitem.h @@ -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,