mirror of
https://github.com/huderlem/porymap.git
synced 2026-03-22 01:54:46 -05:00
248 lines
8.8 KiB
C++
248 lines
8.8 KiB
C++
#include "imageproviders.h"
|
|
#include "metatileselector.h"
|
|
#include "project.h"
|
|
#include <QPainter>
|
|
|
|
QSize MetatileSelector::getSelectionDimensions() const {
|
|
if (this->prefabSelection || this->externalSelection)
|
|
return selection.dimensions;
|
|
return SelectablePixmapItem::getSelectionDimensions();
|
|
}
|
|
|
|
int MetatileSelector::numPrimaryMetatilesRounded() const {
|
|
if (!primaryTileset())
|
|
return 0;
|
|
return Util::roundUpToMultiple(primaryTileset()->numMetatiles(), this->numMetatilesWide);
|
|
}
|
|
|
|
void MetatileSelector::updateBasePixmap() {
|
|
this->basePixmap = QPixmap::fromImage(getMetatileSheetImage(this->layout, this->numMetatilesWide));
|
|
}
|
|
|
|
void MetatileSelector::draw() {
|
|
if (this->basePixmap.isNull())
|
|
updateBasePixmap();
|
|
setPixmap(this->basePixmap);
|
|
drawSelection();
|
|
}
|
|
|
|
void MetatileSelector::drawSelection() {
|
|
if (!this->prefabSelection && (!this->externalSelection || (this->externalSelectionWidth == 1 && this->externalSelectionHeight == 1))) {
|
|
SelectablePixmapItem::drawSelection();
|
|
}
|
|
}
|
|
|
|
bool MetatileSelector::select(uint16_t metatileId) {
|
|
bool ok;
|
|
QPoint pos = metatileIdToPos(metatileId, &ok);
|
|
if (!ok) {
|
|
return false;
|
|
}
|
|
this->externalSelection = false;
|
|
this->prefabSelection = false;
|
|
this->selection = MetatileSelection{
|
|
QSize(1, 1),
|
|
false,
|
|
QList<MetatileSelectionItem>({MetatileSelectionItem{true, metatileId}}),
|
|
QList<CollisionSelectionItem>(),
|
|
};
|
|
SelectablePixmapItem::select(pos);
|
|
this->updateSelectedMetatiles();
|
|
return true;
|
|
}
|
|
|
|
void MetatileSelector::selectFromMap(uint16_t metatileId, uint16_t collision, uint16_t elevation) {
|
|
QPair<uint16_t, uint16_t> movePermissions(collision, elevation);
|
|
this->setExternalSelection(1, 1, {metatileId}, {movePermissions});
|
|
}
|
|
|
|
void MetatileSelector::setLayout(Layout *layout) {
|
|
this->layout = layout;
|
|
if (this->externalSelection)
|
|
this->updateExternalSelectedMetatiles();
|
|
else
|
|
this->updateSelectedMetatiles();
|
|
|
|
updateBasePixmap();
|
|
draw();
|
|
}
|
|
|
|
void MetatileSelector::refresh() {
|
|
setLayout(this->layout);
|
|
}
|
|
|
|
void MetatileSelector::setExternalSelection(int width, int height, const QList<uint16_t> &metatiles, const QList<QPair<uint16_t, uint16_t>> &collisions) {
|
|
this->prefabSelection = false;
|
|
this->externalSelection = true;
|
|
this->externalSelectionWidth = width;
|
|
this->externalSelectionHeight = height;
|
|
this->externalSelectedMetatiles.clear();
|
|
this->selection.metatileItems.clear();
|
|
this->selection.collisionItems.clear();
|
|
this->selection.hasCollision = true;
|
|
this->selection.dimensions = QSize(width, height);
|
|
for (int i = 0; i < qMin(metatiles.length(), collisions.length()); i++) {
|
|
uint16_t metatileId = metatiles.at(i);
|
|
uint16_t collision = collisions.at(i).first;
|
|
uint16_t elevation = collisions.at(i).second;
|
|
this->selection.collisionItems.append(CollisionSelectionItem{true, collision, elevation});
|
|
this->externalSelectedMetatiles.append(metatileId);
|
|
if (!this->layout->metatileIsValid(metatileId))
|
|
metatileId = 0;
|
|
this->selection.metatileItems.append(MetatileSelectionItem{true, metatileId});
|
|
}
|
|
if (this->selection.metatileItems.length() == 1) {
|
|
SelectablePixmapItem::select(metatileIdToPos(this->selection.metatileItems.first().metatileId));
|
|
}
|
|
|
|
this->draw();
|
|
emit selectedMetatilesChanged();
|
|
}
|
|
|
|
void MetatileSelector::setPrefabSelection(MetatileSelection selection) {
|
|
this->externalSelection = false;
|
|
this->prefabSelection = true;
|
|
this->externalSelectedMetatiles.clear();
|
|
this->selection = selection;
|
|
this->draw();
|
|
emit selectedMetatilesChanged();
|
|
}
|
|
|
|
bool MetatileSelector::positionIsValid(const QPoint &pos) const {
|
|
bool ok;
|
|
posToMetatileId(pos, &ok);
|
|
return ok;
|
|
}
|
|
|
|
void MetatileSelector::mousePressEvent(QGraphicsSceneMouseEvent *event) {
|
|
QPoint pos = this->getCellPos(event->pos());
|
|
if (!positionIsValid(pos))
|
|
return;
|
|
|
|
this->cellPos = pos;
|
|
SelectablePixmapItem::mousePressEvent(event);
|
|
this->updateSelectedMetatiles();
|
|
}
|
|
|
|
void MetatileSelector::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
|
|
QPoint pos = this->getCellPos(event->pos());
|
|
if (!positionIsValid(pos) || this->cellPos == pos)
|
|
return;
|
|
|
|
this->cellPos = pos;
|
|
SelectablePixmapItem::mouseMoveEvent(event);
|
|
this->updateSelectedMetatiles();
|
|
this->hoverChanged();
|
|
}
|
|
|
|
void MetatileSelector::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
|
|
QPoint pos = this->getCellPos(event->pos());
|
|
if (!positionIsValid(pos))
|
|
return;
|
|
SelectablePixmapItem::mouseReleaseEvent(event);
|
|
}
|
|
|
|
void MetatileSelector::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
|
|
QPoint pos = this->getCellPos(event->pos());
|
|
if (this->cellPos == pos)
|
|
return;
|
|
|
|
this->cellPos = pos;
|
|
this->hoverChanged();
|
|
}
|
|
|
|
void MetatileSelector::hoverChanged() {
|
|
bool ok;
|
|
uint16_t metatileId = posToMetatileId(this->cellPos, &ok);
|
|
if (ok) {
|
|
emit this->hoveredMetatileSelectionChanged(metatileId);
|
|
} else {
|
|
emit this->hoveredMetatileSelectionCleared();
|
|
this->cellPos = QPoint(-1, -1);
|
|
}
|
|
}
|
|
|
|
void MetatileSelector::hoverLeaveEvent(QGraphicsSceneHoverEvent*) {
|
|
emit this->hoveredMetatileSelectionCleared();
|
|
this->cellPos = QPoint(-1, -1);
|
|
}
|
|
|
|
void MetatileSelector::updateSelectedMetatiles() {
|
|
this->externalSelection = false;
|
|
this->prefabSelection = false;
|
|
this->selection.metatileItems.clear();
|
|
this->selection.collisionItems.clear();
|
|
this->selection.hasCollision = false;
|
|
this->selection.dimensions = this->getSelectionDimensions();
|
|
QPoint origin = this->getSelectionStart();
|
|
for (int j = 0; j < this->selection.dimensions.height(); j++) {
|
|
for (int i = 0; i < this->selection.dimensions.width(); i++) {
|
|
uint16_t metatileId = posToMetatileId(origin.x() + i, origin.y() + j);
|
|
this->selection.metatileItems.append(MetatileSelectionItem{true, metatileId});
|
|
}
|
|
}
|
|
emit selectedMetatilesChanged();
|
|
}
|
|
|
|
void MetatileSelector::updateExternalSelectedMetatiles() {
|
|
this->selection.metatileItems.clear();
|
|
this->selection.dimensions = QSize(this->externalSelectionWidth, this->externalSelectionHeight);
|
|
for (int i = 0; i < this->externalSelectedMetatiles.count(); ++i) {
|
|
uint16_t metatileId = this->externalSelectedMetatiles.at(i);
|
|
if (!this->layout->metatileIsValid(metatileId))
|
|
metatileId = 0;
|
|
this->selection.metatileItems.append(MetatileSelectionItem{true, metatileId});
|
|
}
|
|
emit selectedMetatilesChanged();
|
|
}
|
|
|
|
uint16_t MetatileSelector::posToMetatileId(const QPoint &pos, bool *ok) const {
|
|
return posToMetatileId(pos.x(), pos.y(), ok);
|
|
}
|
|
|
|
uint16_t MetatileSelector::posToMetatileId(int x, int y, bool *ok) const {
|
|
if (ok) *ok = true;
|
|
int index = y * this->numMetatilesWide + x;
|
|
uint16_t metatileId = static_cast<uint16_t>(index);
|
|
if (primaryTileset() && primaryTileset()->containsMetatileId(metatileId)) {
|
|
return metatileId;
|
|
}
|
|
|
|
// There's some extra handling here because we round the tilesets to keep them on separate rows.
|
|
// This means if the maximum number of primary metatiles is not divisible by the metatile width
|
|
// then the metatiles we used to round the primary tileset would have the index of valid secondary metatiles.
|
|
// These need to be ignored, or they'll appear to be duplicates of the subseqeunt secondary metatiles.
|
|
int numPrimaryRounded = numPrimaryMetatilesRounded();
|
|
int firstSecondaryRow = numPrimaryRounded / this->numMetatilesWide;
|
|
metatileId = static_cast<uint16_t>(Project::getNumMetatilesPrimary() + index - numPrimaryRounded);
|
|
if (secondaryTileset() && secondaryTileset()->containsMetatileId(metatileId) && y >= firstSecondaryRow) {
|
|
return metatileId;
|
|
}
|
|
|
|
if (ok) *ok = false;
|
|
return 0;
|
|
}
|
|
|
|
QPoint MetatileSelector::metatileIdToPos(uint16_t metatileId, bool *ok) const {
|
|
if (primaryTileset() && primaryTileset()->containsMetatileId(metatileId)) {
|
|
if (ok) *ok = true;
|
|
int index = metatileId;
|
|
return QPoint(index % this->numMetatilesWide, index / this->numMetatilesWide);
|
|
}
|
|
if (secondaryTileset() && secondaryTileset()->containsMetatileId(metatileId)) {
|
|
if (ok) *ok = true;
|
|
int index = metatileId - Project::getNumMetatilesPrimary() + numPrimaryMetatilesRounded();
|
|
return QPoint(index % this->numMetatilesWide, index / this->numMetatilesWide);
|
|
}
|
|
|
|
if (ok) *ok = false;
|
|
return QPoint(0,0);
|
|
}
|
|
|
|
QPoint MetatileSelector::getMetatileIdCoordsOnWidget(uint16_t metatileId) const {
|
|
QPoint pos = metatileIdToPos(metatileId);
|
|
pos.rx() = (pos.x() * this->cellWidth) + (this->cellWidth / 2);
|
|
pos.ry() = (pos.y() * this->cellHeight) + (this->cellHeight / 2);
|
|
return pos;
|
|
}
|