From f60d16a1525fe3b4ba2897ec3fe5be95f42d6708 Mon Sep 17 00:00:00 2001 From: IoriBranford Date: Thu, 7 Dec 2023 17:39:18 -0800 Subject: [PATCH 1/5] Support point rotation. - Consider point rotatable - Transform graphics item - Rotate reference arrow position - Rotate selection outline - Let selection tool rotate but not resize single point - Always use point position as the rotate origin - Unlock rotation property on point --- src/libtiled/mapobject.h | 2 +- src/tiled/mapobjectitem.cpp | 3 +-- src/tiled/objectreferenceitem.cpp | 10 +++----- src/tiled/objectselectionitem.cpp | 3 +-- src/tiled/objectselectiontool.cpp | 41 +++++++++++++++++++++++++------ src/tiled/propertybrowser.cpp | 3 +-- 6 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/libtiled/mapobject.h b/src/libtiled/mapobject.h index 4e8ae8ab27..53d66039dc 100644 --- a/src/libtiled/mapobject.h +++ b/src/libtiled/mapobject.h @@ -422,7 +422,7 @@ inline bool MapObject::hasDimensions() const * Returns true if this object can be rotated. */ inline bool MapObject::canRotate() const -{ return mShape != Point; } +{ return true; } inline bool MapObject::isTileObject() const { return !mCell.isEmpty(); } diff --git a/src/tiled/mapobjectitem.cpp b/src/tiled/mapobjectitem.cpp index 70c679fecb..744f7ebf04 100644 --- a/src/tiled/mapobjectitem.cpp +++ b/src/tiled/mapobjectitem.cpp @@ -97,8 +97,7 @@ void MapObjectItem::syncWithMapObject() } setVisible(mObject->isVisible()); - setFlag(QGraphicsItem::ItemIgnoresTransformations, - mObject->shape() == MapObject::Point); + setFlag(QGraphicsItem::ItemIgnoresTransformations, false); } void MapObjectItem::setIsHoverIndicator(bool isHoverIndicator) diff --git a/src/tiled/objectreferenceitem.cpp b/src/tiled/objectreferenceitem.cpp index f0be3eca99..004d8302c1 100644 --- a/src/tiled/objectreferenceitem.cpp +++ b/src/tiled/objectreferenceitem.cpp @@ -199,13 +199,11 @@ QPointF ObjectReferenceItem::objectCenter(MapObject *object, const MapRenderer & { QPointF screenPos = renderer.pixelToScreenCoords(object->position()); - if (object->shape() != MapObject::Point) { - QRectF bounds = object->screenBounds(renderer); + QRectF bounds = object->screenBounds(renderer); - // Adjust the bounding box for object rotation - bounds = rotateAt(screenPos, object->rotation()).mapRect(bounds); - screenPos = bounds.center(); - } + // Adjust the bounding box for object rotation + bounds = rotateAt(screenPos, object->rotation()).mapRect(bounds); + screenPos = bounds.center(); if (auto mapScene = qobject_cast(scene())) screenPos += mapScene->absolutePositionForLayer(*object->objectGroup()); diff --git a/src/tiled/objectselectionitem.cpp b/src/tiled/objectselectionitem.cpp index 729de2f515..27a4dae520 100644 --- a/src/tiled/objectselectionitem.cpp +++ b/src/tiled/objectselectionitem.cpp @@ -110,8 +110,7 @@ void MapObjectOutline::syncWithMapObject(const MapRenderer &renderer) setPos(pixelPos); setRotation(mObject->rotation()); - setFlag(QGraphicsItem::ItemIgnoresTransformations, - mObject->shape() == MapObject::Point); + setFlag(QGraphicsItem::ItemIgnoresTransformations, false); if (mBoundingRect != bounds) { prepareGeometryChange(); diff --git a/src/tiled/objectselectiontool.cpp b/src/tiled/objectselectiontool.cpp index 758eb7a113..d3c53f0fe0 100644 --- a/src/tiled/objectselectiontool.cpp +++ b/src/tiled/objectselectiontool.cpp @@ -58,6 +58,8 @@ using namespace Tiled; +static bool canResize(const MapObject *object); + namespace Tiled { enum AnchorPosition { @@ -685,12 +687,18 @@ void ObjectSelectionTool::mouseReleased(QGraphicsSceneMouseEvent *event) if (selection.size() > 1 || selection.first()->canRotate()) setMode(Rotate); } else { - setMode(Resize); + if (selection.size() == 1 && selection.first()->canRotate() && !canResize(selection.first())) + setMode(Rotate); + else + setMode(Resize); } } else { selection.clear(); selection.append(mClickedObject); - setMode(Resize); + if (selection.first()->canRotate() && !canResize(selection.first())) + setMode(Rotate); + else + setMode(Resize); mapDocument()->setSelectedObjects(selection); } } else if (!(modifiers & Qt::ShiftModifier)) { @@ -856,6 +864,16 @@ static bool canResize(const MapObject *object) return object->shape() != MapObject::Point; } +static bool canResizeOrRotate(const MapObject *object) +{ + return canResize(object) || object->canRotate(); +} + +static bool originIsAlwaysPosition(const MapObject *object) +{ + return object->shape() == MapObject::Point; +} + static bool canResizeAbsolute(const MapObject *object) { switch (object->shape()) { @@ -977,7 +995,7 @@ void ObjectSelectionTool::updateHandlesImpl(bool resetOriginIndicator) return; const QList &objects = mapDocument()->selectedObjects(); - const bool showHandles = objects.size() > 0 && (objects.size() > 1 || canResize(objects.first())); + const bool showHandles = objects.size() > 0 && (objects.size() > 1 || canResizeOrRotate(objects.first())); if (showHandles) { MapRenderer *renderer = mapDocument()->renderer(); @@ -1013,7 +1031,11 @@ void ObjectSelectionTool::updateHandlesImpl(bool resetOriginIndicator) topRight = transform.map(renderer->pixelToScreenCoords(bounds.topRight())); bottomLeft = transform.map(renderer->pixelToScreenCoords(bounds.bottomLeft())); bottomRight = transform.map(renderer->pixelToScreenCoords(bounds.bottomRight())); - center = transform.map(renderer->pixelToScreenCoords(bounds.center())); + + if (originIsAlwaysPosition(object)) + center = object->position(); + else + center = transform.map(renderer->pixelToScreenCoords(bounds.center())); // Ugly hack to make handles appear nicer in this case if (mapDocument()->map()->orientation() == Map::Isometric) @@ -1026,7 +1048,11 @@ void ObjectSelectionTool::updateHandlesImpl(bool resetOriginIndicator) topRight = transform.map(bounds.topRight()); bottomLeft = transform.map(bounds.bottomLeft()); bottomRight = transform.map(bounds.bottomRight()); - center = transform.map(bounds.center()); + + if (originIsAlwaysPosition(object)) + center = object->position(); + else + center = transform.map(bounds.center()); } } @@ -1074,9 +1100,10 @@ void ObjectSelectionTool::updateHandleVisibility() { const QList &objects = mapDocument()->selectedObjects(); const bool hasSelection = !objects.isEmpty(); - const bool hasResizableObject = std::any_of(objects.begin(), objects.end(), canResize); - const bool showHandles = hasSelection && (objects.size() > 1 || hasResizableObject) && (mAction == NoAction || mAction == Selecting); + const bool hasResizableOrRotatableObject = std::any_of(objects.begin(), objects.end(), canResizeOrRotate); + const bool showHandles = hasSelection && (objects.size() > 1 || hasResizableOrRotatableObject) && (mAction == NoAction || mAction == Selecting); const bool showOrigin = hasSelection && + (objects.size() > 1 || !originIsAlwaysPosition(objects.first())) && mAction != Moving && (mMode == Rotate || mAction == Resizing); for (RotateHandle *handle : mRotateHandles) diff --git a/src/tiled/propertybrowser.cpp b/src/tiled/propertybrowser.cpp index 1b1850b873..864b4cd825 100644 --- a/src/tiled/propertybrowser.cpp +++ b/src/tiled/propertybrowser.cpp @@ -835,8 +835,7 @@ void PropertyBrowser::addMapObjectProperties() addProperty(HeightProperty, QMetaType::Double, tr("Height"), groupProperty); } - bool isPoint = mapObject->shape() == MapObject::Point; - addProperty(RotationProperty, QMetaType::Double, tr("Rotation"), groupProperty)->setEnabled(!isPoint); + addProperty(RotationProperty, QMetaType::Double, tr("Rotation"), groupProperty); if (mMapObjectFlags & ObjectHasTile) { QtVariantProperty *flippingProperty = From 0ffa9bf52edba762d09947ffba14f2dd6b033f1c Mon Sep 17 00:00:00 2001 From: IoriBranford Date: Thu, 7 Dec 2023 18:33:13 -0800 Subject: [PATCH 2/5] Add resetModeForSelection. --- src/tiled/objectselectiontool.cpp | 21 +++++++++++++-------- src/tiled/objectselectiontool.h | 1 + 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/tiled/objectselectiontool.cpp b/src/tiled/objectselectiontool.cpp index d3c53f0fe0..4bc2f87635 100644 --- a/src/tiled/objectselectiontool.cpp +++ b/src/tiled/objectselectiontool.cpp @@ -687,18 +687,12 @@ void ObjectSelectionTool::mouseReleased(QGraphicsSceneMouseEvent *event) if (selection.size() > 1 || selection.first()->canRotate()) setMode(Rotate); } else { - if (selection.size() == 1 && selection.first()->canRotate() && !canResize(selection.first())) - setMode(Rotate); - else - setMode(Resize); + resetModeForSelection(selection); } } else { selection.clear(); selection.append(mClickedObject); - if (selection.first()->canRotate() && !canResize(selection.first())) - setMode(Rotate); - else - setMode(Resize); + resetModeForSelection(selection); mapDocument()->setSelectedObjects(selection); } } else if (!(modifiers & Qt::ShiftModifier)) { @@ -1662,6 +1656,17 @@ void ObjectSelectionTool::finishResizing() updateHandlesAndOrigin(); } +void ObjectSelectionTool::resetModeForSelection(const QList &selection) +{ + if (selection.size() == 1) + if (selection.first()->canRotate()) + if (!canResize(selection.first())) { + setMode(Rotate); + return; + } + setMode(Resize); +} + void ObjectSelectionTool::setMode(Mode mode) { if (mMode != mode) { diff --git a/src/tiled/objectselectiontool.h b/src/tiled/objectselectiontool.h index 6b01a4b66a..1bd3509bf3 100644 --- a/src/tiled/objectselectiontool.h +++ b/src/tiled/objectselectiontool.h @@ -124,6 +124,7 @@ class ObjectSelectionTool : public AbstractObjectTool void finishResizing(); void setMode(Mode mode); + void resetModeForSelection(const QList &selection); void saveSelectionState(); enum AbortReason { From 62ee3ecc508813fcec061d4c8398c329eb144a79 Mon Sep 17 00:00:00 2001 From: IoriBranford Date: Thu, 7 Dec 2023 18:40:26 -0800 Subject: [PATCH 3/5] Update mode on selectedObjectsChanged. Fixes going to resize mode instead of rotate mode when creating new point object. --- src/tiled/objectselectiontool.cpp | 18 +++++++++++++----- src/tiled/objectselectiontool.h | 3 ++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/tiled/objectselectiontool.cpp b/src/tiled/objectselectiontool.cpp index 4bc2f87635..453366a10a 100644 --- a/src/tiled/objectselectiontool.cpp +++ b/src/tiled/objectselectiontool.cpp @@ -371,7 +371,7 @@ void ObjectSelectionTool::activate(MapScene *scene) connect(mapDocument(), &MapDocument::mapChanged, this, &ObjectSelectionTool::updateHandlesAndOrigin); connect(mapDocument(), &MapDocument::selectedObjectsChanged, - this, &ObjectSelectionTool::updateHandlesAndOrigin); + this, &ObjectSelectionTool::updateHandlesAndOriginAndMode); connect(mapDocument(), &MapDocument::tilesetTilePositioningChanged, this, &ObjectSelectionTool::updateHandlesAndOrigin); connect(scene, &MapScene::parallaxParametersChanged, @@ -395,7 +395,7 @@ void ObjectSelectionTool::deactivate(MapScene *scene) disconnect(mapDocument(), &MapDocument::mapChanged, this, &ObjectSelectionTool::updateHandlesAndOrigin); disconnect(mapDocument(), &MapDocument::selectedObjectsChanged, - this, &ObjectSelectionTool::updateHandlesAndOrigin); + this, &ObjectSelectionTool::updateHandlesAndOriginAndMode); disconnect(mapDocument(), &MapDocument::tilesetTilePositioningChanged, this, &ObjectSelectionTool::updateHandlesAndOrigin); disconnect(scene, &MapScene::parallaxParametersChanged, @@ -802,12 +802,17 @@ void ObjectSelectionTool::changeEvent(const ChangeEvent &event) void ObjectSelectionTool::updateHandles() { - updateHandlesImpl(false); + updateHandlesImpl(false, false); } void ObjectSelectionTool::updateHandlesAndOrigin() { - updateHandlesImpl(true); + updateHandlesImpl(true, false); +} + +void ObjectSelectionTool::updateHandlesAndOriginAndMode() +{ + updateHandlesImpl(true, true); } // TODO: Check whether this function should be moved into MapObject::bounds @@ -983,7 +988,7 @@ static QRectF uniteBounds(const QRectF &a, const QRectF &b) return QRectF(left, top, right - left, bottom - top); } -void ObjectSelectionTool::updateHandlesImpl(bool resetOriginIndicator) +void ObjectSelectionTool::updateHandlesImpl(bool resetOriginIndicator, bool shouldResetMode) { if (mAction == Moving || mAction == Rotating || mAction == Resizing) return; @@ -992,6 +997,9 @@ void ObjectSelectionTool::updateHandlesImpl(bool resetOriginIndicator) const bool showHandles = objects.size() > 0 && (objects.size() > 1 || canResizeOrRotate(objects.first())); if (showHandles) { + if (shouldResetMode) + resetModeForSelection(objects); + MapRenderer *renderer = mapDocument()->renderer(); QRectF boundingRect = objectBounds(objects.first(), renderer, objectTransform(objects.first(), renderer, mapScene())); diff --git a/src/tiled/objectselectiontool.h b/src/tiled/objectselectiontool.h index 1bd3509bf3..bb0275b861 100644 --- a/src/tiled/objectselectiontool.h +++ b/src/tiled/objectselectiontool.h @@ -72,6 +72,7 @@ class ObjectSelectionTool : public AbstractObjectTool void updateHandles(); void updateHandlesAndOrigin(); + void updateHandlesAndOriginAndMode(); void updateHandleVisibility(); void objectsAboutToBeRemoved(const QList &); @@ -92,7 +93,7 @@ class ObjectSelectionTool : public AbstractObjectTool Rotate, }; - void updateHandlesImpl(bool resetOriginIndicator); + void updateHandlesImpl(bool resetOriginIndicator, bool shouldResetMode); void updateHover(const QPointF &pos); QList objectsAboutToBeSelected(const QPointF &pos, From 0c8f53c45d2f99325b8dd209e5879a1319f0e3f4 Mon Sep 17 00:00:00 2001 From: IoriBranford Date: Thu, 7 Dec 2023 18:44:03 -0800 Subject: [PATCH 4/5] Remove unnecessary canResize forward declaration. --- src/tiled/objectselectiontool.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tiled/objectselectiontool.cpp b/src/tiled/objectselectiontool.cpp index 453366a10a..02bfa95059 100644 --- a/src/tiled/objectselectiontool.cpp +++ b/src/tiled/objectselectiontool.cpp @@ -58,8 +58,6 @@ using namespace Tiled; -static bool canResize(const MapObject *object); - namespace Tiled { enum AnchorPosition { From fc1116d14471347b880697fb0e326657b57a5ebc Mon Sep 17 00:00:00 2001 From: IoriBranford Date: Thu, 7 Dec 2023 19:06:19 -0800 Subject: [PATCH 5/5] Rotate point object label positions too. --- src/tiled/objectselectionitem.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/tiled/objectselectionitem.cpp b/src/tiled/objectselectionitem.cpp index 27a4dae520..eb81db2606 100644 --- a/src/tiled/objectselectionitem.cpp +++ b/src/tiled/objectselectionitem.cpp @@ -202,13 +202,7 @@ void MapObjectLabel::syncWithMapObject(const MapRenderer &renderer) bounds = rotateAt(pos, mObject->rotation()).mapRect(bounds); // Center the object name on the object bounding box - if (mObject->shape() == MapObject::Point) { - // Use a local offset, since point objects don't scale with the view - boundingRect.translate(0, -bounds.height()); - mTextPos.ry() -= bounds.height(); - } else { - pos = { (bounds.left() + bounds.right()) / 2, bounds.top() }; - } + pos = { (bounds.left() + bounds.right()) / 2, bounds.top() }; if (auto mapScene = static_cast(scene())) pos += mapScene->absolutePositionForLayer(*mObject->objectGroup());