Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Give scripts access to existing file formats #2716

Merged
merged 12 commits into from
Jan 7, 2020
95 changes: 95 additions & 0 deletions docs/reference/scripting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@ Properties
**openAssets** : array |ro|, "List of currently opened :ref:`assets <script-asset>`."
**mapEditor** : :ref:`script-mapeditor`, "Access the editor used when editing maps."
**tilesetEditor** : :ref:`script-tileseteditor`, "Access the editor used when editing tilesets."
**tilesetFormats** : [string] |ro|, "List of supported tileset format names. Use
:ref:`tilesetFormat <script-tilesetFormat>` to get the corresponding format object
to read and write files. (Since 1.4)"
**mapFormats** : [string] |ro|, "List of supported map format names. Use
:ref:`mapFormat <script-mapFormat>` to get the corresponding format object to
read and write files. (Since 1.4)"

Functions
~~~~~~~~~
Expand Down Expand Up @@ -432,6 +438,31 @@ tiled.extendMenu(id : string, items : array | object) : void
The "CustomAction" will need to have been registered before using
:ref:`tiled.registerAction() <script-registerAction>`.


.. _script-tilesetFormat:

tiled.tilesetFormat(shortName : string) : :ref:`script-tilesetformatwrapper`
Returns the tileset format object with the given name, or `undefined` if
no object was found. See the `tilesetFormats` property for more info.

.. _script-tilesetFormatForFile:

tiled.tilesetFormatForFile(fileName : string) : :ref:`script-tilesetformatwrapper`
Returns the tileset format object that can read the given file, or `undefined`
if no object was found.

.. _script-mapFormat:

tiled.mapFormat(shortName : string) : :ref:`script-mapformatwrapper`
Returns the map format object with the given name, or `undefined` if no object
was found. See the `mapFormats` property for more info.

.. _script-mapFormatForFile:

tiled.mapFormatForFile(fileName : string) : :ref:`script-mapformatwrapper`
Returns the map format object that can read the given file, or `undefined` if
no object was found.

.. _script-tiled-signals:

Signals
Expand Down Expand Up @@ -537,6 +568,28 @@ Asset.macro(text : string, callback : function) : value

The returned value is whatever the callback function returned.

.. _script-fileformat:

File Format
^^^^^^^^^^^

Common functionality for file format readers and writers. (Since 1.4)

Properties
~~~~~~~~~~

.. csv-table::
widths: 1, 2

**canRead** : bool |ro|, Whether this format supports reading files.
**canWrite** : bool |ro|, Whether this format supports writing files.

Functions
~~~~~~~~~

FileFormat.supportsFile(fileName : string) : bool
Returns whether the file is readable by this format.

.. _script-grouplayer:

GroupLayer
Expand Down Expand Up @@ -690,6 +743,27 @@ Properties
**currentMapView** : :ref:`script-mapview` |ro|, "Access the current map view."
**tilesetsView** : :ref:`script-tilesetsview` |ro|, "Access the Tilesets view."

.. _script-mapformatwrapper:

Map Format
^^^^^^^^^^

This is an object that can read or write map files. (Since 1.4)

Inherits :ref:`script-fileformat`.

Functions
~~~~~~~~~

MapFormat.read(fileName : string) : :ref:`script-map`
Read the given file as a map. This function will throw an error if it
is not supported.

MapFormat.write(map : :ref:`script-map`, fileName : string) : string
Write the given map to a file. This function will throw an error if it
is not supported. If there is an error writing the file, it will return a
description of the error; otherwise, it will return "".

.. _script-mapview:

Map View
Expand Down Expand Up @@ -1296,6 +1370,27 @@ Properties

**collisionEditor** : :ref:`script-tilecollisioneditor`, "Access the collision editor within the tileset editor."

.. _script-tilesetformatwrapper:

Tileset Format
^^^^^^^^^^^^^^

This is an object that can read or write tileset files. (Since 1.4)

Inherits :ref:`script-fileformat`.

Functions
~~~~~~~~~

TilesetFormat.read(fileName : string) : :ref:`script-tileset`
Read the given file as a tileset. This function will throw an error if it
is not supported.

TilesetFormat.write(tileset : :ref:`script-tileset`, fileName : string) : string
Write the given tileset to a file. This function will throw an error if it
is not supported. If there is an error writing the file, it will return a
description of the error; otherwise, it will return "".

.. _script-tilesetsview:

Tilesets View
Expand Down
135 changes: 135 additions & 0 deletions src/tiled/scriptfileformatwrappers.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
* scriptfileformatwrappers.h
* Copyright 2019, Phlosioneer <mattmdrr2@gmail.com>
*
* This file is part of Tiled.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "scriptfileformatwrappers.h"

#include "editablemap.h"
#include "editabletileset.h"
#include "mapformat.h"
#include "scriptedfileformat.h"
#include "scriptmanager.h"
#include "tilesetformat.h"

#include <QCoreApplication>
#include <QQmlEngine>

