Skip to content

Commit

Permalink
Use Q_GADGET to avoid needing to wrap things in QObject instances
Browse files Browse the repository at this point in the history
Now QVector<WorldMapEntry> and QVector<WorldPattern> can be exposed to
JS directly. This only works with Qt 6 (tested with 5.15, 6.5 and 6.6),
but I don't think it's worth supporting these properties for Qt 5
builds.

Also removed World.displayName, since I think this was just a
convenience member which isn't very useful to add to the scripting API.
In the end it was just returning the file name part of the path returned
by World.fileName.

Improved the documentation in a few places.
  • Loading branch information
bjorn committed Jan 17, 2024
1 parent 64d7580 commit 49288cf
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 148 deletions.
66 changes: 40 additions & 26 deletions docs/scripting-doc/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1132,14 +1132,16 @@ declare class Project extends TiledObject {
}

/**
* Details of a map that is added to a {@link World},
* Details of a map that is added to a {@link World}.
*
* @since 1.10.x TODO
*/
declare class WorldMapEntry {
/**
* File name of the map.
*/
fileName : string;

/**
* A rect describing the location and dimensions of the map within the World.
*/
Expand All @@ -1148,75 +1150,87 @@ declare class WorldMapEntry {

/**
* Patterns added to a {@link World}, which are used to automatically match
* maps.
* https://doc.mapeditor.org/en/stable/manual/worlds/#using-pattern-matching
* maps. See the [Using Pattern
* Matching](https://doc.mapeditor.org/en/stable/manual/worlds/#using-pattern-matching)
* section in the manual for more information.
*
* @since 1.10.x TODO
*/
declare class WorldPattern {
/**
* String version of the regular expression pattern used
* The regular expression pattern used to match maps in the world.
*/
regExp: string;
regExp: RegExp;

/**
* Multiplied by the first number (x) in the regular expression to determine
* the map's position in the world.
*/
*/
multiplierX: number;

/**
* Multiplied by the second number (y) in the regular expression to determine
* the map's position in the world.
*/
multiplierY: number;

/**
* After calculating the map's position in the world using x and y in its
* regular expression and the associated multipliers, this offset is added
* to determine the final position.
*/
offset: point;

/**
* Used to support showing only directly neighboring maps when a world is loaded.
* For more information, see the Showing Only Direct Neighbors section of this page:
* https://doc.mapeditor.org/en/stable/manual/worlds/#using-pattern-matching
* The size of the map in pixels.
*
* Used to support showing only directly neighboring maps when a world is
* loaded. For more information, see the [Showing Only Direct
* Neighbors](https://doc.mapeditor.org/en/stable/manual/worlds/#showing-only-direct-neighbors)
* section in the manual.
*/
mapSize: size;
}

/**
* A world defined in a .world file, which is a JSON file that tells
* Tiled which maps are part of the world and at what location.
* https://doc.mapeditor.org/en/stable/manual/worlds/
*
* See the [Working with
* Worlds](https://doc.mapeditor.org/en/stable/manual/worlds/) page in the
* manual for more information.
*
* @since 1.10.x TODO
*/
declare class World extends TiledObject {
/**
* Returns maps that are explicitly added to this world. It does
* not include those maps which match due to patterns defined on the world.
* The maps that are explicitly added to this world. It does not include
* those maps which match due to patterns defined on the world.
*/
maps() : WorldMapEntry[];
readonly maps : WorldMapEntry[];

/**
* Returns the list of patterns that are configured for this map.
* The patterns will be used to automatically match maps in your project.
* The patterns that are configured for this map. These patterns will be used
* to automatically match maps in your project.
*/
patterns(): WorldPattern[];
readonly patterns : WorldPattern[];

/**
* Returns all maps that are added to this World.
* Returns all maps that are part of this world, either directly referenced
* or matched by one of the patterns.
*/
allMaps() : WorldMapEntry[];

/**
* Return any maps that intersect with the given {@link rect} .
* @param rect - the rect used to
* Returns any maps that intersect with the given {@link rect}. This is a
* filtered version of the results from {@link allMaps}.
*/
mapsInRect(rect : rect) : WorldMapEntry[];
/**
* Returns true if this World contains the map specified in fileName.
* @param fileName filename of the map
*/
containsMap(fileName : string) : boolean;

/**
* The display name of the World.
* Returns true if this world contains the map specified in fileName.
*/
displayName: string;
containsMap(fileName : string) : boolean;
}

/**
Expand Down
36 changes: 19 additions & 17 deletions src/libtiled/world.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ void World::removeMap(int mapIndex)

void World::addMap(const QString &fileName, const QRect &rect)
{
MapEntry entry;
WorldMapEntry entry;
entry.rect = rect;
entry.fileName = fileName;
maps.append(entry);
Expand All @@ -76,7 +76,7 @@ int World::mapIndex(const QString &fileName) const

bool World::containsMap(const QString &fileName) const
{
for (const World::MapEntry &mapEntry : maps) {
for (const WorldMapEntry &mapEntry : maps) {
if (mapEntry.fileName == fileName)
return true;
}
Expand All @@ -87,7 +87,7 @@ bool World::containsMap(const QString &fileName) const
if (QFileInfo(this->fileName).path() != QFileInfo(fileName).path())
return false;

for (const World::Pattern &pattern : patterns) {
for (const WorldPattern &pattern : patterns) {
QRegularExpressionMatch match = pattern.regexp.match(fileName);
if (match.hasMatch())
return true;
Expand All @@ -98,12 +98,12 @@ bool World::containsMap(const QString &fileName) const

QRect World::mapRect(const QString &fileName) const
{
for (const World::MapEntry &mapEntry : maps) {
for (const WorldMapEntry &mapEntry : maps) {
if (mapEntry.fileName == fileName)
return mapEntry.rect;
}

for (const World::Pattern &pattern : patterns) {
for (const WorldPattern &pattern : patterns) {
QRegularExpressionMatch match = pattern.regexp.match(fileName);
if (match.hasMatch()) {
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
Expand All @@ -123,15 +123,15 @@ QRect World::mapRect(const QString &fileName) const
return QRect();
}

QVector<World::MapEntry> World::allMaps() const
QVector<WorldMapEntry> World::allMaps() const
{
QVector<World::MapEntry> all(maps);
QVector<WorldMapEntry> all(maps);

if (!patterns.isEmpty()) {
const QDir dir(QFileInfo(fileName).dir());
const QStringList entries = dir.entryList(QDir::Files | QDir::Readable);

for (const World::Pattern &pattern : patterns) {
for (const WorldPattern &pattern : patterns) {
for (const QString &fileName : entries) {
QRegularExpressionMatch match = pattern.regexp.match(fileName);
if (match.hasMatch()) {
Expand All @@ -143,7 +143,7 @@ QVector<World::MapEntry> World::allMaps() const
const int y = match.capturedRef(2).toInt();
#endif

MapEntry entry;
WorldMapEntry entry;
entry.fileName = dir.filePath(fileName);
entry.rect = QRect(QPoint(x * pattern.multiplierX,
y * pattern.multiplierY) + pattern.offset,
Expand All @@ -157,18 +157,18 @@ QVector<World::MapEntry> World::allMaps() const
return all;
}

QVector<World::MapEntry> World::mapsInRect(const QRect &rect) const
QVector<WorldMapEntry> World::mapsInRect(const QRect &rect) const
{
QVector<World::MapEntry> maps(allMaps());
QVector<WorldMapEntry> maps(allMaps());

maps.erase(std::remove_if(maps.begin(), maps.end(),
[&](const World::MapEntry &mapEntry) { return !mapEntry.rect.intersects(rect); }),
[&](const WorldMapEntry &mapEntry) { return !mapEntry.rect.intersects(rect); }),
maps.end());

return maps;
}

QVector<World::MapEntry> World::contextMaps(const QString &fileName) const
QVector<WorldMapEntry> World::contextMaps(const QString &fileName) const
{
if (onlyShowAdjacentMaps)
return mapsInRect(mapRect(fileName).adjusted(-1, -1, 1, 1));
Expand All @@ -184,7 +184,7 @@ QString World::firstMap() const
const QDir dir(QFileInfo(fileName).dir());
const QStringList entries = dir.entryList(QDir::Files | QDir::Readable);

for (const World::Pattern &pattern : patterns) {
for (const WorldPattern &pattern : patterns) {
for (const QString &fileName : entries) {
QRegularExpressionMatch match = pattern.regexp.match(fileName);
if (match.hasMatch())
Expand Down Expand Up @@ -277,7 +277,7 @@ std::unique_ptr<World> World::load(const QString &fileName,
for (const QJsonValue &value : maps) {
const QJsonObject mapObject = value.toObject();

World::MapEntry map;
WorldMapEntry map;
map.fileName = QDir::cleanPath(dir.filePath(mapObject.value(QLatin1String("fileName")).toString()));
map.rect = QRect(mapObject.value(QLatin1String("x")).toInt(),
mapObject.value(QLatin1String("y")).toInt(),
Expand All @@ -291,7 +291,7 @@ std::unique_ptr<World> World::load(const QString &fileName,
for (const QJsonValue &value : patterns) {
const QJsonObject patternObject = value.toObject();

World::Pattern pattern;
WorldPattern pattern;
pattern.regexp.setPattern(patternObject.value(QLatin1String("regexp")).toString());
pattern.multiplierX = patternObject.value(QLatin1String("multiplierX")).toInt(1);
pattern.multiplierY = patternObject.value(QLatin1String("multiplierY")).toInt(1);
Expand Down Expand Up @@ -327,7 +327,7 @@ bool World::save(World &world, QString *errorString)
const QDir worldDir = QFileInfo(world.fileName).dir();

QJsonArray maps;
for (const World::MapEntry& map : std::as_const(world.maps)) {
for (const WorldMapEntry &map : std::as_const(world.maps)) {
QJsonObject jsonMap;

const QString relativeFileName = QDir::cleanPath(worldDir.relativeFilePath(map.fileName));
Expand Down Expand Up @@ -363,3 +363,5 @@ bool World::save(World &world, QString *errorString)
}

} // namespace Tiled

#include "moc_world.cpp"
57 changes: 36 additions & 21 deletions src/libtiled/world.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,31 +41,44 @@

namespace Tiled {

class TILEDSHARED_EXPORT WorldMapEntry
{
Q_GADGET
Q_PROPERTY(QString fileName MEMBER fileName)
Q_PROPERTY(QRect rect MEMBER rect)

public:
QString fileName;
QRect rect;
};

class TILEDSHARED_EXPORT WorldPattern
{
Q_GADGET
Q_PROPERTY(QRegularExpression regExp MEMBER regexp);
Q_PROPERTY(int multiplierX MEMBER multiplierX);
Q_PROPERTY(int multiplierY MEMBER multiplierY);
Q_PROPERTY(QPoint offset MEMBER offset);
Q_PROPERTY(QSize mapSize MEMBER mapSize);

public:
QRegularExpression regexp;
int multiplierX;
int multiplierY;
QPoint offset;
QSize mapSize;
};

class TILEDSHARED_EXPORT World : public Object
{
Q_DECLARE_TR_FUNCTIONS(Tiled::WorldManager);

public:
World() : Object(WorldType) {}

struct Pattern
{
QRegularExpression regexp;
int multiplierX;
int multiplierY;
QPoint offset;
QSize mapSize;
};

struct MapEntry
{
QString fileName;
QRect rect;
};

QString fileName;
QVector<MapEntry> maps;
QVector<Pattern> patterns;
QVector<WorldMapEntry> maps;
QVector<WorldPattern> patterns;
bool onlyShowAdjacentMaps = false;
bool hasUnsavedChanges = false;

Expand All @@ -75,9 +88,9 @@ class TILEDSHARED_EXPORT World : public Object
void removeMap(int mapIndex);
bool containsMap(const QString &fileName) const;
QRect mapRect(const QString &fileName) const;
QVector<MapEntry> allMaps() const;
QVector<MapEntry> mapsInRect(const QRect &rect) const;
QVector<MapEntry> contextMaps(const QString &fileName) const;
QVector<WorldMapEntry> allMaps() const;
QVector<WorldMapEntry> mapsInRect(const QRect &rect) const;
QVector<WorldMapEntry> contextMaps(const QString &fileName) const;
QString firstMap() const;

void error(const QString &message) const;
Expand All @@ -99,5 +112,7 @@ class TILEDSHARED_EXPORT World : public Object
QString *errorString = nullptr);
};


} // namespace Tiled

Q_DECLARE_METATYPE(Tiled::WorldPattern)
Q_DECLARE_METATYPE(Tiled::WorldMapEntry)
2 changes: 1 addition & 1 deletion src/tiled/changeworld.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ void RemoveMapCommand::redo()
DocumentManager *manager = DocumentManager::instance();
if (manager->currentDocument() && manager->currentDocument()->fileName() == mMapName) {
const World *world = WorldManager::instance().worldForMap(mMapName);
for (const World::MapEntry &entry : world->allMaps()) {
for (const WorldMapEntry &entry : world->allMaps()) {
if (entry.fileName != mMapName) {
manager->switchToDocument(entry.fileName);
break;
Expand Down
Loading

0 comments on commit 49288cf

Please sign in to comment.