diff --git a/forms/tileseteditor.ui b/forms/tileseteditor.ui
index 895fae0f..b7f78f66 100644
--- a/forms/tileseteditor.ui
+++ b/forms/tileseteditor.ui
@@ -158,7 +158,7 @@
0
- 166
+ 190
@@ -194,7 +194,7 @@
false
-
+
-
@@ -451,12 +451,6 @@
-
-
-
- 0
- 0
-
-
98
@@ -497,16 +491,22 @@
-
+
+
+ 0
+ 0
+
+
- 18
- 18
+ 98
+ 98
98
- 34
+ 98
@@ -520,22 +520,22 @@
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 1
+
+
+
+
- -
-
-
- Qt::Orientation::Vertical
-
-
-
- 20
- 10
-
-
-
-
@@ -686,6 +686,14 @@
View
+
+
@@ -863,6 +871,22 @@
Secondary...
+
+
+ true
+
+
+ Horizontal
+
+
+
+
+ true
+
+
+ Vertical
+
+
diff --git a/include/config.h b/include/config.h
index 25482457..1f2a1a14 100644
--- a/include/config.h
+++ b/include/config.h
@@ -108,6 +108,7 @@ public:
int metatilesZoom;
int tilesetEditorMetatilesZoom;
int tilesetEditorTilesZoom;
+ Qt::Orientation tilesetEditorLayerOrientation;
bool showPlayerView;
bool showCursorTile;
bool showBorder;
diff --git a/include/ui/metatilelayersitem.h b/include/ui/metatilelayersitem.h
index 61eae902..7d1c74ce 100644
--- a/include/ui/metatilelayersitem.h
+++ b/include/ui/metatilelayersitem.h
@@ -9,28 +9,40 @@
class MetatileLayersItem: public SelectablePixmapItem {
Q_OBJECT
public:
- MetatileLayersItem(Metatile *metatile, Tileset *primaryTileset, Tileset *secondaryTileset);
+ MetatileLayersItem(Metatile *metatile,
+ Tileset *primaryTileset,
+ Tileset *secondaryTileset,
+ Qt::Orientation orientation = Qt::Horizontal);
void draw();
void setTilesets(Tileset*, Tileset*);
void setMetatile(Metatile*);
void clearLastModifiedCoords();
void clearLastHoveredCoords();
+
+ QPoint tileIndexToPos(int index) const { return this->tilePositions.value(index); }
+ int posToTileIndex(const QPoint &pos) const { return this->tilePositions.indexOf(pos); }
+ int posToTileIndex(int x, int y) const { return posToTileIndex(QPoint(x, y)); }
+
+ void setOrientation(Qt::Orientation orientation);
+
bool showGrid;
private:
Metatile* metatile;
Tileset *primaryTileset;
Tileset *secondaryTileset;
+ Qt::Orientation orientation;
QPoint prevChangedPos;
QPoint prevHoveredPos;
+ QList tilePositions;
+
QPoint getBoundedPos(const QPointF &);
- void requestTileChange(const QPoint &pos);
- void requestPaletteChange(const QPoint &pos);
void updateSelection();
+ void hover(const QPoint &pos);
signals:
void tileChanged(const QPoint &pos);
void paletteChanged(const QPoint &pos);
- void selectedTilesChanged(QPoint, int, int);
+ void selectedTilesChanged(const QPoint &pos, const QSize &dimensions);
void hoveredTileChanged(const Tile &tile);
void hoveredTileCleared();
protected:
diff --git a/include/ui/selectablepixmapitem.h b/include/ui/selectablepixmapitem.h
index 05dadb86..433b2bca 100644
--- a/include/ui/selectablepixmapitem.h
+++ b/include/ui/selectablepixmapitem.h
@@ -19,9 +19,13 @@ public:
selectionOffsetX(0),
selectionOffsetY(0)
{}
- virtual QSize getSelectionDimensions() const;
+ virtual QSize getSelectionDimensions() const { return QSize(abs(this->selectionOffsetX) + 1, abs(this->selectionOffsetY) + 1); }
virtual void draw() = 0;
+ virtual void setMaxSelectionSize(const QSize &size) { setMaxSelectionSize(size.width(), size.height()); }
+ virtual void setMaxSelectionSize(int width, int height);
+ QSize maxSelectionSize() { return QSize(this->maxSelectionWidth, this->maxSelectionHeight); }
+
protected:
int cellWidth;
int cellHeight;
@@ -33,17 +37,22 @@ protected:
int selectionOffsetY;
QPoint getSelectionStart();
- void select(int x, int y, int width = 0, int height = 0);
- void select(const QPoint &pos, const QSize &size = QSize(0,0)) { select(pos.x(), pos.y(), size.width(), size.height()); }
- void updateSelection(int, int);
+ void select(const QPoint &pos, const QSize &size = QSize(1,1));
+ void select(int x, int y, int width = 1, int height = 1) { select(QPoint(x, y), QSize(width, height)); }
+ void updateSelection(const QPoint &pos);
QPoint getCellPos(QPointF);
virtual void mousePressEvent(QGraphicsSceneMouseEvent*) override;
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent*) override;
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent*) override;
virtual void drawSelection();
+ virtual int cellsWide() const { return this->cellWidth ? (pixmap().width() / this->cellWidth) : 0; }
+ virtual int cellsTall() const { return this->cellHeight ? (pixmap().height() / this->cellHeight) : 0; }
signals:
- void selectionChanged(int, int, int, int);
+ void selectionChanged(const QPoint&, const QSize&);
+
+private:
+ QPoint prevCellPos = QPoint(-1,-1);
};
#endif // SELECTABLEPIXMAPITEM_H
diff --git a/include/ui/tileseteditor.h b/include/ui/tileseteditor.h
index 4d8c5b95..43467713 100644
--- a/include/ui/tileseteditor.h
+++ b/include/ui/tileseteditor.h
@@ -69,7 +69,7 @@ private slots:
void onHoveredTileChanged(const Tile&);
void onHoveredTileChanged(uint16_t);
void onHoveredTileCleared();
- void onMetatileLayerSelectionChanged(QPoint, int, int);
+ void onMetatileLayerSelectionChanged(const QPoint&, const QSize&);
void onPaletteEditorChangedPaletteColor();
void on_actionChange_Metatiles_Count_triggered();
@@ -138,6 +138,7 @@ private:
void refreshTileFlips();
void refreshPaletteId();
void paintSelectedLayerTiles(const QPoint &pos, bool paletteOnly = false);
+ void setMetatileLayerOrientation(Qt::Orientation orientation);
Ui::TilesetEditor *ui;
History metatileHistory;
diff --git a/include/ui/tileseteditortileselector.h b/include/ui/tileseteditortileselector.h
index 01b0aed9..915a9227 100644
--- a/include/ui/tileseteditortileselector.h
+++ b/include/ui/tileseteditortileselector.h
@@ -7,8 +7,8 @@
class TilesetEditorTileSelector: public SelectablePixmapItem {
Q_OBJECT
public:
- TilesetEditorTileSelector(Tileset *primaryTileset, Tileset *secondaryTileset, int numLayers)
- : SelectablePixmapItem(16, 16, numLayers * Metatile::tileWidth(), Metatile::tileHeight()) {
+ TilesetEditorTileSelector(Tileset *primaryTileset, Tileset *secondaryTileset)
+ : SelectablePixmapItem(16, 16, Metatile::tileWidth(), Metatile::tileWidth()) {
this->primaryTileset = primaryTileset;
this->secondaryTileset = secondaryTileset;
this->numTilesWide = 16;
@@ -19,6 +19,7 @@ public:
setAcceptHoverEvents(true);
}
QSize getSelectionDimensions() const override;
+ void setMaxSelectionSize(int width, int height) override;
void draw() override;
void select(uint16_t metatileId);
void highlight(uint16_t metatileId);
@@ -31,6 +32,7 @@ public:
QImage buildPrimaryTilesIndexedImage();
QImage buildSecondaryTilesIndexedImage();
+
QVector usedTiles;
bool showUnused = false;
bool showDivider = false;
@@ -49,6 +51,7 @@ private:
int externalSelectionHeight;
QList externalSelectedTiles;
QList externalSelectedPos;
+ QPoint prevCellPos = QPoint(-1,-1);
Tileset *primaryTileset;
Tileset *secondaryTileset;
diff --git a/src/config.cpp b/src/config.cpp
index b53f171b..4bff6a78 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -338,6 +338,7 @@ void PorymapConfig::reset() {
this->metatilesZoom = 30;
this->tilesetEditorMetatilesZoom = 30;
this->tilesetEditorTilesZoom = 30;
+ this->tilesetEditorLayerOrientation = Qt::Horizontal;
this->showPlayerView = false;
this->showCursorTile = true;
this->showBorder = true;
@@ -454,6 +455,9 @@ void PorymapConfig::parseConfigKeyValue(QString key, QString value) {
this->tilesetEditorMetatilesZoom = getConfigInteger(key, value, 10, 100, 30);
} else if (key == "tileset_editor_tiles_zoom") {
this->tilesetEditorTilesZoom = getConfigInteger(key, value, 10, 100, 30);
+ } else if (key == "tileset_editor_layer_orientation") {
+ // Being explicit here to avoid casting out-of-range values.
+ this->tilesetEditorLayerOrientation = (getConfigInteger(key, value) == static_cast(Qt::Horizontal)) ? Qt::Horizontal : Qt::Vertical;
} else if (key == "show_player_view") {
this->showPlayerView = getConfigBool(key, value);
} else if (key == "show_cursor_tile") {
@@ -604,6 +608,7 @@ QMap PorymapConfig::getKeyValueMap() {
map.insert("metatiles_zoom", QString::number(this->metatilesZoom));
map.insert("tileset_editor_metatiles_zoom", QString::number(this->tilesetEditorMetatilesZoom));
map.insert("tileset_editor_tiles_zoom", QString::number(this->tilesetEditorTilesZoom));
+ map.insert("tileset_editor_layer_orientation", QString::number(this->tilesetEditorLayerOrientation));
map.insert("show_player_view", this->showPlayerView ? "1" : "0");
map.insert("show_cursor_tile", this->showCursorTile ? "1" : "0");
map.insert("show_border", this->showBorder ? "1" : "0");
diff --git a/src/editor.cpp b/src/editor.cpp
index 69009613..9c6a7d0a 100644
--- a/src/editor.cpp
+++ b/src/editor.cpp
@@ -1773,8 +1773,8 @@ void Editor::displayMovementPermissionSelector() {
this, &Editor::onHoveredMovementPermissionChanged);
connect(movement_permissions_selector_item, &MovementPermissionsSelector::hoveredMovementPermissionCleared,
this, &Editor::onHoveredMovementPermissionCleared);
- connect(movement_permissions_selector_item, &SelectablePixmapItem::selectionChanged, [this](int x, int y, int, int) {
- this->setCollisionTabSpinBoxes(x, y);
+ connect(movement_permissions_selector_item, &SelectablePixmapItem::selectionChanged, [this](const QPoint &pos, const QSize&) {
+ this->setCollisionTabSpinBoxes(pos.x(), pos.y());
});
movement_permissions_selector_item->select(projectConfig.defaultCollision, projectConfig.defaultElevation);
}
diff --git a/src/project.cpp b/src/project.cpp
index 9c5fd9af..07ac72ea 100644
--- a/src/project.cpp
+++ b/src/project.cpp
@@ -1187,6 +1187,18 @@ bool Project::loadLayoutTilesets(Layout *layout) {
logError(QString("Failed to load %1: missing secondary tileset label.").arg(layout->name));
return false;
}
+ if (!this->primaryTilesetLabels.contains(layout->tileset_primary_label)) {
+ logError(QString("Failed to load %1: unknown primary tileset label '%2'.")
+ .arg(layout->name)
+ .arg(layout->tileset_primary_label));
+ return false;
+ }
+ if (!this->secondaryTilesetLabels.contains(layout->tileset_secondary_label)) {
+ logError(QString("Failed to load %1: unknown secondary tileset label '%2'.")
+ .arg(layout->name)
+ .arg(layout->tileset_secondary_label));
+ return false;
+ }
layout->tileset_primary = getTileset(layout->tileset_primary_label);
layout->tileset_secondary = getTileset(layout->tileset_secondary_label);
@@ -1194,6 +1206,11 @@ bool Project::loadLayoutTilesets(Layout *layout) {
}
Tileset* Project::getTileset(const QString &label, bool forceLoad) {
+ if (!this->tilesetLabelsOrdered.contains(label)) {
+ logError(QString("Unknown tileset name '%1'.").arg(label));
+ return nullptr;
+ }
+
Tileset *tileset = nullptr;
auto it = this->tilesetCache.constFind(label);
diff --git a/src/ui/metatilelayersitem.cpp b/src/ui/metatilelayersitem.cpp
index 9c95f6ef..34afce00 100644
--- a/src/ui/metatilelayersitem.cpp
+++ b/src/ui/metatilelayersitem.cpp
@@ -3,8 +3,8 @@
#include "imageproviders.h"
#include
-MetatileLayersItem::MetatileLayersItem(Metatile *metatile, Tileset *primaryTileset, Tileset *secondaryTileset)
- : SelectablePixmapItem(16, 16, Metatile::tileWidth() * projectConfig.getNumLayersInMetatile(), Metatile::tileHeight()),
+MetatileLayersItem::MetatileLayersItem(Metatile *metatile, Tileset *primaryTileset, Tileset *secondaryTileset, Qt::Orientation orientation)
+ : SelectablePixmapItem(16, 16, Metatile::tileWidth(), Metatile::tileHeight()),
metatile(metatile),
primaryTileset(primaryTileset),
secondaryTileset(secondaryTileset)
@@ -12,28 +12,51 @@ MetatileLayersItem::MetatileLayersItem(Metatile *metatile, Tileset *primaryTiles
clearLastModifiedCoords();
clearLastHoveredCoords();
setAcceptHoverEvents(true);
+ setOrientation(orientation);
}
-static const QList tilePositions = {
- QPoint(0, 0),
- QPoint(1, 0),
- QPoint(0, 1),
- QPoint(1, 1),
- QPoint(2, 0),
- QPoint(3, 0),
- QPoint(2, 1),
- QPoint(3, 1),
- QPoint(4, 0),
- QPoint(5, 0),
- QPoint(4, 1),
- QPoint(5, 1),
-};
+void MetatileLayersItem::setOrientation(Qt::Orientation orientation) {
+ this->orientation = orientation;
+ int maxWidth = Metatile::tileWidth();
+ int maxHeight = Metatile::tileHeight();
+
+ // Generate a table of tile positions that allows us to map between
+ // the index of a tile in the metatile and its position in this layer view.
+ this->tilePositions.clear();
+ if (this->orientation == Qt::Horizontal) {
+ // Tiles are laid out horizontally, with the bottom layer on the left:
+ // 0 1 4 5 8 9
+ // 2 3 6 7 10 11
+ for (int layer = 0; layer < projectConfig.getNumLayersInMetatile(); layer++)
+ for (int y = 0; y < Metatile::tileHeight(); y++)
+ for (int x = 0; x < Metatile::tileWidth(); x++) {
+ this->tilePositions.append(QPoint(x + layer * Metatile::tileWidth(), y));
+ }
+ maxWidth *= projectConfig.getNumLayersInMetatile();
+ } else if (this->orientation == Qt::Vertical) {
+ // Tiles are laid out vertically, with the bottom layer on the bottom:
+ // 8 9
+ // 10 11
+ // 4 5
+ // 6 7
+ // 0 1
+ // 2 3
+ for (int layer = projectConfig.getNumLayersInMetatile() - 1; layer >= 0; layer--)
+ for (int y = 0; y < Metatile::tileHeight(); y++)
+ for (int x = 0; x < Metatile::tileWidth(); x++) {
+ this->tilePositions.append(QPoint(x, y + layer * Metatile::tileHeight()));
+ }
+ maxHeight *= projectConfig.getNumLayersInMetatile();
+ }
+ setMaxSelectionSize(maxWidth, maxHeight);
+ update();
+ if (!this->pixmap().isNull()) {
+ draw();
+ }
+}
void MetatileLayersItem::draw() {
- const int numLayers = projectConfig.getNumLayersInMetatile();
- const int layerWidth = this->cellWidth * Metatile::tileWidth();
- const int layerHeight = this->cellHeight * Metatile::tileHeight();
- QPixmap pixmap(numLayers * layerWidth, layerHeight);
+ QPixmap pixmap(this->cellWidth * this->maxSelectionWidth, this->cellHeight * this->maxSelectionHeight);
QPainter painter(&pixmap);
// Draw tile images
@@ -47,15 +70,22 @@ void MetatileLayersItem::draw() {
true
).scaled(this->cellWidth, this->cellHeight);
tile.flip(&tileImage);
- QPoint pos = tilePositions.at(i);
+ QPoint pos = tileIndexToPos(i);
painter.drawImage(pos.x() * this->cellWidth, pos.y() * this->cellHeight, tileImage);
}
if (this->showGrid) {
// Draw grid
painter.setPen(Qt::white);
- for (int i = 1; i < numLayers; i++) {
- int x = i * layerWidth;
- painter.drawLine(x, 0, x, layerHeight);
+ const int layerWidth = this->cellWidth * Metatile::tileWidth();
+ const int layerHeight = this->cellHeight * Metatile::tileHeight();
+ for (int i = 1; i < projectConfig.getNumLayersInMetatile(); i++) {
+ if (this->orientation == Qt::Vertical) {
+ int y = i * layerHeight;
+ painter.drawLine(0, y, layerWidth, y);
+ } else if (this->orientation == Qt::Horizontal) {
+ int x = i * layerWidth;
+ painter.drawLine(x, 0, x, layerHeight);
+ }
}
}
@@ -76,51 +106,41 @@ void MetatileLayersItem::setTilesets(Tileset *primaryTileset, Tileset *secondary
this->clearLastHoveredCoords();
}
-// We request our current selection to be painted,
-// this class doesn't handle changing the metatile data.
-void MetatileLayersItem::requestTileChange(const QPoint &pos) {
- this->prevChangedPos = pos;
- this->clearLastHoveredCoords();
- emit this->tileChanged(pos);
-}
-void MetatileLayersItem::requestPaletteChange(const QPoint &pos) {
- this->prevChangedPos = pos;
- this->clearLastHoveredCoords();
- emit this->paletteChanged(pos);
-}
-
void MetatileLayersItem::updateSelection() {
- QPoint selectionOrigin = this->getSelectionStart();
- QSize dimensions = this->getSelectionDimensions();
- emit this->selectedTilesChanged(selectionOrigin, dimensions.width(), dimensions.height());
- this->drawSelection();
+ drawSelection();
+ emit selectedTilesChanged(getSelectionStart(), getSelectionDimensions());
}
void MetatileLayersItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
+ const QPoint pos = this->getBoundedPos(event->pos());
+ hover(pos);
+
if (event->buttons() & Qt::RightButton) {
SelectablePixmapItem::mousePressEvent(event);
updateSelection();
} else if (event->modifiers() & Qt::ControlModifier) {
- requestPaletteChange(getBoundedPos(event->pos()));
+ emit paletteChanged(pos);
} else {
- requestTileChange(getBoundedPos(event->pos()));
+ emit tileChanged(pos);
}
+ this->prevChangedPos = pos;
}
void MetatileLayersItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
+ const QPoint pos = this->getBoundedPos(event->pos());
+ if (this->prevChangedPos == pos)
+ return;
+ hover(pos);
+
if (event->buttons() & Qt::RightButton) {
SelectablePixmapItem::mouseMoveEvent(event);
updateSelection();
+ } else if (event->modifiers() & Qt::ControlModifier) {
+ emit paletteChanged(pos);
} else {
- const QPoint pos = this->getBoundedPos(event->pos());
- if (this->prevChangedPos != pos) {
- if (event->modifiers() & Qt::ControlModifier) {
- requestPaletteChange(pos);
- } else {
- requestTileChange(pos);
- }
- }
+ emit tileChanged(pos);
}
+ this->prevChangedPos = pos;
}
void MetatileLayersItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
@@ -130,16 +150,19 @@ void MetatileLayersItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
}
// Clear selection rectangle
- this->draw();
+ draw();
}
void MetatileLayersItem::hoverMoveEvent(QGraphicsSceneHoverEvent * event) {
- const QPoint pos = this->getBoundedPos(event->pos());
+ hover(getBoundedPos(event->pos()));
+}
+
+void MetatileLayersItem::hover(const QPoint &pos) {
if (pos == this->prevHoveredPos)
return;
this->prevHoveredPos = pos;
- int tileIndex = tilePositions.indexOf(pos);
+ int tileIndex = posToTileIndex(pos);
if (tileIndex < 0 || tileIndex >= this->metatile->tiles.length())
return;
diff --git a/src/ui/selectablepixmapitem.cpp b/src/ui/selectablepixmapitem.cpp
index d3aa2914..7a38913e 100644
--- a/src/ui/selectablepixmapitem.cpp
+++ b/src/ui/selectablepixmapitem.cpp
@@ -1,11 +1,6 @@
#include "selectablepixmapitem.h"
#include
-QSize SelectablePixmapItem::getSelectionDimensions() const
-{
- return QSize(abs(this->selectionOffsetX) + 1, abs(this->selectionOffsetY) + 1);
-}
-
QPoint SelectablePixmapItem::getSelectionStart()
{
int x = this->selectionInitialX;
@@ -15,47 +10,62 @@ QPoint SelectablePixmapItem::getSelectionStart()
return QPoint(x, y);
}
-void SelectablePixmapItem::select(int x, int y, int width, int height)
+void SelectablePixmapItem::select(const QPoint &pos, const QSize &size)
{
- this->selectionInitialX = x;
- this->selectionInitialY = y;
- this->selectionOffsetX = qBound(0, width, this->maxSelectionWidth);
- this->selectionOffsetY = qBound(0, height, this->maxSelectionHeight);
- this->draw();
- emit this->selectionChanged(x, y, width, height);
+ this->selectionInitialX = pos.x();
+ this->selectionInitialY = pos.y();
+ this->selectionOffsetX = qBound(0, size.width(), this->maxSelectionWidth - 1);
+ this->selectionOffsetY = qBound(0, size.height(), this->maxSelectionHeight - 1);
+ draw();
+ emit selectionChanged(pos, getSelectionDimensions());
}
void SelectablePixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
- QPoint pos = this->getCellPos(event->pos());
+ QPoint pos = getCellPos(event->pos());
this->selectionInitialX = pos.x();
this->selectionInitialY = pos.y();
this->selectionOffsetX = 0;
this->selectionOffsetY = 0;
- this->updateSelection(pos.x(), pos.y());
+ this->prevCellPos = pos;
+ updateSelection(pos);
}
void SelectablePixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
- QPoint pos = this->getCellPos(event->pos());
- this->updateSelection(pos.x(), pos.y());
+ QPoint pos = getCellPos(event->pos());
+ if (pos == this->prevCellPos)
+ return;
+ this->prevCellPos = pos;
+ updateSelection(pos);
}
void SelectablePixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
- QPoint pos = this->getCellPos(event->pos());
- this->updateSelection(pos.x(), pos.y());
+ updateSelection(getCellPos(event->pos()));
}
-void SelectablePixmapItem::updateSelection(int x, int y)
-{
+void SelectablePixmapItem::setMaxSelectionSize(int width, int height) {
+ this->maxSelectionWidth = qMax(width, 1);
+ this->maxSelectionHeight = qMax(height, 1);
+
+ // Update the selection if we shrank below the current selection size.
+ QSize size = getSelectionDimensions();
+ if (size.width() > this->maxSelectionWidth || size.height() > this->maxSelectionHeight) {
+ QPoint origin = getSelectionStart();
+ this->selectionInitialX = origin.x();
+ this->selectionInitialY = origin.y();
+ this->selectionOffsetX = qMin(size.width(), this->maxSelectionWidth) - 1;
+ this->selectionOffsetY = qMin(size.height(), this->maxSelectionHeight) - 1;
+ draw();
+ emit selectionChanged(getSelectionStart(), getSelectionDimensions());
+ }
+}
+
+void SelectablePixmapItem::updateSelection(const QPoint &pos) {
// Snap to a valid position inside the selection area.
- int width = pixmap().width() / this->cellWidth;
- int height = pixmap().height() / this->cellHeight;
- if (x < 0) x = 0;
- if (x >= width) x = width - 1;
- if (y < 0) y = 0;
- if (y >= height) y = height - 1;
+ int x = qBound(0, pos.x(), cellsWide() - 1);
+ int y = qBound(0, pos.y(), cellsTall() - 1);
this->selectionOffsetX = x - this->selectionInitialX;
this->selectionOffsetY = y - this->selectionInitialY;
@@ -76,22 +86,20 @@ void SelectablePixmapItem::updateSelection(int x, int y)
this->selectionOffsetY = -this->maxSelectionHeight + 1;
}
- this->draw();
- emit this->selectionChanged(x, y, width, height);
+ draw();
+ emit selectionChanged(QPoint(x, y), getSelectionDimensions());
}
-QPoint SelectablePixmapItem::getCellPos(QPointF pos)
-{
- if (pos.x() < 0) pos.setX(0);
- if (pos.y() < 0) pos.setY(0);
- if (pos.x() >= this->pixmap().width()) pos.setX(this->pixmap().width() - 1);
- if (pos.y() >= this->pixmap().height()) pos.setY(this->pixmap().height() - 1);
- return QPoint(static_cast(pos.x()) / this->cellWidth,
- static_cast(pos.y()) / this->cellHeight);
+QPoint SelectablePixmapItem::getCellPos(QPointF pos) {
+ if (this->cellWidth == 0 || this->cellHeight == 0 || pixmap().isNull())
+ return QPoint(0,0);
+
+ int x = qBound(0, static_cast(pos.x()), pixmap().width() - 1);
+ int y = qBound(0, static_cast(pos.y()), pixmap().height() - 1);
+ return QPoint(x / this->cellWidth, y / this->cellHeight);
}
-void SelectablePixmapItem::drawSelection()
-{
+void SelectablePixmapItem::drawSelection() {
QPoint origin = this->getSelectionStart();
QSize dimensions = this->getSelectionDimensions();
QRect selectionRect(origin.x() * this->cellWidth, origin.y() * this->cellHeight, dimensions.width() * this->cellWidth, dimensions.height() * this->cellHeight);
diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp
index adc3f280..5b4c34b1 100644
--- a/src/ui/tileseteditor.cpp
+++ b/src/ui/tileseteditor.cpp
@@ -62,12 +62,16 @@ TilesetEditor::TilesetEditor(Project *project, Layout *layout, QWidget *parent)
connect(ui->spinBox_paletteSelector, QOverload::of(&QSpinBox::valueChanged), this, &TilesetEditor::refreshPaletteId);
+ connect(ui->actionLayer_Arrangement_Horizontal, &QAction::triggered, [this] { setMetatileLayerOrientation(Qt::Horizontal); });
+ connect(ui->actionLayer_Arrangement_Vertical, &QAction::triggered, [this] { setMetatileLayerOrientation(Qt::Vertical); });
+
initAttributesUi();
initMetatileSelector();
initMetatileLayersItem();
initTileSelector();
initSelectedTileItem();
initShortcuts();
+ setMetatileLayerOrientation(porymapConfig.tilesetEditorLayerOrientation);
this->metatileSelector->select(0);
restoreWindowState();
}
@@ -234,6 +238,53 @@ void TilesetEditor::initMetatileSelector()
this->ui->horizontalSlider_MetatilesZoom->setValue(porymapConfig.tilesetEditorMetatilesZoom);
}
+void TilesetEditor::setMetatileLayerOrientation(Qt::Orientation orientation) {
+ // Sync settings
+ bool horizontal = (orientation == Qt::Horizontal);
+ porymapConfig.tilesetEditorLayerOrientation = orientation;
+ const QSignalBlocker b_Horizontal(ui->actionLayer_Arrangement_Horizontal);
+ const QSignalBlocker b_Vertical(ui->actionLayer_Arrangement_Vertical);
+ ui->actionLayer_Arrangement_Horizontal->setChecked(horizontal);
+ ui->actionLayer_Arrangement_Vertical->setChecked(!horizontal);
+
+ this->metatileLayersItem->setOrientation(orientation);
+
+ int numTilesWide = Metatile::tileWidth();
+ int numTilesTall = Metatile::tileHeight();
+ int numLayers = projectConfig.getNumLayersInMetatile();
+ if (horizontal) {
+ numTilesWide *= numLayers;
+ } else {
+ numTilesTall *= numLayers;
+ }
+ this->tileSelector->setMaxSelectionSize(numTilesWide, numTilesTall);
+
+ const int scale = 2;
+ int w = Tile::pixelWidth() * numTilesWide * scale + 2;
+ int h = Tile::pixelHeight() * numTilesTall * scale + 2;
+ ui->graphicsView_selectedTile->setFixedSize(w, h);
+ ui->graphicsView_metatileLayers->setFixedSize(w, h);
+
+ // If the layers are laid out vertically then the orientation is obvious, no need to label them.
+ ui->label_BottomTop->setVisible(horizontal);
+
+ // Let the graphics view take over the label's vertical space (or conversely, give the space back).
+ // (This is a bit of a process, apparently there's no quick way to set a widget's row / row span once they're added to the layout
+ int row, col, rowSpan, colSpan;
+ int index = ui->gridLayout_MetatileProperties->indexOf(ui->label_BottomTop);
+ ui->gridLayout_MetatileProperties->getItemPosition(index, &row, &col, &rowSpan, &colSpan);
+
+ // TODO: Rearrange the rest of the metatile properties panel. The vertical triple-layer metatiles layout esp. looks terrible.
+ ui->gridLayout_MetatileProperties->removeWidget(ui->graphicsView_metatileLayers);
+ if (horizontal) {
+ // Give space from graphics view back to label
+ ui->gridLayout_MetatileProperties->addWidget(ui->graphicsView_metatileLayers, row + 1, col, rowSpan, colSpan);
+ } else {
+ // Take space from label and give it to graphics view
+ ui->gridLayout_MetatileProperties->addWidget(ui->graphicsView_metatileLayers, row, col, rowSpan + 1, colSpan);
+ }
+}
+
void TilesetEditor::initMetatileLayersItem() {
Metatile *metatile = Tileset::getMetatile(this->getSelectedMetatileId(), this->primaryTileset, this->secondaryTileset);
this->metatileLayersItem = new MetatileLayersItem(metatile, this->primaryTileset, this->secondaryTileset);
@@ -252,9 +303,8 @@ void TilesetEditor::initMetatileLayersItem() {
this->ui->graphicsView_metatileLayers->setScene(this->metatileLayersScene);
}
-void TilesetEditor::initTileSelector()
-{
- this->tileSelector = new TilesetEditorTileSelector(this->primaryTileset, this->secondaryTileset, projectConfig.getNumLayersInMetatile());
+void TilesetEditor::initTileSelector() {
+ this->tileSelector = new TilesetEditorTileSelector(this->primaryTileset, this->secondaryTileset);
connect(this->tileSelector, &TilesetEditorTileSelector::hoveredTileChanged, [this](uint16_t tileId) {
onHoveredTileChanged(tileId);
});
@@ -277,7 +327,6 @@ void TilesetEditor::initSelectedTileItem() {
this->selectedTileScene = new QGraphicsScene;
this->drawSelectedTiles();
this->ui->graphicsView_selectedTile->setScene(this->selectedTileScene);
- this->ui->graphicsView_selectedTile->setFixedSize(this->selectedTilePixmapItem->pixmap().width() + 2, this->selectedTilePixmapItem->pixmap().height() + 2);
}
void TilesetEditor::initShortcuts() {
@@ -392,13 +441,12 @@ void TilesetEditor::drawSelectedTiles() {
QImage selectionImage(imgTileWidth * dimensions.width(), imgTileHeight * dimensions.height(), QImage::Format_RGBA8888);
QPainter painter(&selectionImage);
int tileIndex = 0;
- for (int j = 0; j < dimensions.height(); j++) {
- for (int i = 0; i < dimensions.width(); i++) {
- auto tile = tiles.at(tileIndex);
+ for (int y = 0; y < dimensions.height(); y++) {
+ for (int x = 0; x < dimensions.width(); x++) {
+ auto tile = tiles.at(tileIndex++);
QImage tileImage = getPalettedTileImage(tile.tileId, this->primaryTileset, this->secondaryTileset, tile.palette, true).scaled(imgTileWidth, imgTileHeight);
tile.flip(&tileImage);
- tileIndex++;
- painter.drawImage(i * imgTileWidth, j * imgTileHeight, tileImage);
+ painter.drawImage(x * imgTileWidth, y * imgTileHeight, tileImage);
}
}
@@ -407,7 +455,6 @@ void TilesetEditor::drawSelectedTiles() {
QSize size(this->selectedTilePixmapItem->pixmap().width(), this->selectedTilePixmapItem->pixmap().height());
this->ui->graphicsView_selectedTile->setSceneRect(0, 0, size.width(), size.height());
- this->ui->graphicsView_selectedTile->setFixedSize(size.width() + 2, size.height() + 2);
}
void TilesetEditor::onHoveredMetatileChanged(uint16_t metatileId) {
@@ -436,7 +483,6 @@ void TilesetEditor::onSelectedMetatileChanged(uint16_t metatileId) {
this->metatileLayersItem->setMetatile(metatile);
this->metatileLayersItem->draw();
- this->ui->graphicsView_metatileLayers->setFixedSize(this->metatileLayersItem->pixmap().width() + 2, this->metatileLayersItem->pixmap().height() + 2);
MetatileLabelPair labels = Tileset::getMetatileLabelPair(metatileId, this->primaryTileset, this->secondaryTileset);
this->ui->lineEdit_metatileLabel->setText(labels.owned);
@@ -467,33 +513,18 @@ void TilesetEditor::onHoveredTileCleared() {
}
void TilesetEditor::paintSelectedLayerTiles(const QPoint &pos, bool paletteOnly) {
- static const QList tileCoords = QList{
- QPoint(0, 0),
- QPoint(1, 0),
- QPoint(0, 1),
- QPoint(1, 1),
- QPoint(2, 0),
- QPoint(3, 0),
- QPoint(2, 1),
- QPoint(3, 1),
- QPoint(4, 0),
- QPoint(5, 0),
- QPoint(4, 1),
- QPoint(5, 1),
- };
bool changed = false;
Metatile *prevMetatile = new Metatile(*this->metatile);
QSize dimensions = this->tileSelector->getSelectionDimensions();
QList tiles = this->tileSelector->getSelectedTiles();
- int selectedTileIndex = 0;
+ int srcTileIndex = 0;
int maxTileIndex = projectConfig.getNumTilesInMetatile();
- for (int j = 0; j < dimensions.height(); j++) {
- for (int i = 0; i < dimensions.width(); i++) {
- int tileIndex = ((pos.x() + i) / 2 * 4) + ((pos.y() + j) * 2) + ((pos.x() + i) % 2);
- QPoint tilePos = tileCoords.at(tileIndex);
- if (tileIndex < maxTileIndex && tilePos.x() >= pos.x() && tilePos.y() >= pos.y()){
- Tile &destTile = this->metatile->tiles[tileIndex];
- const Tile srcTile = tiles.at(selectedTileIndex);
+ for (int y = 0; y < dimensions.height(); y++) {
+ for (int x = 0; x < dimensions.width(); x++) {
+ int destTileIndex = this->metatileLayersItem->posToTileIndex(pos.x() + x, pos.y() + y);
+ if (destTileIndex < maxTileIndex) {
+ Tile &destTile = this->metatile->tiles[destTileIndex];
+ const Tile srcTile = tiles.at(srcTileIndex++);
if (paletteOnly) {
if (srcTile.palette == destTile.palette)
continue; // Ignore no-ops for edit history
@@ -511,7 +542,6 @@ void TilesetEditor::paintSelectedLayerTiles(const QPoint &pos, bool paletteOnly)
}
changed = true;
}
- selectedTileIndex++;
}
}
if (!changed) {
@@ -525,26 +555,24 @@ void TilesetEditor::paintSelectedLayerTiles(const QPoint &pos, bool paletteOnly)
this->commitMetatileChange(prevMetatile);
}
-void TilesetEditor::onMetatileLayerSelectionChanged(QPoint selectionOrigin, int width, int height) {
+void TilesetEditor::onMetatileLayerSelectionChanged(const QPoint &selectionOrigin, const QSize &size) {
QList tiles;
QList tileIdxs;
- int x = selectionOrigin.x();
- int y = selectionOrigin.y();
int maxTileIndex = projectConfig.getNumTilesInMetatile();
- for (int j = 0; j < height; j++) {
- for (int i = 0; i < width; i++) {
- int tileIndex = ((x + i) / 2 * 4) + ((y + j) * 2) + ((x + i) % 2);
+ for (int j = 0; j < size.height(); j++) {
+ for (int i = 0; i < size.width(); i++) {
+ int tileIndex = this->metatileLayersItem->posToTileIndex(selectionOrigin.x() + i, selectionOrigin.y() + j);
if (tileIndex < maxTileIndex) {
- tiles.append(this->metatile->tiles.at(tileIndex));
+ tiles.append(this->metatile->tiles.value(tileIndex));
tileIdxs.append(tileIndex);
}
}
}
- this->tileSelector->setExternalSelection(width, height, tiles, tileIdxs);
- if (width == 1 && height == 1) {
+ this->tileSelector->setExternalSelection(size.width(), size.height(), tiles, tileIdxs);
+ if (size == QSize(1,1)) {
setPaletteId(tiles[0].palette);
- this->tileSelector->highlight(static_cast(tiles[0].tileId));
+ this->tileSelector->highlight(tiles[0].tileId);
this->redrawTileSelector();
}
this->metatileLayersItem->clearLastModifiedCoords();
diff --git a/src/ui/tileseteditortileselector.cpp b/src/ui/tileseteditortileselector.cpp
index 3d42cb72..ec3caa83 100644
--- a/src/ui/tileseteditortileselector.cpp
+++ b/src/ui/tileseteditortileselector.cpp
@@ -12,6 +12,11 @@ QSize TilesetEditorTileSelector::getSelectionDimensions() const {
}
}
+void TilesetEditorTileSelector::setMaxSelectionSize(int width, int height) {
+ SelectablePixmapItem::setMaxSelectionSize(width, height);
+ updateSelectedTiles();
+}
+
void TilesetEditorTileSelector::updateBasePixmap() {
if (!this->primaryTileset || !this->secondaryTileset || this->numTilesWide == 0) {
this->basePixmap = QPixmap();
@@ -134,7 +139,7 @@ QList TilesetEditorTileSelector::buildSelectedTiles(int width, int height,
// If we've completed a layer row, or its the last tile of an incompletely
// selected layer, then append the layer row to the full row
// If not an external selection, treat the whole row as 1 "layer"
- if (i == width - 1 || (this->externalSelection && (this->externalSelectedPos.at(index) % 4) & 1)) {
+ if (i == width - 1 || (this->externalSelection && (this->externalSelectedPos.at(index) % Metatile::tilesPerLayer()) & 1)) {
row.append(layerRow);
layerRow.clear();
}
@@ -170,16 +175,20 @@ uint16_t TilesetEditorTileSelector::getTileId(int x, int y) {
}
void TilesetEditorTileSelector::mousePressEvent(QGraphicsSceneMouseEvent *event) {
+ this->prevCellPos = getCellPos(event->pos());
SelectablePixmapItem::mousePressEvent(event);
this->updateSelectedTiles();
emit selectedTilesChanged();
}
void TilesetEditorTileSelector::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
+ QPoint pos = getCellPos(event->pos());
+ if (this->prevCellPos == pos)
+ return;
+ this->prevCellPos = pos;
+
SelectablePixmapItem::mouseMoveEvent(event);
this->updateSelectedTiles();
-
- QPoint pos = this->getCellPos(event->pos());
uint16_t tile = this->getTileId(pos.x(), pos.y());
emit hoveredTileChanged(tile);
emit selectedTilesChanged();