From 136eb08a1be238dc84e15777c75c3d3a30f71933 Mon Sep 17 00:00:00 2001 From: Beat Hangartner Date: Sun, 4 Oct 2026 19:07:10 +0200 Subject: [PATCH] Save the rotation of a picture turned with the rotate action The rotate action (Space) turned a picture through QGraphicsItem's plain rotation, which DiagramImageItem::toXml() does not save -- it saves the rotation of the picture's own transform. The picture came back unrotated once the project was reopened. Turn it through "rotationAngle" instead, around its own pivot, and when a selection is turned as a group, move the picture so that its pivot, not its top-left corner, orbits the group's centre. Co-Authored-By: Claude Opus 5.5 --- .../undocommand/rotateselectioncommand.cpp | 25 ++++++++++++++----- sources/undocommand/rotateselectioncommand.h | 2 +- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/sources/undocommand/rotateselectioncommand.cpp b/sources/undocommand/rotateselectioncommand.cpp index 2bfc5dd6f..15ec8bd90 100644 --- a/sources/undocommand/rotateselectioncommand.cpp +++ b/sources/undocommand/rotateselectioncommand.cpp @@ -109,9 +109,17 @@ m_diagram(diagram) } break; case DiagramImageItem::Type: - m_undo << new QPropertyUndoCommand(item->toGraphicsObject(), "rotation", QVariant(item->rotation()), QVariant(item->rotation()+angle), this); + { + //A picture keeps its rotation in its own transform + //("rotationAngle", around its pivot), which is what + //toXml() saves. QGraphicsItem's plain "rotation" is + //not saved, so a picture turned with it came back + //unrotated once the project was reopened. + auto *image = static_cast(item); + m_undo << new QPropertyUndoCommand(image, "rotationAngle", QVariant(image->rotationAngle()), QVariant(image->rotationAngle()+angle), this); if (rotate_as_group) - addGroupPositionUndo(item, pivot, angle); + addGroupPositionUndo(item, pivot, angle, image->mapToScene(image->pivot()) - image->pos()); + } break; default: break; @@ -135,11 +143,16 @@ m_diagram(diagram) @param item : item to reposition, its own rotation undo already queued @param pivot : shared pivot point, in scene coordinates @param angle : rotation angle in degrees + @param anchor : the point of @a item, relative to its pos(), that + orbits @a pivot -- null for items that turn around pos() itself, the + picture's own pivot for a DiagramImageItem, which turns around that. + Only a null anchor is snapped to the grid: the centre of a picture is + rarely on it. */ -void RotateSelectionCommand::addGroupPositionUndo(QGraphicsItem *item, const QPointF &pivot, qreal angle) +void RotateSelectionCommand::addGroupPositionUndo(QGraphicsItem *item, const QPointF &pivot, qreal angle, const QPointF &anchor) { const QPointF old_pos = item->pos(); - const QPointF delta = old_pos - pivot; + const QPointF delta = old_pos + anchor - pivot; /* Exact arithmetic for the right angles instead of qCos()/qSin(). * The rotate actions only ever pass multiples of 90 degrees, and @@ -168,8 +181,8 @@ void RotateSelectionCommand::addGroupPositionUndo(QGraphicsItem *item, const QPo delta.x() * qSin(radians) + delta.y() * qCos(radians)); } - QPointF new_pos = pivot + offset; - if (exact_quadrant) + QPointF new_pos = pivot + offset - anchor; + if (exact_quadrant && anchor.isNull()) { /* Swapping X/Y deltas for a 90/270 turn only stays on the * user's configured grid if xGrid == yGrid. With an diff --git a/sources/undocommand/rotateselectioncommand.h b/sources/undocommand/rotateselectioncommand.h index df96fba96..bfc86e2f2 100644 --- a/sources/undocommand/rotateselectioncommand.h +++ b/sources/undocommand/rotateselectioncommand.h @@ -42,7 +42,7 @@ class RotateSelectionCommand : public QUndoCommand bool isValid(); private: - void addGroupPositionUndo(QGraphicsItem *item, const QPointF &pivot, qreal angle); + void addGroupPositionUndo(QGraphicsItem *item, const QPointF &pivot, qreal angle, const QPointF &anchor = QPointF()); Diagram *m_diagram =nullptr;