Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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') }}
Expand Down
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -30,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)

Expand Down
12 changes: 11 additions & 1 deletion docs/reference/json-map-format.rst
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ Layer
objects, array, "Array of :ref:`objects <json-object>`. ``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 <parallax-factor>` for this layer (default: 1). (since 1.5)"
parallaxy, double, "Vertical :ref:`parallax factor <parallax-factor>` for this layer (default: 1). (since 1.5)"
properties, array, "Array of :ref:`Properties <json-property>`"
Expand Down Expand Up @@ -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 <json-point>`, in case the object is a polygon"
polyline, array, "Array of :ref:`Points <json-point>`, in case the object is a polyline"
Expand Down Expand Up @@ -271,6 +272,7 @@ Object Example
"value":12
}],
"rotation":0,
"opacity":1,
"type":"npc",
"visible":true,
"width":0,
Expand All @@ -289,6 +291,7 @@ Ellipse Example
"id":13,
"name":"",
"rotation":0,
"opacity":1,
"type":"",
"visible":true,
"width":248,
Expand All @@ -306,6 +309,7 @@ Rectangle Example
"id":14,
"name":"",
"rotation":0,
"opacity":1,
"type":"",
"visible":true,
"width":368,
Expand All @@ -324,6 +328,7 @@ Point Example
"name":"",
"point":true,
"rotation":0,
"opacity":1,
"type":"",
"visible":true,
"width":0,
Expand Down Expand Up @@ -362,6 +367,7 @@ Polygon Example
"y":-288
}],
"rotation":0,
"opacity":1,
"type":"",
"visible":true,
"width":0,
Expand Down Expand Up @@ -404,6 +410,7 @@ Polyline Example
"y":0
}],
"rotation":0,
"opacity":1,
"type":"",
"visible":true,
"width":0,
Expand All @@ -426,6 +433,7 @@ Text Example
"wrap":true
},
"rotation":0,
"opacity":1,
"type":"",
"visible":true,
"width":248,
Expand Down Expand Up @@ -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
~~~~~~~~~~~~

Expand Down
2 changes: 2 additions & 0 deletions docs/reference/tmx-changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ Tiled 1.12
<capsule/>
</object>

- Added ``opacity`` attribute to :ref:`tmx-object` to specificy its opacity.


Tiled 1.10
----------
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/tmx-map-format.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
7 changes: 7 additions & 0 deletions src/libtiled/mapobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<Shape>()); break;
case TemplateProperty: Q_ASSERT(false); break;
Expand Down Expand Up @@ -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);
Expand All @@ -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());
Expand Down Expand Up @@ -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());
}
Expand Down
25 changes: 21 additions & 4 deletions src/libtiled/mapobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
};

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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; }

Expand Down
6 changes: 6 additions & 0 deletions src/libtiled/mapreader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1230,6 +1230,12 @@ std::unique_ptr<MapObject> 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);
Expand Down
3 changes: 3 additions & 0 deletions src/libtiled/maptovariantconverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
4 changes: 4 additions & 0 deletions src/libtiled/mapwriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"));

Expand Down
5 changes: 4 additions & 1 deletion src/libtiled/minimaprenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down Expand Up @@ -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))
Expand Down
6 changes: 6 additions & 0 deletions src/libtiled/varianttomapconverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,7 @@ std::unique_ptr<MapObject> 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
Expand All @@ -772,6 +773,11 @@ std::unique_ptr<MapObject> 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);
Expand Down
1 change: 1 addition & 0 deletions src/plugins/lua/luaplugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()));
Expand Down
31 changes: 31 additions & 0 deletions src/plugins/python/pythonbind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
{
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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" },
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/python/qtbinding.py
Original file line number Diff line number Diff line change
Expand Up @@ -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*>')
Expand Down
4 changes: 3 additions & 1 deletion src/plugins/python/tiledbinding.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')])
Expand All @@ -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', [])
Expand Down
5 changes: 5 additions & 0 deletions src/tiled/editablemapobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading