porymap/src/ui/tileseteditormetatileselector.cpp

292 lines
10 KiB
C++
Raw Normal View History

#include "tileseteditormetatileselector.h"
#include "imageproviders.h"
#include "project.h"
#include <QPainter>
TilesetEditorMetatileSelector::TilesetEditorMetatileSelector(Tileset *primaryTileset, Tileset *secondaryTileset, Map *map)
: SelectablePixmapItem(32, 32, 1, 1) {
this->setTilesets(primaryTileset, secondaryTileset, false);
this->numMetatilesWide = 8;
this->map = map;
setAcceptHoverEvents(true);
this->usedMetatiles.resize(Project::getNumMetatilesTotal());
}
2023-12-20 02:21:16 +00:00
int TilesetEditorMetatileSelector::numRows(int numMetatiles) {
int numMetatilesHigh = numMetatiles / this->numMetatilesWide;
if (numMetatiles % this->numMetatilesWide != 0) {
// Round up height for incomplete last row
numMetatilesHigh++;
}
return numMetatilesHigh;
}
int TilesetEditorMetatileSelector::numRows() {
return this->numRows(this->primaryTileset->metatiles.length() + this->secondaryTileset->metatiles.length());
}
2022-10-05 13:54:04 +01:00
QImage TilesetEditorMetatileSelector::buildAllMetatilesImage() {
return this->buildImage(0, this->primaryTileset->metatiles.length() + this->secondaryTileset->metatiles.length());
2022-10-05 13:54:04 +01:00
}
QImage TilesetEditorMetatileSelector::buildPrimaryMetatilesImage() {
return this->buildImage(0, this->primaryTileset->metatiles.length());
2022-10-05 13:54:04 +01:00
}
QImage TilesetEditorMetatileSelector::buildSecondaryMetatilesImage() {
return this->buildImage(Project::getNumMetatilesPrimary(), this->secondaryTileset->metatiles.length());
2022-10-05 13:54:04 +01:00
}
QImage TilesetEditorMetatileSelector::buildImage(int metatileIdStart, int numMetatiles) {
2023-12-20 02:21:16 +00:00
int numMetatilesHigh = this->numRows(numMetatiles);
int numPrimary = this->primaryTileset->metatiles.length();
int maxPrimary = Project::getNumMetatilesPrimary();
bool includesPrimary = metatileIdStart < maxPrimary;
2022-10-05 13:54:04 +01:00
QImage image(this->numMetatilesWide * 32, numMetatilesHigh * 32, QImage::Format_RGBA8888);
image.fill(Qt::magenta);
QPainter painter(&image);
for (int i = 0; i < numMetatiles; i++) {
int metatileId = i + metatileIdStart;
if (includesPrimary && metatileId >= numPrimary)
metatileId += maxPrimary - numPrimary; // Skip over unused region of primary tileset
QImage metatile_image = getMetatileImage(
metatileId,
this->primaryTileset,
this->secondaryTileset,
map->metatileLayerOrder,
map->metatileLayerOpacity,
true)
.scaled(32, 32);
int map_y = i / this->numMetatilesWide;
int map_x = i % this->numMetatilesWide;
QPoint metatile_origin = QPoint(map_x * 32, map_y * 32);
painter.drawImage(metatile_origin, metatile_image);
}
painter.end();
2022-10-05 13:54:04 +01:00
return image;
}
void TilesetEditorMetatileSelector::draw() {
this->setPixmap(QPixmap::fromImage(this->buildAllMetatilesImage()));
2023-12-31 19:06:47 +00:00
this->drawGrid();
this->drawSelection();
2023-12-31 19:06:47 +00:00
this->drawFilters();
}
bool TilesetEditorMetatileSelector::select(uint16_t metatileId) {
if (!Tileset::metatileIsValid(metatileId, this->primaryTileset, this->secondaryTileset)) return false;
QPoint coords = this->getMetatileIdCoords(metatileId);
SelectablePixmapItem::select(coords.x(), coords.y(), 0, 0);
this->selectedMetatile = metatileId;
emit selectedMetatileChanged(metatileId);
return true;
}
void TilesetEditorMetatileSelector::setTilesets(Tileset *primaryTileset, Tileset *secondaryTileset, bool draw) {
this->primaryTileset = primaryTileset;
this->secondaryTileset = secondaryTileset;
if (draw) this->draw();
}
void TilesetEditorMetatileSelector::updateSelectedMetatile() {
QPoint origin = this->getSelectionStart();
uint16_t metatileId = this->getMetatileId(origin.x(), origin.y());
if (Tileset::metatileIsValid(metatileId, this->primaryTileset, this->secondaryTileset))
this->selectedMetatile = metatileId;
else
2021-02-17 02:45:54 +00:00
this->selectedMetatile = Project::getNumMetatilesPrimary() + this->secondaryTileset->metatiles.length() - 1;
emit selectedMetatileChanged(this->selectedMetatile);
}
2022-03-30 23:03:13 +01:00
uint16_t TilesetEditorMetatileSelector::getSelectedMetatileId() {
return this->selectedMetatile;
}
uint16_t TilesetEditorMetatileSelector::getMetatileId(int x, int y) {
int index = y * this->numMetatilesWide + x;
2021-02-17 02:45:54 +00:00
if (index < this->primaryTileset->metatiles.length()) {
return static_cast<uint16_t>(index);
} else {
2021-02-17 02:45:54 +00:00
return static_cast<uint16_t>(Project::getNumMetatilesPrimary() + index - this->primaryTileset->metatiles.length());
}
}
bool TilesetEditorMetatileSelector::shouldAcceptEvent(QGraphicsSceneMouseEvent *event) {
QPoint pos = this->getCellPos(event->pos());
return Tileset::metatileIsValid(getMetatileId(pos.x(), pos.y()), this->primaryTileset, this->secondaryTileset);
}
void TilesetEditorMetatileSelector::mousePressEvent(QGraphicsSceneMouseEvent *event) {
if (!shouldAcceptEvent(event)) return;
SelectablePixmapItem::mousePressEvent(event);
this->updateSelectedMetatile();
}
void TilesetEditorMetatileSelector::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
if (!shouldAcceptEvent(event)) return;
SelectablePixmapItem::mouseMoveEvent(event);
this->updateSelectedMetatile();
emit hoveredMetatileChanged(this->selectedMetatile);
}
void TilesetEditorMetatileSelector::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
if (!shouldAcceptEvent(event)) return;
SelectablePixmapItem::mouseReleaseEvent(event);
this->updateSelectedMetatile();
}
void TilesetEditorMetatileSelector::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
QPoint pos = this->getCellPos(event->pos());
uint16_t metatileId = this->getMetatileId(pos.x(), pos.y());
emit this->hoveredMetatileChanged(metatileId);
}
void TilesetEditorMetatileSelector::hoverLeaveEvent(QGraphicsSceneHoverEvent*) {
emit this->hoveredMetatileCleared();
}
QPoint TilesetEditorMetatileSelector::getMetatileIdCoords(uint16_t metatileId) {
if (!Tileset::metatileIsValid(metatileId, this->primaryTileset, this->secondaryTileset))
{
// Invalid metatile id.
return QPoint(0, 0);
2021-02-17 02:45:54 +00:00
}
int index = metatileId < Project::getNumMetatilesPrimary()
? metatileId
2021-02-17 02:45:54 +00:00
: metatileId - Project::getNumMetatilesPrimary() + this->primaryTileset->metatiles.length();
return QPoint(index % this->numMetatilesWide, index / this->numMetatilesWide);
}
QPoint TilesetEditorMetatileSelector::getMetatileIdCoordsOnWidget(uint16_t metatileId) {
QPoint pos = getMetatileIdCoords(metatileId);
pos.rx() = (pos.x() * this->cellWidth) + (this->cellWidth / 2);
pos.ry() = (pos.y() * this->cellHeight) + (this->cellHeight / 2);
return pos;
}
2023-12-31 19:06:47 +00:00
void TilesetEditorMetatileSelector::drawGrid() {
if (!this->showGrid)
return;
QPixmap pixmap = this->pixmap();
QPainter painter(&pixmap);
const int numColumns = this->numMetatilesWide;
const int numRows = this->numRows();
for (int column = 1; column < numColumns; column++) {
int x = column * 32;
painter.drawLine(x, 0, x, numRows * 32);
}
for (int row = 1; row < numRows; row++) {
int y = row * 32;
painter.drawLine(0, y, numColumns * 32, y);
2023-12-20 02:21:16 +00:00
}
2023-12-31 19:06:47 +00:00
painter.end();
this->setPixmap(pixmap);
}
void TilesetEditorMetatileSelector::drawFilters() {
if (selectorShowUnused) {
drawUnused();
}
if (selectorShowCounts) {
drawCounts();
}
}
void TilesetEditorMetatileSelector::drawUnused() {
// setup the circle with a line through it image to layer above unused metatiles
QPixmap redX(32, 32);
redX.fill(Qt::transparent);
QPen whitePen(Qt::white);
whitePen.setWidth(1);
2021-07-21 23:55:33 +01:00
QPen pinkPen(Qt::magenta);
pinkPen.setWidth(1);
QPainter oPainter(&redX);
oPainter.setPen(whitePen);
oPainter.drawEllipse(QRect(1, 1, 30, 30));
2021-07-21 23:55:33 +01:00
oPainter.setPen(pinkPen);
oPainter.drawEllipse(QRect(2, 2, 28, 28));
oPainter.drawEllipse(QRect(3, 3, 26, 26));
oPainter.setPen(whitePen);
oPainter.drawEllipse(QRect(4, 4, 24, 24));
whitePen.setWidth(5);
oPainter.setPen(whitePen);
oPainter.drawLine(0, 0, 31, 31);
2021-07-21 23:55:33 +01:00
pinkPen.setWidth(3);
oPainter.setPen(pinkPen);
oPainter.drawLine(2, 2, 29, 29);
oPainter.end();
// draw symbol on unused metatiles
QPixmap metatilesPixmap = this->pixmap();
QPainter unusedPainter(&metatilesPixmap);
2021-07-21 23:55:33 +01:00
unusedPainter.setOpacity(0.5);
2021-07-23 17:11:35 +01:00
int primaryLength = this->primaryTileset->metatiles.length();
int length_ = primaryLength + this->secondaryTileset->metatiles.length();
for (int i = 0; i < length_; i++) {
int tile = i;
if (i >= primaryLength) {
tile += Project::getNumMetatilesPrimary() - primaryLength;
}
if (!usedMetatiles[tile]) {
2021-07-23 17:11:35 +01:00
unusedPainter.drawPixmap((i % 8) * 32, (i / 8) * 32, redX);
}
}
unusedPainter.end();
this->setPixmap(metatilesPixmap);
}
void TilesetEditorMetatileSelector::drawCounts() {
QPen blackPen(Qt::black);
blackPen.setWidth(1);
QPixmap metatilesPixmap = this->pixmap();
QPainter countPainter(&metatilesPixmap);
countPainter.setPen(blackPen);
for (int tile = 0; tile < this->usedMetatiles.size(); tile++) {
int count = usedMetatiles[tile];
QString countText = QString::number(count);
if (count > 1000) countText = ">1k";
countPainter.drawText((tile % 8) * 32, (tile / 8) * 32 + 32, countText);
}
// write in white and black for contrast
QPen whitePen(Qt::white);
whitePen.setWidth(1);
countPainter.setPen(whitePen);
2021-07-23 17:11:35 +01:00
int primaryLength = this->primaryTileset->metatiles.length();
int length_ = primaryLength + this->secondaryTileset->metatiles.length();
for (int i = 0; i < length_; i++) {
int tile = i;
if (i >= primaryLength) {
tile += Project::getNumMetatilesPrimary() - primaryLength;
}
int count = usedMetatiles[tile];
QString countText = QString::number(count);
if (count > 1000) countText = ">1k";
2021-07-23 17:11:35 +01:00
countPainter.drawText((i % 8) * 32 + 1, (i / 8) * 32 + 32 - 1, countText);
}
countPainter.end();
this->setPixmap(metatilesPixmap);
}