diff --git a/core/maplayout.cpp b/core/maplayout.cpp new file mode 100644 index 00000000..b4fdb18d --- /dev/null +++ b/core/maplayout.cpp @@ -0,0 +1,2 @@ +#include "maplayout.h" + diff --git a/core/maplayout.h b/core/maplayout.h new file mode 100644 index 00000000..ad178ece --- /dev/null +++ b/core/maplayout.h @@ -0,0 +1,41 @@ +#ifndef MAPLAYOUT_H +#define MAPLAYOUT_H + +#include "blockdata.h" +#include "tileset.h" +#include +#include +#include + +class MapLayout { +public: + MapLayout() {} + int index; + QString name; + QString label; + QString width; + QString height; + QString border_label; + QString border_path; + QString blockdata_label; + QString blockdata_path; + QString tileset_primary_label; + QString tileset_secondary_label; + Tileset *tileset_primary = nullptr; + Tileset *tileset_secondary = nullptr; + Blockdata* blockdata = nullptr; + QImage border_image; + QPixmap border_pixmap; + Blockdata *border = nullptr; + Blockdata *cached_blockdata = nullptr; + Blockdata *cached_collision = nullptr; + Blockdata *cached_border = nullptr; + bool has_unsaved_changes = false; +public: + static QString getNameFromLabel(QString label) { + // ASSUMPTION: strip off "_Layout" from layout label. Directories in 'data/layouts/' must be well-formed. + return label.replace(label.lastIndexOf("_Layout"), label.length(), ""); + } +}; + +#endif // MAPLAYOUT_H diff --git a/editor.cpp b/editor.cpp index 66e1a516..afbbd9d0 100755 --- a/editor.cpp +++ b/editor.cpp @@ -322,6 +322,18 @@ void Editor::onHoveredMovementPermissionCleared() { map->clearHoveredMovementPermissionTile(); } +void Editor::onHoveredMetatileSelectionChanged(uint16_t metatileId) { + map->hoveredMetatileSelectionChanged(metatileId); +} + +void Editor::onHoveredMetatileSelectionCleared() { + map->clearHoveredMetatileSelection(); +} + +void Editor::onSelectedMetatilesChanged() { + this->redrawCurrentMetatilesSelection(); +} + void Editor::setConnectionsVisibility(bool visible) { for (QGraphicsPixmapItem* item : connection_items) { item->setVisible(visible); @@ -335,12 +347,7 @@ void Editor::setMap(QString map_name) { } if (project) { map = project->loadMap(map_name); - connect(map, &Map::paintTileChanged, [=]() { - lastSelectedMetatilesFromMap = false; - redrawCurrentMetatilesSelection(); - }); selected_events->clear(); - updateCurrentMetatilesSelection(); displayMap(); updateSelectedEvents(); } @@ -398,15 +405,6 @@ void Editor::mouseEvent_collision(QGraphicsSceneMouseEvent *event, CollisionPixm } } -void Editor::updateCurrentMetatilesSelection() { - if (lastSelectedMetatilesFromMap) { - // Remember the copied metatiles from the previously-opened map - map->selected_metatiles_width = this->copiedMetatileSelectionWidth; - map->selected_metatiles_height = this->copiedMetatileSelectionHeight; - *map->selected_metatiles = *this->copiedMetatileSelection; - } -} - void Editor::displayMap() { if (!scene) scene = new QGraphicsScene; @@ -442,10 +440,10 @@ void Editor::displayMap() { map_item->pixmap().height() + 12 * th ); - displayMetatiles(); + displayMetatileSelector(); displayBorderMetatiles(); displayCurrentMetatilesSelection(); - displayCollisionMetatiles(); + displayMovementPermissionSelector(); displayMapEvents(); displayMapConnections(); displayMapBorder(); @@ -462,16 +460,27 @@ void Editor::displayMap() { } } -void Editor::displayMetatiles() { - if (metatiles_item && metatiles_item->scene()) { - metatiles_item->scene()->removeItem(metatiles_item); - delete metatiles_item; +void Editor::displayMetatileSelector() { + if (metatile_selector_item && metatile_selector_item->scene()) { + metatile_selector_item->scene()->removeItem(metatile_selector_item); + delete scene_metatiles; } scene_metatiles = new QGraphicsScene; - metatiles_item = new MetatilesPixmapItem(map); - metatiles_item->draw(); - scene_metatiles->addItem(metatiles_item); + if (!metatile_selector_item) { + metatile_selector_item = new MetatileSelector(8, map->layout->tileset_primary, map->layout->tileset_secondary); + connect(metatile_selector_item, SIGNAL(hoveredMetatileSelectionChanged(uint16_t)), + this, SLOT(onHoveredMetatileSelectionChanged(uint16_t))); + connect(metatile_selector_item, SIGNAL(hoveredMetatileSelectionCleared()), + this, SLOT(onHoveredMetatileSelectionCleared())); + connect(metatile_selector_item, SIGNAL(selectedMetatilesChanged()), + this, SLOT(onSelectedMetatilesChanged())); + metatile_selector_item->select(0); + } else { + metatile_selector_item->setTilesets(map->layout->tileset_primary, map->layout->tileset_secondary); + } + + scene_metatiles->addItem(metatile_selector_item); } void Editor::displayBorderMetatiles() { @@ -481,7 +490,7 @@ void Editor::displayBorderMetatiles() { } scene_selected_border_metatiles = new QGraphicsScene; - selected_border_metatiles_item = new BorderMetatilesPixmapItem(map); + selected_border_metatiles_item = new BorderMetatilesPixmapItem(map, this); selected_border_metatiles_item->draw(); scene_selected_border_metatiles->addItem(selected_border_metatiles_item); @@ -495,7 +504,7 @@ void Editor::displayCurrentMetatilesSelection() { } scene_current_metatile_selection = new QGraphicsScene; - scene_current_metatile_selection_item = new CurrentSelectedMetatilesPixmapItem(map); + scene_current_metatile_selection_item = new CurrentSelectedMetatilesPixmapItem(map, this); scene_current_metatile_selection_item->draw(); scene_current_metatile_selection->addItem(scene_current_metatile_selection_item); } @@ -507,20 +516,22 @@ void Editor::redrawCurrentMetatilesSelection() { } } -void Editor::displayCollisionMetatiles() { +void Editor::displayMovementPermissionSelector() { if (movement_permissions_selector_item && movement_permissions_selector_item->scene()) { movement_permissions_selector_item->scene()->removeItem(movement_permissions_selector_item); - delete movement_permissions_selector_item; + delete scene_collision_metatiles; } scene_collision_metatiles = new QGraphicsScene; - movement_permissions_selector_item = new MovementPermissionsSelector(); - connect(movement_permissions_selector_item, SIGNAL(hoveredMovementPermissionChanged(uint16_t, uint16_t)), - this, SLOT(onHoveredMovementPermissionChanged(uint16_t, uint16_t))); - connect(movement_permissions_selector_item, SIGNAL(hoveredMovementPermissionCleared()), - this, SLOT(onHoveredMovementPermissionCleared())); - movement_permissions_selector_item->select(0, 3); - movement_permissions_selector_item->draw(); + if (!movement_permissions_selector_item) { + movement_permissions_selector_item = new MovementPermissionsSelector(); + connect(movement_permissions_selector_item, SIGNAL(hoveredMovementPermissionChanged(uint16_t, uint16_t)), + this, SLOT(onHoveredMovementPermissionChanged(uint16_t, uint16_t))); + connect(movement_permissions_selector_item, SIGNAL(hoveredMovementPermissionCleared()), + this, SLOT(onHoveredMovementPermissionCleared())); + movement_permissions_selector_item->select(0, 3); + } + scene_collision_metatiles->addItem(movement_permissions_selector_item); } @@ -901,74 +912,17 @@ void Editor::toggleBorderVisibility(bool visible) this->setConnectionsVisibility(visible); } -void MetatilesPixmapItem::paintTileChanged() { - draw(); -} - -void MetatilesPixmapItem::draw() { - setPixmap(map->renderMetatiles()); -} - -void MetatilesPixmapItem::updateCurHoveredMetatile(QPointF pos) { - int x = static_cast(pos.x()) / 16; - int y = static_cast(pos.y()) / 16; - int width = pixmap().width() / 16; - int height = pixmap().height() / 16; - if (x < 0 || x >= width || y < 0 || y >= height) { - map->clearHoveredMetatile(); - } else { - int block = y * width + x; - map->hoveredMetatileChanged(block); - } -} - -void MetatilesPixmapItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { - updateCurHoveredMetatile(event->pos()); -} -void MetatilesPixmapItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *) { - map->clearHoveredMetatile(); -} -void MetatilesPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { - QPointF pos = event->pos(); - int x = static_cast(pos.x()) / 16; - int y = static_cast(pos.y()) / 16; - map->paint_metatile_initial_x = x; - map->paint_metatile_initial_y = y; - updateSelection(event->pos()); -} -void MetatilesPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { - updateCurHoveredMetatile(event->pos()); - updateSelection(event->pos()); -} -void MetatilesPixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { - updateSelection(event->pos()); -} -void MetatilesPixmapItem::updateSelection(QPointF pos) { - int x = static_cast(pos.x()) / 16; - int y = static_cast(pos.y()) / 16; - int width = pixmap().width() / 16; - int height = pixmap().height() / 16; - if ((x >= 0 && x < width) && (y >=0 && y < height)) { - int x1 = x < map->paint_metatile_initial_x ? x : map->paint_metatile_initial_x; - int y1 = y < map->paint_metatile_initial_y ? y : map->paint_metatile_initial_y; - map->paint_tile_index = y1 * 8 + x1; - map->paint_tile_width = abs(map->paint_metatile_initial_x - x) + 1; - map->paint_tile_height = abs(map->paint_metatile_initial_y - y) + 1; - map->setSelectedMetatilesFromTilePicker(); - - emit map->paintTileChanged(); - } -} - void BorderMetatilesPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { + QList *selectedMetatiles = editor->metatile_selector_item->getSelectedMetatiles(); + QPoint selectionDimensions = editor->metatile_selector_item->getSelectionDimensions(); QPointF pos = event->pos(); int x = static_cast(pos.x()) / 16; int y = static_cast(pos.y()) / 16; - for (int i = 0; i < map->selected_metatiles_width && (i + x) < 2; i++) { - for (int j = 0; j < map->selected_metatiles_height && (j + y) < 2; j++) { + for (int i = 0; i < selectionDimensions.x() && (i + x) < 2; i++) { + for (int j = 0; j < selectionDimensions.y() && (j + y) < 2; j++) { int blockIndex = (j + y) * 2 + (i + x); - uint16_t tile = map->selected_metatiles->at(j * map->selected_metatiles_width + i); + uint16_t tile = selectedMetatiles->at(j * selectionDimensions.x() + i); (*map->layout->border->blocks)[blockIndex].tile = tile; } } @@ -982,15 +936,15 @@ void BorderMetatilesPixmapItem::draw() { QPainter painter(&image); QList *blocks = map->layout->border->blocks; - for (int i = 0; i < 2; i++) - for (int j = 0; j < 2; j++) - { - int x = i * 16; - int y = j * 16; - int index = j * 2 + i; - QImage metatile_image = Tileset::getMetatileImage(blocks->value(index).tile, map->layout->tileset_primary, map->layout->tileset_secondary); - QPoint metatile_origin = QPoint(x, y); - painter.drawImage(metatile_origin, metatile_image); + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + int x = i * 16; + int y = j * 16; + int index = j * 2 + i; + QImage metatile_image = Tileset::getMetatileImage(blocks->value(index).tile, map->layout->tileset_primary, map->layout->tileset_secondary); + QPoint metatile_origin = QPoint(x, y); + painter.drawImage(metatile_origin, metatile_image); + } } painter.end(); @@ -998,20 +952,22 @@ void BorderMetatilesPixmapItem::draw() { } void CurrentSelectedMetatilesPixmapItem::draw() { - int width = map->selected_metatiles_width * 16; - int height = map->selected_metatiles_height * 16; + QList *selectedMetatiles = editor->metatile_selector_item->getSelectedMetatiles(); + QPoint selectionDimensions = editor->metatile_selector_item->getSelectionDimensions(); + int width = selectionDimensions.x() * 16; + int height = selectionDimensions.y() * 16; QImage image(width, height, QImage::Format_RGBA8888); QPainter painter(&image); - for (int i = 0; i < map->selected_metatiles_width; i++) - for (int j = 0; j < map->selected_metatiles_height; j++) - { - int x = i * 16; - int y = j * 16; - int index = j * map->selected_metatiles_width + i; - QImage metatile_image = Tileset::getMetatileImage(map->selected_metatiles->at(index), map->layout->tileset_primary, map->layout->tileset_secondary); - QPoint metatile_origin = QPoint(x, y); - painter.drawImage(metatile_origin, metatile_image); + for (int i = 0; i < selectionDimensions.x(); i++) { + for (int j = 0; j < selectionDimensions.y(); j++) { + int x = i * 16; + int y = j * 16; + int index = j * selectionDimensions.x() + i; + QImage metatile_image = Tileset::getMetatileImage(selectedMetatiles->at(index), map->layout->tileset_primary, map->layout->tileset_secondary); + QPoint metatile_origin = QPoint(x, y); + painter.drawImage(metatile_origin, metatile_image); + } } painter.end(); @@ -1085,7 +1041,8 @@ void MapPixmapItem::paint(QGraphicsSceneMouseEvent *event) { // Paint onto the map. bool smartPathsEnabled = event->modifiers() & Qt::ShiftModifier; - if ((map->smart_paths_enabled || smartPathsEnabled) && map->selected_metatiles_width == 3 && map->selected_metatiles_height == 3) { + QPoint selectionDimensions = editor->metatile_selector_item->getSelectionDimensions(); + if ((map->smart_paths_enabled || smartPathsEnabled) && selectionDimensions.x() == 3 && selectionDimensions.y() == 3) { paintSmartPath(x, y); } else { paintNormal(x, y); @@ -1140,22 +1097,26 @@ void MapPixmapItem::shift(QGraphicsSceneMouseEvent *event) { } void MapPixmapItem::paintNormal(int x, int y) { + QPoint selectionDimensions = editor->metatile_selector_item->getSelectionDimensions(); + QList *selectedMetatiles = editor->metatile_selector_item->getSelectedMetatiles(); + // Snap the selected position to the top-left of the block boundary. // This allows painting via dragging the mouse to tile the painted region. int xDiff = x - map->paint_tile_initial_x; int yDiff = y - map->paint_tile_initial_y; - if (xDiff < 0 && xDiff % map->selected_metatiles_width != 0) xDiff -= map->selected_metatiles_width; - if (yDiff < 0 && yDiff % map->selected_metatiles_height != 0) yDiff -= map->selected_metatiles_height; + if (xDiff < 0 && xDiff % selectionDimensions.x() != 0) xDiff -= selectionDimensions.x(); + if (yDiff < 0 && yDiff % selectionDimensions.y() != 0) yDiff -= selectionDimensions.y(); - x = map->paint_tile_initial_x + (xDiff / map->selected_metatiles_width) * map->selected_metatiles_width; - y = map->paint_tile_initial_y + (yDiff / map->selected_metatiles_height) * map->selected_metatiles_height; - for (int i = 0; i < map->selected_metatiles_width && i + x < map->getWidth(); i++) - for (int j = 0; j < map->selected_metatiles_height && j + y < map->getHeight(); j++) { + x = map->paint_tile_initial_x + (xDiff / selectionDimensions.x()) * selectionDimensions.x(); + y = map->paint_tile_initial_y + (yDiff / selectionDimensions.y()) * selectionDimensions.y(); + + for (int i = 0; i < selectionDimensions.x() && i + x < map->getWidth(); i++) + for (int j = 0; j < selectionDimensions.y() && j + y < map->getHeight(); j++) { int actualX = i + x; int actualY = j + y; Block *block = map->getBlock(actualX, actualY); if (block) { - block->tile = map->selected_metatiles->at(j * map->selected_metatiles_width + i); + block->tile = selectedMetatiles->at(j * selectionDimensions.x() + i); map->_setBlock(actualX, actualY, *block); } } @@ -1183,14 +1144,17 @@ QList MapPixmapItem::smartPathTable = QList({ 4, // 1111 }); -#define IS_SMART_PATH_TILE(block) (map->selected_metatiles->contains(block->tile)) +#define IS_SMART_PATH_TILE(block) (selectedMetatiles->contains(block->tile)) void MapPixmapItem::paintSmartPath(int x, int y) { + QPoint selectionDimensions = editor->metatile_selector_item->getSelectionDimensions(); + QList *selectedMetatiles = editor->metatile_selector_item->getSelectedMetatiles(); + // Smart path should never be enabled without a 3x3 block selection. - if (map->selected_metatiles_width != 3 || map->selected_metatiles_height != 3) return; + if (selectionDimensions.x() != 3 || selectionDimensions.y() != 3) return; // Shift to the middle tile of the smart path selection. - uint16_t openTile = map->selected_metatiles->at(4); + uint16_t openTile = selectedMetatiles->at(4); // Fill the region with the open tile. for (int i = 0; i <= 1; i++) @@ -1242,7 +1206,7 @@ void MapPixmapItem::paintSmartPath(int x, int y) { if (left && IS_SMART_PATH_TILE(left)) id += 8; - block->tile = map->selected_metatiles->at(smartPathTable[id]); + block->tile = selectedMetatiles->at(smartPathTable[id]); map->_setBlock(actualX, actualY, *block); } } @@ -1263,8 +1227,8 @@ void MapPixmapItem::updateMetatileSelection(QGraphicsSceneMouseEvent *event) { selection_origin = QPoint(x, y); selection.clear(); selection.append(QPoint(x, y)); - editor->copiedMetatileSelectionWidth = 1; - editor->copiedMetatileSelectionHeight = 1; + uint16_t metatileId = map->getBlock(x, y)->tile; + editor->metatile_selector_item->select(metatileId); } else if (event->type() == QEvent::GraphicsSceneMouseMove) { QPoint pos = QPoint(x, y); int x1 = selection_origin.x(); @@ -1280,21 +1244,13 @@ void MapPixmapItem::updateMetatileSelection(QGraphicsSceneMouseEvent *event) { } } - editor->copiedMetatileSelectionWidth = x2 - x1 + 1; - editor->copiedMetatileSelectionHeight = y2 - y1 + 1; + QList metatiles; + for (QPoint point : selection) { + metatiles.append(map->getBlock(point.x(), point.y())->tile); + } + + editor->metatile_selector_item->setExternalSelection(x2 - x1 + 1, y2 - y1 + 1, &metatiles); } - - editor->copiedMetatileSelection->clear(); - for (QPoint point : selection) { - editor->copiedMetatileSelection->append(map->getBlock(point.x(), point.y())->tile); - } - - editor->lastSelectedMetatilesFromMap = true; - map->selected_metatiles_width = editor->copiedMetatileSelectionWidth; - map->selected_metatiles_height = editor->copiedMetatileSelectionHeight; - *map->selected_metatiles = *editor->copiedMetatileSelection; - - editor->redrawCurrentMetatilesSelection(); } void MapPixmapItem::floodFill(QGraphicsSceneMouseEvent *event) { @@ -1306,10 +1262,12 @@ void MapPixmapItem::floodFill(QGraphicsSceneMouseEvent *event) { int x = static_cast(pos.x()) / 16; int y = static_cast(pos.y()) / 16; Block *block = map->getBlock(x, y); - int tile = map->selected_metatiles->first(); + QList *selectedMetatiles = editor->metatile_selector_item->getSelectedMetatiles(); + QPoint selectionDimensions = editor->metatile_selector_item->getSelectionDimensions(); + int tile = selectedMetatiles->first(); if (block && block->tile != tile) { bool smartPathsEnabled = event->modifiers() & Qt::ShiftModifier; - if ((map->smart_paths_enabled || smartPathsEnabled) && map->selected_metatiles_width == 3 && map->selected_metatiles_height == 3) + if ((map->smart_paths_enabled || smartPathsEnabled) && selectionDimensions.x() == 3 && selectionDimensions.y() == 3) this->_floodFillSmartPath(x, y); else this->_floodFill(x, y); @@ -1321,6 +1279,9 @@ void MapPixmapItem::floodFill(QGraphicsSceneMouseEvent *event) { } void MapPixmapItem::_floodFill(int initialX, int initialY) { + QPoint selectionDimensions = editor->metatile_selector_item->getSelectionDimensions(); + QList *selectedMetatiles = editor->metatile_selector_item->getSelectedMetatiles(); + QList todo; todo.append(QPoint(initialX, initialY)); while (todo.length()) { @@ -1335,11 +1296,11 @@ void MapPixmapItem::_floodFill(int initialX, int initialY) { int xDiff = x - initialX; int yDiff = y - initialY; - int i = xDiff % map->selected_metatiles_width; - int j = yDiff % map->selected_metatiles_height; - if (i < 0) i = map->selected_metatiles_width + i; - if (j < 0) j = map->selected_metatiles_height + j; - uint16_t tile = map->selected_metatiles->at(j * map->selected_metatiles_width + i); + int i = xDiff % selectionDimensions.x(); + int j = yDiff % selectionDimensions.y(); + if (i < 0) i = selectionDimensions.x() + i; + if (j < 0) j = selectionDimensions.y() + j; + uint16_t tile = selectedMetatiles->at(j * selectionDimensions.x() + i); uint16_t old_tile = block->tile; if (old_tile == tile) { continue; @@ -1363,11 +1324,14 @@ void MapPixmapItem::_floodFill(int initialX, int initialY) { } void MapPixmapItem::_floodFillSmartPath(int initialX, int initialY) { + QPoint selectionDimensions = editor->metatile_selector_item->getSelectionDimensions(); + QList *selectedMetatiles = editor->metatile_selector_item->getSelectedMetatiles(); + // Smart path should never be enabled without a 3x3 block selection. - if (map->selected_metatiles_width != 3 || map->selected_metatiles_height != 3) return; + if (selectionDimensions.x() != 3 || selectionDimensions.y() != 3) return; // Shift to the middle tile of the smart path selection. - uint16_t openTile = map->selected_metatiles->at(4); + uint16_t openTile = selectedMetatiles->at(4); // Flood fill the region with the open tile. QList todo; @@ -1438,7 +1402,7 @@ void MapPixmapItem::_floodFillSmartPath(int initialX, int initialY) { if (left && IS_SMART_PATH_TILE(left)) id += 8; - block->tile = map->selected_metatiles->at(smartPathTable[id]); + block->tile = selectedMetatiles->at(smartPathTable[id]); map->_setBlock(x, y, *block); // Visit neighbors if they are smart-path tiles, and don't revisit any. @@ -1469,12 +1433,7 @@ void MapPixmapItem::pick(QGraphicsSceneMouseEvent *event) { int y = static_cast(pos.y()) / 16; Block *block = map->getBlock(x, y); if (block) { - map->paint_tile_index = map->getDisplayedBlockIndex(block->tile); - map->paint_tile_width = 1; - map->paint_tile_height = 1; - map->setSelectedMetatilesFromTilePicker(); - - emit map->paintTileChanged(); + editor->metatile_selector_item->select(block->tile); } } @@ -1615,7 +1574,6 @@ void CollisionPixmapItem::pick(QGraphicsSceneMouseEvent *event) { Block *block = map->getBlock(x, y); if (block) { editor->movement_permissions_selector_item->select(block->collision, block->elevation); - emit map->paintCollisionChanged(map); } } @@ -1632,7 +1590,6 @@ void CollisionPixmapItem::updateMovementPermissionSelection(QGraphicsSceneMouseE Block *block = map->getBlock(x, y); editor->movement_permissions_selector_item->select(block->collision, block->elevation); - editor->movement_permissions_selector_item->draw(); } void DraggablePixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *mouse) { diff --git a/editor.h b/editor.h index 7b8eb677..32a3e3d1 100755 --- a/editor.h +++ b/editor.h @@ -9,6 +9,7 @@ #include #include +#include "ui/metatileselector.h" #include "ui/movementpermissionsselector.h" #include "project.h" #include "ui_mainwindow.h" @@ -38,13 +39,12 @@ public: void undo(); void redo(); void setMap(QString map_name); - void updateCurrentMetatilesSelection(); void displayMap(); - void displayMetatiles(); + void displayMetatileSelector(); void displayBorderMetatiles(); void displayCurrentMetatilesSelection(); void redrawCurrentMetatilesSelection(); - void displayCollisionMetatiles(); + void displayMovementPermissionSelector(); void displayElevationMetatiles(); void displayMapEvents(); void displayMapConnections(); @@ -95,7 +95,7 @@ public: QGraphicsScene *scene_selected_border_metatiles = nullptr; QGraphicsScene *scene_collision_metatiles = nullptr; QGraphicsScene *scene_elevation_metatiles = nullptr; - MetatilesPixmapItem *metatiles_item = nullptr; + MetatileSelector *metatile_selector_item = nullptr; BorderMetatilesPixmapItem *selected_border_metatiles_item = nullptr; CurrentSelectedMetatilesPixmapItem *scene_current_metatile_selection_item = nullptr; @@ -104,11 +104,6 @@ public: QList *events = nullptr; QList *selected_events = nullptr; - bool lastSelectedMetatilesFromMap = false; - int copiedMetatileSelectionWidth = 0; - int copiedMetatileSelectionHeight = 0; - QList *copiedMetatileSelection = new QList; - QString map_edit_mode; QString prev_edit_mode; QCursor cursor; @@ -151,6 +146,9 @@ private slots: void onBorderMetatilesChanged(); void onHoveredMovementPermissionChanged(uint16_t, uint16_t); void onHoveredMovementPermissionCleared(); + void onHoveredMetatileSelectionChanged(uint16_t); + void onHoveredMetatileSelectionCleared(); + void onSelectedMetatilesChanged(); signals: void objectsChanged(); @@ -362,37 +360,15 @@ signals: void connectionMoved(Connection*); }; -class MetatilesPixmapItem : public QObject, public QGraphicsPixmapItem { - Q_OBJECT -public: - MetatilesPixmapItem(Map *map_) { - map = map_; - setAcceptHoverEvents(true); - connect(map, SIGNAL(paintTileChanged()), this, SLOT(paintTileChanged())); - } - Map* map = nullptr; - virtual void draw(); -private: - void updateSelection(QPointF pos); -protected: - virtual void updateCurHoveredMetatile(QPointF pos); -private slots: - void paintTileChanged(); -protected: - void hoverMoveEvent(QGraphicsSceneHoverEvent*); - void hoverLeaveEvent(QGraphicsSceneHoverEvent*); - void mousePressEvent(QGraphicsSceneMouseEvent*); - void mouseMoveEvent(QGraphicsSceneMouseEvent*); - void mouseReleaseEvent(QGraphicsSceneMouseEvent*); -}; - class BorderMetatilesPixmapItem : public QObject, public QGraphicsPixmapItem { Q_OBJECT public: - BorderMetatilesPixmapItem(Map *map_) { + BorderMetatilesPixmapItem(Map *map_, Editor *editor_) { map = map_; + editor = editor_; setAcceptHoverEvents(true); } + Editor *editor = nullptr; Map* map = nullptr; virtual void draw(); signals: @@ -404,10 +380,12 @@ protected: class CurrentSelectedMetatilesPixmapItem : public QObject, public QGraphicsPixmapItem { Q_OBJECT public: - CurrentSelectedMetatilesPixmapItem(Map *map_) { + CurrentSelectedMetatilesPixmapItem(Map *map_, Editor *editor_) { map = map_; + editor = editor_; } Map* map = nullptr; + Editor *editor = nullptr; virtual void draw(); }; diff --git a/mainwindow.cpp b/mainwindow.cpp index 8c0c45b9..b1d8f4b5 100755 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -195,7 +195,7 @@ void MainWindow::redrawMapScene() ui->graphicsView_Metatiles->setScene(editor->scene_metatiles); //ui->graphicsView_Metatiles->setSceneRect(editor->scene_metatiles->sceneRect()); - ui->graphicsView_Metatiles->setFixedSize(editor->metatiles_item->pixmap().width() + 2, editor->metatiles_item->pixmap().height() + 2); + ui->graphicsView_Metatiles->setFixedSize(editor->metatile_selector_item->pixmap().width() + 2, editor->metatile_selector_item->pixmap().height() + 2); ui->graphicsView_BorderMetatile->setScene(editor->scene_selected_border_metatiles); ui->graphicsView_BorderMetatile->setFixedSize(editor->selected_border_metatiles_item->pixmap().width() + 2, editor->selected_border_metatiles_item->pixmap().height() + 2); diff --git a/map.cpp b/map.cpp index d21bec1a..c66feb34 100755 --- a/map.cpp +++ b/map.cpp @@ -10,11 +10,6 @@ Map::Map(QObject *parent) : QObject(parent) { - paint_tile_index = 1; - selected_metatiles_width = 1; - selected_metatiles_height = 1; - selected_metatiles = new QList; - selected_metatiles->append(1); } void Map::setName(QString mapName) { @@ -305,35 +300,6 @@ void Map::drawSelection(int i, int w, int selectionWidth, int selectionHeight, Q painter->restore(); } -QPixmap Map::renderMetatiles() { - if (!layout->tileset_primary || !layout->tileset_primary->metatiles - || !layout->tileset_secondary || !layout->tileset_secondary->metatiles) { - return QPixmap(); - } - int primary_length = layout->tileset_primary->metatiles->length(); - int length_ = primary_length + layout->tileset_secondary->metatiles->length(); - int width_ = 8; - int height_ = length_ / width_; - QImage image(width_ * 16, height_ * 16, QImage::Format_RGBA8888); - QPainter painter(&image); - for (int i = 0; i < length_; i++) { - int tile = i; - if (i >= primary_length) { - tile += Project::getNumMetatilesPrimary() - primary_length; - } - QImage metatile_image = Tileset::getMetatileImage(tile, layout->tileset_primary, layout->tileset_secondary); - int map_y = i / width_; - int map_x = i % width_; - QPoint metatile_origin = QPoint(map_x * 16, map_y * 16); - painter.drawImage(metatile_origin, metatile_image); - } - - drawSelection(paint_tile_index, width_, paint_tile_width, paint_tile_height, &painter, 16); - - painter.end(); - return QPixmap::fromImage(image); -} - void Map::setNewDimensionsBlockdata(int newWidth, int newHeight) { int oldWidth = getWidth(); int oldHeight = getHeight(); @@ -517,13 +483,12 @@ void Map::clearHoveredTile() { emit statusBarMessage(QString("")); } -void Map::hoveredMetatileChanged(int blockIndex) { - uint16_t tile = getSelectedBlockIndex(blockIndex); +void Map::hoveredMetatileSelectionChanged(uint16_t metatileId) { emit statusBarMessage(QString("Metatile: 0x%1") - .arg(QString("%1").arg(tile, 3, 16, QChar('0')).toUpper())); + .arg(QString("%1").arg(metatileId, 3, 16, QChar('0')).toUpper())); } -void Map::clearHoveredMetatile() { +void Map::clearHoveredMetatileSelection() { emit statusBarMessage(QString("")); } @@ -546,16 +511,3 @@ void Map::hoveredMovementPermissionTileChanged(int collision, int elevation) { void Map::clearHoveredMovementPermissionTile() { emit statusBarMessage(QString("")); } - -void Map::setSelectedMetatilesFromTilePicker() { - this->selected_metatiles_width = this->paint_tile_width; - this->selected_metatiles_height = this->paint_tile_height; - this->selected_metatiles->clear(); - for (int j = 0; j < this->paint_tile_height; j++) { - for (int i = 0; i < this->paint_tile_width; i++) { - uint16_t metatile = this->getSelectedBlockIndex(this->paint_tile_index + i + (j * 8)); - this->selected_metatiles->append(metatile); - } - } -} - diff --git a/map.h b/map.h index 60909193..992af76d 100755 --- a/map.h +++ b/map.h @@ -3,6 +3,7 @@ #include "core/tileset.h" #include "core/blockdata.h" +#include "core/maplayout.h" #include "event.h" #include @@ -85,37 +86,6 @@ public: QString map_name; }; -class MapLayout { -public: - MapLayout() {} - int index; - QString name; - QString label; - QString width; - QString height; - QString border_label; - QString border_path; - QString blockdata_label; - QString blockdata_path; - QString tileset_primary_label; - QString tileset_secondary_label; - Tileset *tileset_primary = nullptr; - Tileset *tileset_secondary = nullptr; - Blockdata* blockdata = nullptr; - QImage border_image; - QPixmap border_pixmap; - Blockdata *border = nullptr; - Blockdata *cached_blockdata = nullptr; - Blockdata *cached_collision = nullptr; - Blockdata *cached_border = nullptr; - bool has_unsaved_changes = false; -public: - static QString getNameFromLabel(QString label) { - // ASSUMPTION: strip off "_Layout" from layout label. Directories in 'data/layouts/' must be well-formed. - return label.replace(label.lastIndexOf("_Layout"), label.length(), ""); - } -}; - class Map : public QObject { Q_OBJECT @@ -158,7 +128,6 @@ public: uint16_t getSelectedBlockIndex(int); int getDisplayedBlockIndex(int); QPixmap render(bool ignoreCache); - QPixmap renderMetatiles(); QPixmap renderCollision(bool ignoreCache); QImage collision_image; @@ -175,16 +144,8 @@ public: QPixmap pixmap; QList metatile_images; bool smart_paths_enabled = false; - int paint_metatile_initial_x; - int paint_metatile_initial_y; - int paint_tile_index; - int paint_tile_width = 1; - int paint_tile_height = 1; int paint_tile_initial_x; int paint_tile_initial_y; - int selected_metatiles_width; - int selected_metatiles_height; - QList *selected_metatiles = nullptr; Block *getBlock(int x, int y); void setBlock(int x, int y, Block block); @@ -214,14 +175,11 @@ public: bool hasUnsavedChanges(); void hoveredTileChanged(int x, int y, int block); void clearHoveredTile(); - void hoveredMetatileChanged(int block); - void clearHoveredMetatile(); + void hoveredMetatileSelectionChanged(uint16_t); + void clearHoveredMetatileSelection(); void clearHoveredMovementPermissionTile(); - void setSelectedMetatilesFromTilePicker(); signals: - void paintTileChanged(); - void paintCollisionChanged(Map *map); void mapChanged(Map *map); void mapNeedsRedrawing(); void statusBarMessage(QString); diff --git a/porymap.pro b/porymap.pro index 214b60bd..2cf96b86 100755 --- a/porymap.pro +++ b/porymap.pro @@ -17,9 +17,11 @@ ICON = resources/icons/porymap-icon-1.ico SOURCES += core/block.cpp \ core/blockdata.cpp \ core/heallocation.cpp \ + core/maplayout.cpp \ core/metatile.cpp \ core/tile.cpp \ core/tileset.cpp \ + ui/metatileselector.cpp \ ui/movementpermissionsselector.cpp \ ui/selectablepixmapitem.cpp \ editor.cpp \ @@ -38,9 +40,11 @@ SOURCES += core/block.cpp \ HEADERS += core/block.h \ core/blockdata.h \ core/heallocation.h \ + core/maplayout.h \ core/metatile.h \ core/tile.h \ core/tileset.h \ + ui/metatileselector.h \ ui/movementpermissionsselector.h \ ui/selectablepixmapitem.h \ editor.h \ diff --git a/ui/metatileselector.cpp b/ui/metatileselector.cpp new file mode 100644 index 00000000..0afbcc82 --- /dev/null +++ b/ui/metatileselector.cpp @@ -0,0 +1,146 @@ +#include "metatileselector.h" +#include "project.h" +#include + +QPoint MetatileSelector::getSelectionDimensions() { + if (this->externalSelection) { + return QPoint(this->externalSelectionWidth, this->externalSelectionHeight); + } else { + return SelectablePixmapItem::getSelectionDimensions(); + } +} + +void MetatileSelector::draw() { + if (!this->primaryTileset || !this->primaryTileset->metatiles + || !this->secondaryTileset || !this->secondaryTileset->metatiles) { + this->setPixmap(QPixmap()); + } + + int primaryLength = this->primaryTileset->metatiles->length(); + int length_ = primaryLength + this->secondaryTileset->metatiles->length(); + int height_ = length_ / this->numMetatilesWide; + QImage image(this->numMetatilesWide * 16, height_ * 16, QImage::Format_RGBA8888); + QPainter painter(&image); + for (int i = 0; i < length_; i++) { + int tile = i; + if (i >= primaryLength) { + tile += Project::getNumMetatilesPrimary() - primaryLength; + } + QImage metatile_image = Tileset::getMetatileImage(tile, this->primaryTileset, this->secondaryTileset); + int map_y = i / this->numMetatilesWide; + int map_x = i % this->numMetatilesWide; + QPoint metatile_origin = QPoint(map_x * 16, map_y * 16); + painter.drawImage(metatile_origin, metatile_image); + } + + painter.end(); + this->setPixmap(QPixmap::fromImage(image)); + + if (!this->externalSelection) { + this->drawSelection(); + } +} + +void MetatileSelector::select(uint16_t metatileId) { + this->externalSelection = false; + QPoint coords = this->getMetatileIdCoords(metatileId); + SelectablePixmapItem::select(coords.x(), coords.y(), 0, 0); + this->updateSelectedMetatiles(); + emit selectedMetatilesChanged(); +} + +void MetatileSelector::setTilesets(Tileset *primaryTileset, Tileset *secondaryTileset) { + this->primaryTileset = primaryTileset; + this->secondaryTileset = secondaryTileset; + this->draw(); +} + +QList* MetatileSelector::getSelectedMetatiles() { + if (this->externalSelection) { + return this->externalSelectedMetatiles; + } else { + return this->selectedMetatiles; + } +} + +void MetatileSelector::setExternalSelection(int width, int height, QList *metatiles) { + this->externalSelection = true; + this->externalSelectionWidth = width; + this->externalSelectionHeight = height; + this->externalSelectedMetatiles->clear(); + for (int i = 0; i < metatiles->length(); i++) { + this->externalSelectedMetatiles->append(metatiles->at(i)); + } + + this->draw(); + emit selectedMetatilesChanged(); +} + +void MetatileSelector::mousePressEvent(QGraphicsSceneMouseEvent *event) { + SelectablePixmapItem::mousePressEvent(event); + this->updateSelectedMetatiles(); + emit selectedMetatilesChanged(); +} + +void MetatileSelector::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { + SelectablePixmapItem::mouseMoveEvent(event); + this->updateSelectedMetatiles(); + + QPoint pos = this->getCellPos(event->pos()); + uint16_t metatileId = this->getMetatileId(pos.x(), pos.y()); + emit this->hoveredMetatileSelectionChanged(metatileId); + emit selectedMetatilesChanged(); +} + +void MetatileSelector::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { + SelectablePixmapItem::mouseReleaseEvent(event); + this->updateSelectedMetatiles(); + emit selectedMetatilesChanged(); +} + +void MetatileSelector::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { + QPoint pos = this->getCellPos(event->pos()); + uint16_t metatileId = this->getMetatileId(pos.x(), pos.y()); + emit this->hoveredMetatileSelectionChanged(metatileId); +} + +void MetatileSelector::hoverLeaveEvent(QGraphicsSceneHoverEvent*) { + emit this->hoveredMetatileSelectionCleared(); +} + +void MetatileSelector::updateSelectedMetatiles() { + this->externalSelection = false; + this->selectedMetatiles->clear(); + QPoint origin = this->getSelectionStart(); + QPoint dimensions = this->getSelectionDimensions(); + for (int j = 0; j < dimensions.y(); j++) { + for (int i = 0; i < dimensions.x(); i++) { + uint16_t metatileId = this->getMetatileId(origin.x() + i, origin.y() + j); + this->selectedMetatiles->append(metatileId); + } + } +} + +uint16_t MetatileSelector::getMetatileId(int x, int y) { + int index = y * this->numMetatilesWide + x; + if (index < this->primaryTileset->metatiles->length()) { + return static_cast(index); + } else { + return static_cast(Project::getNumMetatilesPrimary() + index - this->primaryTileset->metatiles->length()); + } +} + +QPoint MetatileSelector::getMetatileIdCoords(uint16_t metatileId) { + if (metatileId >= Project::getNumMetatilesTotal() + || (metatileId < Project::getNumMetatilesPrimary() && metatileId >= this->primaryTileset->metatiles->length()) + || (metatileId < Project::getNumMetatilesTotal() && metatileId >= Project::getNumMetatilesPrimary() + this->secondaryTileset->metatiles->length())) + { + // Invalid metatile id. + return QPoint(0, 0); + } + + int index = metatileId < Project::getNumMetatilesPrimary() + ? metatileId + : metatileId - Project::getNumMetatilesPrimary() + this->primaryTileset->metatiles->length(); + return QPoint(index % this->numMetatilesWide, index / this->numMetatilesWide); +} diff --git a/ui/metatileselector.h b/ui/metatileselector.h new file mode 100644 index 00000000..afeed238 --- /dev/null +++ b/ui/metatileselector.h @@ -0,0 +1,51 @@ +#ifndef METATILESELECTOR_H +#define METATILESELECTOR_H + +#include "selectablepixmapitem.h" +#include "core/tileset.h" + +class MetatileSelector: public SelectablePixmapItem { + Q_OBJECT +public: + MetatileSelector(int numMetatilesWide, Tileset *primaryTileset, Tileset *secondaryTileset): SelectablePixmapItem(16, 16) { + this->externalSelection = false; + this->numMetatilesWide = numMetatilesWide; + this->primaryTileset = primaryTileset; + this->secondaryTileset = secondaryTileset; + this->selectedMetatiles = new QList(); + this->externalSelectedMetatiles = new QList(); + setAcceptHoverEvents(true); + } + QPoint getSelectionDimensions(); + void draw(); + void select(uint16_t metatile); + void setTilesets(Tileset*, Tileset*); + QList* getSelectedMetatiles(); + void setExternalSelection(int, int, QList*); +protected: + void mousePressEvent(QGraphicsSceneMouseEvent*); + void mouseMoveEvent(QGraphicsSceneMouseEvent*); + void mouseReleaseEvent(QGraphicsSceneMouseEvent*); + void hoverMoveEvent(QGraphicsSceneHoverEvent*); + void hoverLeaveEvent(QGraphicsSceneHoverEvent*); +private: + bool externalSelection; + int numMetatilesWide; + Tileset *primaryTileset; + Tileset *secondaryTileset; + QList *selectedMetatiles; + int externalSelectionWidth; + int externalSelectionHeight; + QList *externalSelectedMetatiles; + + void updateSelectedMetatiles(); + uint16_t getMetatileId(int x, int y); + QPoint getMetatileIdCoords(uint16_t); + +signals: + void hoveredMetatileSelectionChanged(uint16_t); + void hoveredMetatileSelectionCleared(); + void selectedMetatilesChanged(); +}; + +#endif // METATILESELECTOR_H diff --git a/ui/movementpermissionsselector.cpp b/ui/movementpermissionsselector.cpp index d0df030b..da6d7178 100644 --- a/ui/movementpermissionsselector.cpp +++ b/ui/movementpermissionsselector.cpp @@ -19,34 +19,6 @@ void MovementPermissionsSelector::select(uint16_t collision, uint16_t elevation) SelectablePixmapItem::select(collision, elevation, 0, 0); } -void MovementPermissionsSelector::mousePressEvent(QGraphicsSceneMouseEvent* event) { - SelectablePixmapItem::mousePressEvent(event); - this->setSelectedMovementPermissions(event->pos()); -} - -void MovementPermissionsSelector::mouseMoveEvent(QGraphicsSceneMouseEvent* event) { - SelectablePixmapItem::mouseMoveEvent(event); - this->setSelectedMovementPermissions(event->pos()); -} - -void MovementPermissionsSelector::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) { - SelectablePixmapItem::mouseReleaseEvent(event); - this->setSelectedMovementPermissions(event->pos()); -} - -void MovementPermissionsSelector::setSelectedMovementPermissions(QPointF pos) { - int x = static_cast(pos.x()) / 32; - int y = static_cast(pos.y()) / 32; - int width = this->pixmap().width() / 32; - int height = this->pixmap().height() / 32; - - // Snap to a valid position inside the selection area. - if (x < 0) x = 0; - if (x >= width) x = width - 1; - if (y < 0) y = 0; - if (y >= height) y = height - 1; -} - void MovementPermissionsSelector::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { QPoint pos = this->getCellPos(event->pos()); uint16_t collision = static_cast(pos.x()); diff --git a/ui/movementpermissionsselector.h b/ui/movementpermissionsselector.h index e7f03bf8..a962f01a 100644 --- a/ui/movementpermissionsselector.h +++ b/ui/movementpermissionsselector.h @@ -15,9 +15,6 @@ public: void select(uint16_t collision, uint16_t elevation); protected: - void mousePressEvent(QGraphicsSceneMouseEvent*); - void mouseMoveEvent(QGraphicsSceneMouseEvent*); - void mouseReleaseEvent(QGraphicsSceneMouseEvent*); void hoverMoveEvent(QGraphicsSceneHoverEvent*); void hoverLeaveEvent(QGraphicsSceneHoverEvent*); diff --git a/ui/selectablepixmapitem.cpp b/ui/selectablepixmapitem.cpp index e144f657..5dcd252f 100644 --- a/ui/selectablepixmapitem.cpp +++ b/ui/selectablepixmapitem.cpp @@ -21,6 +21,7 @@ void SelectablePixmapItem::select(int x, int y, int width, int height) this->selectionInitialY = y; this->selectionOffsetX = qMax(0, qMin(width, this->maxSelectionWidth)); this->selectionOffsetY = qMax(0, qMin(height, this->maxSelectionHeight)); + this->draw(); } void SelectablePixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) diff --git a/ui/selectablepixmapitem.h b/ui/selectablepixmapitem.h index 293ac659..cdab4a6a 100644 --- a/ui/selectablepixmapitem.h +++ b/ui/selectablepixmapitem.h @@ -7,14 +7,14 @@ class SelectablePixmapItem : public QObject, public QGraphicsPixmapItem { Q_OBJECT public: + SelectablePixmapItem(int cellWidth, int cellHeight): SelectablePixmapItem(cellWidth, cellHeight, INT_MAX, INT_MAX) {} SelectablePixmapItem(int cellWidth, int cellHeight, int maxSelectionWidth, int maxSelectionHeight) { this->cellWidth = cellWidth; this->cellHeight = cellHeight; this->maxSelectionWidth = maxSelectionWidth; this->maxSelectionHeight = maxSelectionHeight; } - QPoint getSelectionDimensions(); - QPoint getSelectionStart(); + virtual QPoint getSelectionDimensions(); virtual void draw() = 0; protected: @@ -27,6 +27,7 @@ protected: int selectionOffsetX; int selectionOffsetY; + QPoint getSelectionStart(); void select(int, int, int, int); void updateSelection(int, int); QPoint getCellPos(QPointF);