namespace Tiled {

ScriptFileFormatWrapper::ScriptFileFormatWrapper(FileFormat *format, QObject *parent)
: QObject(parent),
mFormat(format)
{}

bool ScriptFileFormatWrapper::supportsFile(const QString &filename) const
{
return mFormat->supportsFile(filename);
}

bool ScriptFileFormatWrapper::canRead() const
{
return mFormat->capabilities() & FileFormat::Read;
}

bool ScriptFileFormatWrapper::canWrite() const
{
return mFormat->capabilities() & FileFormat::Write;
}

bool ScriptFileFormatWrapper::assertCanRead() const
{
if (canRead())
return true;
auto message = QCoreApplication::translate("Script Errors", "File format doesn't support `read`");
ScriptManager::instance().throwError(message);
return false;
}

bool ScriptFileFormatWrapper::assertCanWrite() const
{
if (canWrite())
return true;
auto message = QCoreApplication::translate("Script Errors", "File format doesn't support `write`");
ScriptManager::instance().throwError(message);
return false;
}


ScriptTilesetFormatWrapper::ScriptTilesetFormatWrapper(TilesetFormat* format, QObject *parent)
: ScriptFileFormatWrapper(format, parent)
{}

EditableTileset *ScriptTilesetFormatWrapper::read(const QString &filename)
{
if (!assertCanRead())
return nullptr;

auto tileset = static_cast<TilesetFormat*>(mFormat)->read(filename);
if (!tileset) {
auto message = QCoreApplication::translate("Script Errors", "Error reading tileset");
ScriptManager::instance().throwError(message);
return nullptr;
}

return new EditableTileset(tileset.data());
}

void ScriptTilesetFormatWrapper::write(EditableTileset *editable, const QString &filename)
{
if (!assertCanWrite())
return;

auto tileset = editable->tileset();
auto success = static_cast<TilesetFormat*>(mFormat)->write(*tileset, filename);
if (!success)
ScriptManager::instance().throwError(mFormat->errorString());
}


ScriptMapFormatWrapper::ScriptMapFormatWrapper(MapFormat *format, QObject *parent)
: ScriptFileFormatWrapper(format, parent)
{}

EditableMap *ScriptMapFormatWrapper::read(const QString &filename)
{
if (!assertCanRead())
return nullptr;

auto map = static_cast<MapFormat*>(mFormat)->read(filename);
if (!map) {
auto message = QCoreApplication::translate("Script Errors", "Error reading map");
ScriptManager::instance().throwError(message);
return nullptr;
}

return new EditableMap(std::move(map));
}

void ScriptMapFormatWrapper::write(EditableMap *editable, const QString &filename)
{
if (!assertCanWrite())
return;

auto map = editable->map();
auto success = static_cast<MapFormat*>(mFormat)->write(map, filename);
if (!success)
ScriptManager::instance().throwError(mFormat->errorString());
}

} // namespace Tiled
80 changes: 80 additions & 0 deletions src/tiled/scriptfileformatwrappers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* scriptfileformatwrappers.h
* Copyright 2019, Phlosioneer <mattmdrr2@gmail.com>
*
* This file is part of Tiled.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include <QObject>

namespace Tiled {

class EditableTileset;
class EditableMap;
class MapFormat;
class TilesetFormat;
class FileFormat;

class ScriptFileFormatWrapper : public QObject
{
Q_OBJECT

Q_PROPERTY(bool canRead READ canRead)
Q_PROPERTY(bool canWrite READ canWrite)

public:
explicit ScriptFileFormatWrapper(FileFormat *format, QObject *parent = nullptr);

Q_INVOKABLE bool supportsFile(const QString &filename) const;

bool canRead() const;
bool canWrite() const;

protected:
bool assertCanRead() const;
bool assertCanWrite() const;

FileFormat *mFormat;
};

class ScriptTilesetFormatWrapper : public ScriptFileFormatWrapper
{
Q_OBJECT

public:
explicit ScriptTilesetFormatWrapper(TilesetFormat *format, QObject *parent = nullptr);

Q_INVOKABLE Tiled::EditableTileset *read(const QString &filename);
Q_INVOKABLE void write(Tiled::EditableTileset *tileset, const QString &filename);
};

class ScriptMapFormatWrapper : public ScriptFileFormatWrapper
{
Q_OBJECT

public:
explicit ScriptMapFormatWrapper(MapFormat *format, QObject *parent = nullptr);

Q_INVOKABLE Tiled::EditableMap *read(const QString &filename);
Q_INVOKABLE void write(Tiled::EditableMap *map, const QString &filename);
};

} // namespace Tiled

Q_DECLARE_METATYPE(Tiled::ScriptTilesetFormatWrapper*)
Q_DECLARE_METATYPE(Tiled::ScriptMapFormatWrapper*)
3 changes: 3 additions & 0 deletions src/tiled/scriptmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "scriptedfileformat.h"
#include "scriptedtool.h"
#include "scriptfile.h"
#include "scriptfileformatwrappers.h"
#include "scriptmodule.h"
#include "tilecollisiondock.h"
#include "tilelayer.h"
Expand Down Expand Up @@ -104,6 +105,8 @@ ScriptManager::ScriptManager(QObject *parent)
qRegisterMetaType<TileLayerEdit*>();
qRegisterMetaType<TilesetDock*>();
qRegisterMetaType<TilesetEditor*>();
qRegisterMetaType<ScriptMapFormatWrapper*>();
qRegisterMetaType<ScriptTilesetFormatWrapper*>();

connect(&mWatcher, &FileSystemWatcher::filesChanged,
this, &ScriptManager::scriptFilesChanged);
Expand Down
Loading