From 1112ca1731038f83607b292182bf964b0728fafc Mon Sep 17 00:00:00 2001 From: Jay <75145117+jcbk101@users.noreply.github.com> Date: Thu, 19 Feb 2026 06:08:28 -0500 Subject: [PATCH 1/3] Added per-object opacity (#4031) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now it is possible to control the opacity of individual objects. Co-authored-by: Thorbjørn Lindeijer --- NEWS.md | 1 + docs/reference/json-map-format.rst | 12 +++++++++- docs/reference/tmx-changelog.rst | 2 ++ docs/reference/tmx-map-format.rst | 2 ++ src/libtiled/mapobject.cpp | 7 ++++++ src/libtiled/mapobject.h | 25 +++++++++++++++++---- src/libtiled/mapreader.cpp | 6 +++++ src/libtiled/maptovariantconverter.cpp | 3 +++ src/libtiled/mapwriter.cpp | 4 ++++ src/libtiled/minimaprenderer.cpp | 5 ++++- src/libtiled/varianttomapconverter.cpp | 6 +++++ src/plugins/lua/luaplugin.cpp | 1 + src/plugins/python/pythonbind.cpp | 31 ++++++++++++++++++++++++++ src/plugins/python/tiledbinding.py | 2 ++ src/tiled/editablemapobject.cpp | 5 +++++ src/tiled/editablemapobject.h | 8 +++++++ src/tiled/mapobjectitem.cpp | 1 + src/tiled/propertieswidget.cpp | 16 +++++++++++++ src/tmxrasterizer/tmxrasterizer.cpp | 5 ++++- src/tmxviewer/tmxviewer.cpp | 1 + 20 files changed, 136 insertions(+), 7 deletions(-) diff --git a/NEWS.md b/NEWS.md index 8057430e32..f5fcc1412e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,7 @@ * Added support for lists in custom properties (#1493) * Added capsule object shape (by Jocelyn, #2153) * Added Oblique map orientation, skewing X and/or Y axis (#2917) +* Added support for per-object opacity (by jcbk101, #4031) * Allow filtering tilesets by name in the tileset dock (with dogboydog, #4239) * Allow changing the values of number inputs using expressions (with dogboydog, #4234) * Added support for SVG 1.2 / CSS blending modes to layers (#3932) diff --git a/docs/reference/json-map-format.rst b/docs/reference/json-map-format.rst index 7651e94246..dbb2824ba2 100644 --- a/docs/reference/json-map-format.rst +++ b/docs/reference/json-map-format.rst @@ -103,7 +103,7 @@ Layer objects, array, "Array of :ref:`objects `. ``objectgroup`` only." offsetx, double, "Horizontal layer offset in pixels (default: 0)" offsety, double, "Vertical layer offset in pixels (default: 0)" - opacity, double, "Value between 0 and 1" + opacity, double, "Value between 0 and 1 (default: 1)" parallaxx, double, "Horizontal :ref:`parallax factor ` for this layer (default: 1). (since 1.5)" parallaxy, double, "Vertical :ref:`parallax factor ` for this layer (default: 1). (since 1.5)" properties, array, "Array of :ref:`Properties `" @@ -241,6 +241,7 @@ Object height, double, "Height in pixels." id, int, "Incremental ID, unique across all objects" name, string, "String assigned to name field in editor" + opacity, double, "The opacity of the object as a value from 0 to 1 (default: 1)" point, bool, "Used to mark an object as a point" polygon, array, "Array of :ref:`Points `, in case the object is a polygon" polyline, array, "Array of :ref:`Points `, in case the object is a polyline" @@ -271,6 +272,7 @@ Object Example "value":12 }], "rotation":0, + "opacity":1, "type":"npc", "visible":true, "width":0, @@ -289,6 +291,7 @@ Ellipse Example "id":13, "name":"", "rotation":0, + "opacity":1, "type":"", "visible":true, "width":248, @@ -306,6 +309,7 @@ Rectangle Example "id":14, "name":"", "rotation":0, + "opacity":1, "type":"", "visible":true, "width":368, @@ -324,6 +328,7 @@ Point Example "name":"", "point":true, "rotation":0, + "opacity":1, "type":"", "visible":true, "width":0, @@ -362,6 +367,7 @@ Polygon Example "y":-288 }], "rotation":0, + "opacity":1, "type":"", "visible":true, "width":0, @@ -404,6 +410,7 @@ Polyline Example "y":0 }], "rotation":0, + "opacity":1, "type":"", "visible":true, "width":0, @@ -426,6 +433,7 @@ Text Example "wrap":true }, "rotation":0, + "opacity":1, "type":"", "visible":true, "width":248, @@ -774,6 +782,8 @@ Tiled 1.12 * Added ``capsule`` property to :ref:`json-object`. +* Added ``opacity`` property to :ref:`json-object`. + Tiled 1.11.1 ~~~~~~~~~~~~ diff --git a/docs/reference/tmx-changelog.rst b/docs/reference/tmx-changelog.rst index a05f370c76..e9df9a678c 100644 --- a/docs/reference/tmx-changelog.rst +++ b/docs/reference/tmx-changelog.rst @@ -22,6 +22,8 @@ Tiled 1.12 +- Added ``opacity`` attribute to :ref:`tmx-object` to specificy its opacity. + Tiled 1.10 ---------- diff --git a/docs/reference/tmx-map-format.rst b/docs/reference/tmx-map-format.rst index 96e1464210..a5c64c2453 100644 --- a/docs/reference/tmx-map-format.rst +++ b/docs/reference/tmx-map-format.rst @@ -556,6 +556,8 @@ Can contain any number: :ref:`tmx-object` - **height:** The height of the object in pixels. (defaults to 0) - **rotation:** The rotation of the object in degrees clockwise around (x, y). (defaults to 0) +- **opacity:** The opacity of the object as a value from 0 to 1. (defaults + to 1) - **gid:** A reference to a tile. (optional) - **visible:** Whether the object is shown (1) or hidden (0). (defaults to 1) diff --git a/src/libtiled/mapobject.cpp b/src/libtiled/mapobject.cpp index be157ed768..bd2f30a344 100644 --- a/src/libtiled/mapobject.cpp +++ b/src/libtiled/mapobject.cpp @@ -313,6 +313,7 @@ QVariant MapObject::mapObjectProperty(Property property) const case PositionProperty: return mPos; case SizeProperty: return mSize; case RotationProperty: return mRotation; + case OpacityProperty: return mOpacity; case CellProperty: Q_ASSERT(false); break; case ShapeProperty: return mShape; case TemplateProperty: Q_ASSERT(false); break; @@ -335,6 +336,7 @@ void MapObject::setMapObjectProperty(Property property, const QVariant &value) case PositionProperty: setPosition(value.toPointF()); break; case SizeProperty: setSize(value.toSizeF()); break; case RotationProperty: setRotation(value.toReal()); break; + case OpacityProperty: setOpacity(value.toReal()); break; case CellProperty: Q_ASSERT(false); break; case ShapeProperty: setShape(value.value()); break; case TemplateProperty: Q_ASSERT(false); break; @@ -375,6 +377,7 @@ MapObject *MapObject::clone() const o->setShape(mShape); o->setCell(mCell); o->setRotation(mRotation); + o->setOpacity(mOpacity); o->setVisible(mVisible); o->setChangedProperties(mChangedProperties); o->setObjectTemplate(mObjectTemplate); @@ -390,6 +393,7 @@ void MapObject::copyPropertiesFrom(const MapObject *object) setShape(object->shape()); setCell(object->cell()); setRotation(object->rotation()); + setOpacity(object->opacity()); setVisible(object->isVisible()); setProperties(object->properties()); setChangedProperties(object->changedProperties()); @@ -429,6 +433,9 @@ void MapObject::syncWithTemplate() if (!propertyChanged(MapObject::RotationProperty)) setRotation(base->rotation()); + if (!propertyChanged(MapObject::OpacityProperty)) + setOpacity(base->opacity()); + if (!propertyChanged(MapObject::VisibleProperty)) setVisible(base->isVisible()); } diff --git a/src/libtiled/mapobject.h b/src/libtiled/mapobject.h index 77f7b3e0d6..3b9173a47d 100644 --- a/src/libtiled/mapobject.h +++ b/src/libtiled/mapobject.h @@ -118,10 +118,11 @@ class TILEDSHARED_EXPORT MapObject : public Object PositionProperty = 1 << 7, SizeProperty = 1 << 8, RotationProperty = 1 << 9, - CellProperty = 1 << 10, - ShapeProperty = 1 << 11, - TemplateProperty = 1 << 12, - CustomProperties = 1 << 13, + OpacityProperty = 1 << 10, + CellProperty = 1 << 11, + ShapeProperty = 1 << 12, + TemplateProperty = 1 << 13, + CustomProperties = 1 << 14, AllProperties = 0xFF }; @@ -201,6 +202,9 @@ class TILEDSHARED_EXPORT MapObject : public Object qreal rotation() const; void setRotation(qreal rotation); + qreal opacity() const; + void setOpacity(qreal opacity); + Alignment alignment(const Map *map = nullptr) const; bool isVisible() const; @@ -248,6 +252,7 @@ class TILEDSHARED_EXPORT MapObject : public Object const ObjectTemplate *mObjectTemplate = nullptr; ObjectGroup *mObjectGroup = nullptr; qreal mRotation = 0.0; + qreal mOpacity = 1.0; bool mVisible = true; bool mTemplateBase = false; ChangedProperties mChangedProperties; @@ -480,6 +485,18 @@ inline qreal MapObject::rotation() const inline void MapObject::setRotation(qreal rotation) { mRotation = rotation; } +/** + * Returns the opacity of the object. + */ +inline qreal MapObject::opacity() const +{ return mOpacity; } + +/** + * Sets the opacity of the object. + */ +inline void MapObject::setOpacity(qreal opacity) +{ mOpacity = opacity; } + inline bool MapObject::isVisible() const { return mVisible; } diff --git a/src/libtiled/mapreader.cpp b/src/libtiled/mapreader.cpp index 2d0bad71d9..bb35f84299 100644 --- a/src/libtiled/mapreader.cpp +++ b/src/libtiled/mapreader.cpp @@ -1230,6 +1230,12 @@ std::unique_ptr MapReaderPrivate::readObject() object->setPropertyChanged(MapObject::RotationProperty); } + const qreal opacity = atts.value(QLatin1String("opacity")).toDouble(&ok); + if (ok) { + object->setOpacity(opacity); + object->setPropertyChanged(MapObject::OpacityProperty); + } + if (gid) { object->setCell(cellForGid(gid)); object->setPropertyChanged(MapObject::CellProperty); diff --git a/src/libtiled/maptovariantconverter.cpp b/src/libtiled/maptovariantconverter.cpp index fd3a451ae8..565ddca67e 100644 --- a/src/libtiled/maptovariantconverter.cpp +++ b/src/libtiled/maptovariantconverter.cpp @@ -591,6 +591,9 @@ QVariant MapToVariantConverter::toVariant(const MapObject &object) const if (notTemplateInstance || object.propertyChanged(MapObject::RotationProperty)) objectVariant[QStringLiteral("rotation")] = object.rotation(); + if (notTemplateInstance || object.propertyChanged(MapObject::OpacityProperty)) + objectVariant[QStringLiteral("opacity")] = object.opacity(); + if (notTemplateInstance || object.propertyChanged(MapObject::VisibleProperty)) objectVariant[QStringLiteral("visible")] = object.isVisible(); diff --git a/src/libtiled/mapwriter.cpp b/src/libtiled/mapwriter.cpp index 3d0e104a31..8b242f626f 100644 --- a/src/libtiled/mapwriter.cpp +++ b/src/libtiled/mapwriter.cpp @@ -765,6 +765,10 @@ void MapWriterPrivate::writeObject(QXmlStreamWriter &w, if (shouldWrite(rotation != 0.0, isTemplateInstance, mapObject.propertyChanged(MapObject::RotationProperty))) w.writeAttribute(QStringLiteral("rotation"), QString::number(rotation)); + const qreal opacity = mapObject.opacity(); + if (shouldWrite(opacity != 1.0, isTemplateInstance, mapObject.propertyChanged(MapObject::OpacityProperty))) + w.writeAttribute(QStringLiteral("opacity"), QString::number(opacity)); + if (shouldWrite(!mapObject.isVisible(), isTemplateInstance, mapObject.propertyChanged(MapObject::VisibleProperty))) w.writeAttribute(QStringLiteral("visible"), QLatin1String(mapObject.isVisible() ? "1" : "0")); diff --git a/src/libtiled/minimaprenderer.cpp b/src/libtiled/minimaprenderer.cpp index f99a43f9dc..3c0c253015 100644 --- a/src/libtiled/minimaprenderer.cpp +++ b/src/libtiled/minimaprenderer.cpp @@ -174,7 +174,8 @@ void MiniMapRenderer::renderToImage(QImage &image, RenderFlags renderFlags) cons const auto offset = layer->totalOffset(); const auto compositionMode = layer->compositionMode(); - painter.setOpacity(layer->effectiveOpacity()); + const auto layerOpacity = layer->effectiveOpacity(); + painter.setOpacity(layerOpacity); painter.translate(offset); switch (layer->layerType()) { @@ -211,6 +212,8 @@ void MiniMapRenderer::renderToImage(QImage &image, RenderFlags renderFlags) cons painter.translate(-origin); } + painter.setOpacity(layerOpacity * object->opacity()); + mRenderer->drawMapObject(&painter, object, object->effectiveColors()); if (object->rotation() != qreal(0)) diff --git a/src/libtiled/varianttomapconverter.cpp b/src/libtiled/varianttomapconverter.cpp index afede7ab43..96f4a833ea 100644 --- a/src/libtiled/varianttomapconverter.cpp +++ b/src/libtiled/varianttomapconverter.cpp @@ -756,6 +756,7 @@ std::unique_ptr VariantToMapConverter::toMapObject(const QVariantMap const qreal width = variantMap[QStringLiteral("width")].toReal(); const qreal height = variantMap[QStringLiteral("height")].toReal(); const qreal rotation = variantMap[QStringLiteral("rotation")].toReal(); + const qreal opacity = variantMap[QStringLiteral("opacity")].toReal(); QString className = variantMap[QStringLiteral("class")].toString(); if (className.isEmpty()) // fallback for compatibility @@ -772,6 +773,11 @@ std::unique_ptr VariantToMapConverter::toMapObject(const QVariantMap object->setPropertyChanged(MapObject::RotationProperty); } + if (variantMap.contains(QLatin1String("opacity"))) { + object->setOpacity(opacity); + object->setPropertyChanged(MapObject::OpacityProperty); + } + if (!templateVariant.isNull()) { // This object is a template instance QString templateFileName = resolvePath(mDir, templateVariant); auto objectTemplate = TemplateManager::instance()->loadObjectTemplate(templateFileName); diff --git a/src/plugins/lua/luaplugin.cpp b/src/plugins/lua/luaplugin.cpp index 101306eb11..5ad050f2de 100644 --- a/src/plugins/lua/luaplugin.cpp +++ b/src/plugins/lua/luaplugin.cpp @@ -737,6 +737,7 @@ void LuaWriter::writeMapObject(const Tiled::MapObject *mapObject) mWriter.writeKeyAndValue("width", mapObject->width()); mWriter.writeKeyAndValue("height", mapObject->height()); mWriter.writeKeyAndValue("rotation", mapObject->rotation()); + mWriter.writeKeyAndValue("opacity", mapObject->opacity()); if (!mapObject->cell().isEmpty()) mWriter.writeKeyAndValue("gid", mGidMapper.cellToGid(mapObject->cell())); diff --git a/src/plugins/python/pythonbind.cpp b/src/plugins/python/pythonbind.cpp index 52313f23f0..db6ead8770 100644 --- a/src/plugins/python/pythonbind.cpp +++ b/src/plugins/python/pythonbind.cpp @@ -6985,6 +6985,18 @@ _wrap_PyTiledMapObject_objectGroup(PyTiledMapObject *self, PyObject *PYBINDGEN_U } +PyObject * +_wrap_PyTiledMapObject_opacity(PyTiledMapObject *self, PyObject *PYBINDGEN_UNUSED(_args), PyObject *PYBINDGEN_UNUSED(_kwargs)) +{ + PyObject *py_retval; + double retval; + + retval = self->obj->opacity(); + py_retval = Py_BuildValue((char *) "d", retval); + return py_retval; +} + + PyObject * _wrap_PyTiledMapObject_rotation(PyTiledMapObject *self, PyObject *PYBINDGEN_UNUSED(_args), PyObject *PYBINDGEN_UNUSED(_kwargs)) { @@ -7049,6 +7061,23 @@ _wrap_PyTiledMapObject_setName(PyTiledMapObject *self, PyObject *args, PyObject } +PyObject * +_wrap_PyTiledMapObject_setOpacity(PyTiledMapObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *py_retval; + double opacity; + const char *keywords[] = {"opacity", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "d", (char **) keywords, &opacity)) { + return NULL; + } + self->obj->setOpacity(opacity); + Py_INCREF(Py_None); + py_retval = Py_None; + return py_retval; +} + + PyObject * _wrap_PyTiledMapObject_setPosition(PyTiledMapObject *self, PyObject *args, PyObject *kwargs) { @@ -7271,10 +7300,12 @@ static PyMethodDef PyTiledMapObject_methods[] = { {(char *) "isVisible", (PyCFunction) _wrap_PyTiledMapObject_isVisible, METH_NOARGS, "isVisible()\n\n" }, {(char *) "name", (PyCFunction) _wrap_PyTiledMapObject_name, METH_NOARGS, "name()\n\n" }, {(char *) "objectGroup", (PyCFunction) _wrap_PyTiledMapObject_objectGroup, METH_NOARGS, "objectGroup()\n\n" }, + {(char *) "opacity", (PyCFunction) _wrap_PyTiledMapObject_opacity, METH_NOARGS, "opacity()\n\n" }, {(char *) "rotation", (PyCFunction) _wrap_PyTiledMapObject_rotation, METH_NOARGS, "rotation()\n\n" }, {(char *) "setCell", (PyCFunction) _wrap_PyTiledMapObject_setCell, METH_KEYWORDS|METH_VARARGS, "setCell(c)\n\ntype: c: Tiled::Cell const" }, {(char *) "setHeight", (PyCFunction) _wrap_PyTiledMapObject_setHeight, METH_KEYWORDS|METH_VARARGS, "setHeight(h)\n\ntype: h: double" }, {(char *) "setName", (PyCFunction) _wrap_PyTiledMapObject_setName, METH_KEYWORDS|METH_VARARGS, "setName(n)\n\ntype: n: QString" }, + {(char *) "setOpacity", (PyCFunction) _wrap_PyTiledMapObject_setOpacity, METH_KEYWORDS|METH_VARARGS, "setOpacity(opacity)\n\ntype: opacity: double" }, {(char *) "setPosition", (PyCFunction) _wrap_PyTiledMapObject_setPosition, METH_KEYWORDS|METH_VARARGS, "setPosition(pos)\n\ntype: pos: QPointF" }, {(char *) "setRotation", (PyCFunction) _wrap_PyTiledMapObject_setRotation, METH_KEYWORDS|METH_VARARGS, "setRotation(r)\n\ntype: r: double" }, {(char *) "setShape", (PyCFunction) _wrap_PyTiledMapObject_setShape, METH_KEYWORDS|METH_VARARGS, "setShape(s)\n\ntype: s: Tiled::MapObject::Shape" }, diff --git a/src/plugins/python/tiledbinding.py b/src/plugins/python/tiledbinding.py index 2901f270aa..084e11a065 100755 --- a/src/plugins/python/tiledbinding.py +++ b/src/plugins/python/tiledbinding.py @@ -280,6 +280,8 @@ def _decorate(obj, *args, **kwargs): cls_mapobject.add_method('objectGroup', retval('Tiled::ObjectGroup*',reference_existing_object=True), []) cls_mapobject.add_method('rotation', 'double', []) cls_mapobject.add_method('setRotation', None, [('double','r')]) +cls_mapobject.add_method('opacity', 'double', []) +cls_mapobject.add_method('setOpacity', None, [('double','opacity')]) cls_mapobject.add_method('isVisible', 'bool', []) cls_mapobject.add_method('setVisible', None, [('bool','v')]) cls_mapobject.add_method('name', 'QString', []) diff --git a/src/tiled/editablemapobject.cpp b/src/tiled/editablemapobject.cpp index 23e67ec53f..537432176f 100644 --- a/src/tiled/editablemapobject.cpp +++ b/src/tiled/editablemapobject.cpp @@ -190,6 +190,11 @@ void EditableMapObject::setRotation(qreal rotation) setMapObjectProperty(MapObject::RotationProperty, rotation); } +void EditableMapObject::setOpacity(qreal opacity) +{ + setMapObjectProperty(MapObject::OpacityProperty, opacity); +} + void EditableMapObject::setVisible(bool visible) { setMapObjectProperty(MapObject::VisibleProperty, visible); diff --git a/src/tiled/editablemapobject.h b/src/tiled/editablemapobject.h index 001f28b12a..3689858f50 100644 --- a/src/tiled/editablemapobject.h +++ b/src/tiled/editablemapobject.h @@ -63,6 +63,7 @@ class EditableMapObject : public EditableObject Q_PROPERTY(qreal height READ height WRITE setHeight) Q_PROPERTY(QSizeF size READ size WRITE setSize) Q_PROPERTY(qreal rotation READ rotation WRITE setRotation) + Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity) Q_PROPERTY(bool visible READ isVisible WRITE setVisible) Q_PROPERTY(QJSValue polygon READ polygon WRITE setPolygon) Q_PROPERTY(QString text READ text WRITE setText) @@ -115,6 +116,7 @@ class EditableMapObject : public EditableObject qreal height() const; QSizeF size() const; qreal rotation() const; + qreal opacity() const; bool isVisible() const; QJSValue polygon() const; QString text() const; @@ -150,6 +152,7 @@ public slots: void setHeight(qreal height); void setSize(QSizeF size); void setRotation(qreal rotation); + void setOpacity(qreal opacity); void setVisible(bool visible); void setPolygon(QJSValue polygon); void setPolygon(const QPolygonF &polygon); @@ -220,6 +223,11 @@ inline qreal EditableMapObject::rotation() const return mapObject()->rotation(); } +inline qreal EditableMapObject::opacity() const +{ + return mapObject()->opacity(); +} + inline bool EditableMapObject::isVisible() const { return mapObject()->isVisible(); diff --git a/src/tiled/mapobjectitem.cpp b/src/tiled/mapobjectitem.cpp index 8219f5f3a2..3816d0a999 100644 --- a/src/tiled/mapobjectitem.cpp +++ b/src/tiled/mapobjectitem.cpp @@ -89,6 +89,7 @@ void MapObjectItem::syncWithMapObject() setPos(pixelPos); setRotation(mObject->rotation()); + setOpacity(mObject->opacity()); if (mBoundingRect != bounds) { // Notify the graphics scene about the geometry change in advance diff --git a/src/tiled/propertieswidget.cpp b/src/tiled/propertieswidget.cpp index 2c4c807f50..cbb8510af7 100644 --- a/src/tiled/propertieswidget.cpp +++ b/src/tiled/propertieswidget.cpp @@ -1630,6 +1630,17 @@ class MapObjectProperties : public ObjectProperties }); mVisibleProperty->setNameOnCheckBox(true); + mOpacityProperty = new IntProperty( + tr("Opacity"), + [this] { return qRound(mapObject()->opacity() * 100); }, + [this](const int &value) { + changeMapObject(MapObject::OpacityProperty, + qreal(value) / 100); + }); + mOpacityProperty->setRange(0, 100); + mOpacityProperty->setSuffix(tr("%")); + mOpacityProperty->setSliderEnabled(true); + mPositionProperty = new PointFProperty( tr("Position"), [this] { @@ -1799,6 +1810,8 @@ class MapObjectProperties : public ObjectProperties if (mapDocument()->allowHidingObjects()) mObjectProperties->addProperty(mVisibleProperty); + mObjectProperties->addProperty(mOpacityProperty); + if (mapObject()->hasDimensions()) mObjectProperties->addProperty(mBoundsProperty); else @@ -1843,6 +1856,8 @@ class MapObjectProperties : public ObjectProperties emit mNameProperty->valueChanged(); if (change.properties & MapObject::VisibleProperty) emit mVisibleProperty->valueChanged(); + if (change.properties & MapObject::OpacityProperty) + emit mOpacityProperty->valueChanged(); if (change.properties & MapObject::PositionProperty) { emit mPositionProperty->valueChanged(); emit mBoundsProperty->valueChanged(); @@ -1920,6 +1935,7 @@ class MapObjectProperties : public ObjectProperties Property *mTemplateProperty; Property *mNameProperty; BoolProperty *mVisibleProperty; + IntProperty *mOpacityProperty; Property *mPositionProperty; Property *mBoundsProperty; FloatProperty *mRotationProperty; diff --git a/src/tmxrasterizer/tmxrasterizer.cpp b/src/tmxrasterizer/tmxrasterizer.cpp index f731feb6c3..91191ad838 100644 --- a/src/tmxrasterizer/tmxrasterizer.cpp +++ b/src/tmxrasterizer/tmxrasterizer.cpp @@ -60,7 +60,8 @@ void TmxRasterizer::drawMapLayers(const MapRenderer &renderer, const auto offset = layer->totalOffset() + mapOffset; const auto compositionMode = layer->compositionMode(); - painter.setOpacity(layer->effectiveOpacity()); + const auto layerOpacity = layer->effectiveOpacity(); + painter.setOpacity(layerOpacity); painter.translate(offset); switch (layer->layerType()) { @@ -90,6 +91,8 @@ void TmxRasterizer::drawMapLayers(const MapRenderer &renderer, painter.translate(-origin); } + painter.setOpacity(layerOpacity * object->opacity()); + renderer.drawMapObject(&painter, object, object->effectiveColors()); if (object->rotation() != qreal(0)) diff --git a/src/tmxviewer/tmxviewer.cpp b/src/tmxviewer/tmxviewer.cpp index e00ea748ef..4a741fc83f 100644 --- a/src/tmxviewer/tmxviewer.cpp +++ b/src/tmxviewer/tmxviewer.cpp @@ -65,6 +65,7 @@ class MapObjectItem : public QGraphicsItem setPos(pixelPos); setRotation(mapObject->rotation()); + setOpacity(mapObject->opacity()); } QRectF boundingRect() const override From bf8788caad1be0ec9003041d2b471076c407af20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Thu, 19 Feb 2026 12:10:59 +0100 Subject: [PATCH 2/3] AppImage: Updated to Sentry 0.12.8 (#4333) --- .github/workflows/packages.yml | 2 +- NEWS.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/packages.yml b/.github/workflows/packages.yml index 96330ebdbe..813d1d83db 100644 --- a/.github/workflows/packages.yml +++ b/.github/workflows/packages.yml @@ -21,7 +21,7 @@ on: env: QBS_VERSION: 2.4.1 CMAKE_VERSION: 3.31 - SENTRY_VERSION: 0.7.19 + SENTRY_VERSION: 0.12.8 SENTRY_ORG: mapeditor SENTRY_PROJECT: tiled TILED_RELEASE: ${{ startsWith(github.ref, 'refs/tags/v') }} diff --git a/NEWS.md b/NEWS.md index f5fcc1412e..7b9f2bc72a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -31,6 +31,7 @@ * macOS: Fixed crash when JS code is JIT-compiled (#4218) * Workaround tileset view layout regression in Qt 6.9 * Raised minimum supported Qt version from 5.12 to 5.15.2 +* AppImage: Updated to Sentry 0.12.8 ### Tiled 1.11.2 (28 Jan 2025) From b02fc9e6d647d9d28621c86ecce3a98898c33141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Thu, 19 Feb 2026 12:51:13 +0100 Subject: [PATCH 3/3] Python plugin: Fixed tiledbinding.py for Python 3.14 (#4335) * Some \s in a regular expression that was part of a string was causing the compiler to complain about invalid escape character. * Shape enum was missing Capsule. --- src/plugins/python/qtbinding.py | 2 +- src/plugins/python/tiledbinding.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/python/qtbinding.py b/src/plugins/python/qtbinding.py index c2d4b42f9d..ed3dcafae4 100644 --- a/src/plugins/python/qtbinding.py +++ b/src/plugins/python/qtbinding.py @@ -23,7 +23,7 @@ import pybindgen.typehandlers.base as typehandlers from pybindgen.typehandlers.base import ForwardWrapperBase, PointerParameter -""" +r""" class QFlagsTransformation(typehandlers.TypeTransformation): def __init__(self): self.rx = re.compile(r'(?:::)?QFlags<\s*(\w+)\s*>') diff --git a/src/plugins/python/tiledbinding.py b/src/plugins/python/tiledbinding.py index 084e11a065..452cb26676 100755 --- a/src/plugins/python/tiledbinding.py +++ b/src/plugins/python/tiledbinding.py @@ -258,7 +258,7 @@ def _decorate(obj, *args, **kwargs): cls_mapobject.add_constructor([]) cls_mapobject.add_constructor([('QString','name'), ('QString','type'), ('QPointF','pos'), ('QSizeF','size') ]) -cls_mapobject.add_enum('Shape', ('Rectangle','Polygon','Polyline','Ellipse','Text','Point')) +cls_mapobject.add_enum('Shape', ('Rectangle','Polygon','Polyline','Ellipse','Capsule','Text','Point')) cls_mapobject.add_method('setPosition', None, [('QPointF','pos')]) cls_mapobject.add_method('x', 'double', []) cls_mapobject.add_method('setX', None, [('double','x')])