diff --git a/core/block.cpp b/src/core/block.cpp similarity index 100% rename from core/block.cpp rename to src/core/block.cpp diff --git a/core/block.h b/src/core/block.h similarity index 100% rename from core/block.h rename to src/core/block.h diff --git a/core/blockdata.cpp b/src/core/blockdata.cpp similarity index 100% rename from core/blockdata.cpp rename to src/core/blockdata.cpp diff --git a/core/blockdata.h b/src/core/blockdata.h similarity index 100% rename from core/blockdata.h rename to src/core/blockdata.h diff --git a/core/event.cpp b/src/core/event.cpp similarity index 100% rename from core/event.cpp rename to src/core/event.cpp diff --git a/core/event.h b/src/core/event.h similarity index 100% rename from core/event.h rename to src/core/event.h diff --git a/core/heallocation.cpp b/src/core/heallocation.cpp similarity index 100% rename from core/heallocation.cpp rename to src/core/heallocation.cpp diff --git a/core/heallocation.h b/src/core/heallocation.h similarity index 100% rename from core/heallocation.h rename to src/core/heallocation.h diff --git a/core/history.cpp b/src/core/history.cpp similarity index 100% rename from core/history.cpp rename to src/core/history.cpp diff --git a/core/history.h b/src/core/history.h similarity index 100% rename from core/history.h rename to src/core/history.h diff --git a/core/historyitem.cpp b/src/core/historyitem.cpp similarity index 100% rename from core/historyitem.cpp rename to src/core/historyitem.cpp diff --git a/core/historyitem.h b/src/core/historyitem.h similarity index 100% rename from core/historyitem.h rename to src/core/historyitem.h diff --git a/core/map.cpp b/src/core/map.cpp similarity index 100% rename from core/map.cpp rename to src/core/map.cpp diff --git a/core/map.h b/src/core/map.h similarity index 100% rename from core/map.h rename to src/core/map.h diff --git a/core/mapconnection.h b/src/core/mapconnection.h similarity index 100% rename from core/mapconnection.h rename to src/core/mapconnection.h diff --git a/core/maplayout.cpp b/src/core/maplayout.cpp similarity index 100% rename from core/maplayout.cpp rename to src/core/maplayout.cpp diff --git a/core/maplayout.h b/src/core/maplayout.h similarity index 100% rename from core/maplayout.h rename to src/core/maplayout.h diff --git a/core/metatile.cpp b/src/core/metatile.cpp similarity index 100% rename from core/metatile.cpp rename to src/core/metatile.cpp diff --git a/core/metatile.h b/src/core/metatile.h similarity index 100% rename from core/metatile.h rename to src/core/metatile.h diff --git a/core/parseutil.cpp b/src/core/parseutil.cpp similarity index 100% rename from core/parseutil.cpp rename to src/core/parseutil.cpp diff --git a/core/parseutil.h b/src/core/parseutil.h similarity index 100% rename from core/parseutil.h rename to src/core/parseutil.h diff --git a/core/tile.cpp b/src/core/tile.cpp similarity index 100% rename from core/tile.cpp rename to src/core/tile.cpp diff --git a/core/tile.h b/src/core/tile.h similarity index 100% rename from core/tile.h rename to src/core/tile.h diff --git a/core/tileset.cpp b/src/core/tileset.cpp similarity index 100% rename from core/tileset.cpp rename to src/core/tileset.cpp diff --git a/core/tileset.h b/src/core/tileset.h similarity index 100% rename from core/tileset.h rename to src/core/tileset.h diff --git a/editor.cpp b/src/editor.cpp old mode 100755 new mode 100644 similarity index 97% rename from editor.cpp rename to src/editor.cpp index 84f3ee67..c9d5a5ea --- a/editor.cpp +++ b/src/editor.cpp @@ -1,1126 +1,1126 @@ -#include "editor.h" -#include "event.h" -#include "imageproviders.h" -#include "mapconnection.h" -#include "currentselectedmetatilespixmapitem.h" -#include <QCheckBox> -#include <QPainter> -#include <QMouseEvent> -#include <math.h> - -static bool selectingEvent = false; - -Editor::Editor(Ui::MainWindow* ui) -{ - this->ui = ui; - this->selected_events = new QList<DraggablePixmapItem*>; - this->settings = new Settings(); -} - -void Editor::saveProject() { - if (project) { - project->saveAllMaps(); - project->saveAllDataStructures(); - } -} - -void Editor::save() { - if (project && map) { - project->saveMap(map); - project->saveAllDataStructures(); - } -} - -void Editor::undo() { - if (current_view) { - map->undo(); - map_item->draw(); - collision_item->draw(); - } -} - -void Editor::redo() { - if (current_view) { - map->redo(); - map_item->draw(); - collision_item->draw(); - } -} - -void Editor::setEditingMap() { - current_view = map_item; - if (map_item) { - displayMapConnections(); - map_item->draw(); - map_item->setVisible(true); - map_item->setEnabled(true); - setConnectionsVisibility(ui->checkBox_ToggleBorder->isChecked()); - } - if (collision_item) { - collision_item->setVisible(false); - } - if (events_group) { - events_group->setVisible(false); - } - setBorderItemsVisible(ui->checkBox_ToggleBorder->isChecked()); - setConnectionItemsVisible(false); -} - -void Editor::setEditingCollision() { - current_view = collision_item; - if (collision_item) { - displayMapConnections(); - collision_item->draw(); - collision_item->setVisible(true); - setConnectionsVisibility(ui->checkBox_ToggleBorder->isChecked()); - } - if (map_item) { - map_item->setVisible(false); - } - if (events_group) { - events_group->setVisible(false); - } - setBorderItemsVisible(ui->checkBox_ToggleBorder->isChecked()); - setConnectionItemsVisible(false); -} - -void Editor::setEditingObjects() { - current_view = map_item; - if (events_group) { - events_group->setVisible(true); - } - if (map_item) { - map_item->setVisible(true); - map_item->setEnabled(false); - setConnectionsVisibility(ui->checkBox_ToggleBorder->isChecked()); - } - if (collision_item) { - collision_item->setVisible(false); - } - setBorderItemsVisible(ui->checkBox_ToggleBorder->isChecked()); - setConnectionItemsVisible(false); -} - -void Editor::setEditingConnections() { - current_view = map_item; - if (map_item) { - map_item->draw(); - map_item->setVisible(true); - map_item->setEnabled(false); - populateConnectionMapPickers(); - ui->label_NumConnections->setText(QString::number(map->connections.length())); - setConnectionsVisibility(false); - setDiveEmergeControls(); - bool controlsEnabled = selected_connection_item != nullptr; - setConnectionEditControlsEnabled(controlsEnabled); - if (selected_connection_item) { - onConnectionOffsetChanged(selected_connection_item->connection->offset.toInt()); - setConnectionMap(selected_connection_item->connection->map_name); - setCurrentConnectionDirection(selected_connection_item->connection->direction); - } - } - if (collision_item) { - collision_item->setVisible(false); - } - if (events_group) { - events_group->setVisible(false); - } - setBorderItemsVisible(true, 0.4); - setConnectionItemsVisible(true); -} - -void Editor::setDiveEmergeControls() { - ui->comboBox_DiveMap->blockSignals(true); - ui->comboBox_EmergeMap->blockSignals(true); - ui->comboBox_DiveMap->setCurrentText(""); - ui->comboBox_EmergeMap->setCurrentText(""); - for (MapConnection* connection : map->connections) { - if (connection->direction == "dive") { - ui->comboBox_DiveMap->setCurrentText(connection->map_name); - } else if (connection->direction == "emerge") { - ui->comboBox_EmergeMap->setCurrentText(connection->map_name); - } - } - ui->comboBox_DiveMap->blockSignals(false); - ui->comboBox_EmergeMap->blockSignals(false); -} - -void Editor::populateConnectionMapPickers() { - ui->comboBox_ConnectedMap->blockSignals(true); - ui->comboBox_DiveMap->blockSignals(true); - ui->comboBox_EmergeMap->blockSignals(true); - - ui->comboBox_ConnectedMap->clear(); - ui->comboBox_ConnectedMap->addItems(*project->mapNames); - ui->comboBox_DiveMap->clear(); - ui->comboBox_DiveMap->addItems(*project->mapNames); - ui->comboBox_EmergeMap->clear(); - ui->comboBox_EmergeMap->addItems(*project->mapNames); - - ui->comboBox_ConnectedMap->blockSignals(false); - ui->comboBox_DiveMap->blockSignals(true); - ui->comboBox_EmergeMap->blockSignals(true); -} - -void Editor::setConnectionItemsVisible(bool visible) { - for (ConnectionPixmapItem* item : connection_edit_items) { - item->setVisible(visible); - item->setEnabled(visible); - } -} - -void Editor::setBorderItemsVisible(bool visible, qreal opacity) { - for (QGraphicsPixmapItem* item : borderItems) { - item->setVisible(visible); - item->setOpacity(opacity); - } -} - -void Editor::setCurrentConnectionDirection(QString curDirection) { - if (!selected_connection_item) - return; - - selected_connection_item->connection->direction = curDirection; - - Map *connected_map = project->getMap(selected_connection_item->connection->map_name); - QPixmap pixmap = connected_map->renderConnection(*selected_connection_item->connection); - int offset = selected_connection_item->connection->offset.toInt(nullptr, 0); - selected_connection_item->initialOffset = offset; - int x = 0, y = 0; - if (selected_connection_item->connection->direction == "up") { - x = offset * 16; - y = -pixmap.height(); - } else if (selected_connection_item->connection->direction == "down") { - x = offset * 16; - y = map->getHeight() * 16; - } else if (selected_connection_item->connection->direction == "left") { - x = -pixmap.width(); - y = offset * 16; - } else if (selected_connection_item->connection->direction == "right") { - x = map->getWidth() * 16; - y = offset * 16; - } - - selected_connection_item->basePixmap = pixmap; - QPainter painter(&pixmap); - painter.setPen(QColor(255, 0, 255)); - painter.drawRect(0, 0, pixmap.width() - 1, pixmap.height() - 1); - painter.end(); - selected_connection_item->setPixmap(pixmap); - selected_connection_item->initialX = x; - selected_connection_item->initialY = y; - selected_connection_item->blockSignals(true); - selected_connection_item->setX(x); - selected_connection_item->setY(y); - selected_connection_item->setZValue(-1); - selected_connection_item->blockSignals(false); - - setConnectionEditControlValues(selected_connection_item->connection); -} - -void Editor::updateCurrentConnectionDirection(QString curDirection) { - if (!selected_connection_item) - return; - - QString originalDirection = selected_connection_item->connection->direction; - setCurrentConnectionDirection(curDirection); - updateMirroredConnectionDirection(selected_connection_item->connection, originalDirection); -} - -void Editor::onConnectionMoved(MapConnection* connection) { - updateMirroredConnectionOffset(connection); - onConnectionOffsetChanged(connection->offset.toInt()); -} - -void Editor::onConnectionOffsetChanged(int newOffset) { - ui->spinBox_ConnectionOffset->blockSignals(true); - ui->spinBox_ConnectionOffset->setValue(newOffset); - ui->spinBox_ConnectionOffset->blockSignals(false); - -} - -void Editor::setConnectionEditControlValues(MapConnection* connection) { - QString mapName = connection ? connection->map_name : ""; - QString direction = connection ? connection->direction : ""; - int offset = connection ? connection->offset.toInt() : 0; - - ui->comboBox_ConnectedMap->blockSignals(true); - ui->comboBox_ConnectionDirection->blockSignals(true); - ui->spinBox_ConnectionOffset->blockSignals(true); - - ui->comboBox_ConnectedMap->setCurrentText(mapName); - ui->comboBox_ConnectionDirection->setCurrentText(direction); - ui->spinBox_ConnectionOffset->setValue(offset); - - ui->comboBox_ConnectedMap->blockSignals(false); - ui->comboBox_ConnectionDirection->blockSignals(false); - ui->spinBox_ConnectionOffset->blockSignals(false); -} - -void Editor::setConnectionEditControlsEnabled(bool enabled) { - ui->comboBox_ConnectionDirection->setEnabled(enabled); - ui->comboBox_ConnectedMap->setEnabled(enabled); - ui->spinBox_ConnectionOffset->setEnabled(enabled); - - if (!enabled) { - setConnectionEditControlValues(nullptr); - } -} - -void Editor::onConnectionItemSelected(ConnectionPixmapItem* connectionItem) { - if (!connectionItem) - return; - - for (ConnectionPixmapItem* item : connection_edit_items) { - bool isSelectedItem = item == connectionItem; - int zValue = isSelectedItem ? 0 : -1; - qreal opacity = isSelectedItem ? 1 : 0.75; - item->setZValue(zValue); - item->render(opacity); - if (isSelectedItem) { - QPixmap pixmap = item->pixmap(); - QPainter painter(&pixmap); - painter.setPen(QColor(255, 0, 255)); - painter.drawRect(0, 0, pixmap.width() - 1, pixmap.height() - 1); - painter.end(); - item->setPixmap(pixmap); - } - } - selected_connection_item = connectionItem; - setConnectionEditControlsEnabled(true); - setConnectionEditControlValues(selected_connection_item->connection); - ui->spinBox_ConnectionOffset->setMaximum(selected_connection_item->getMaxOffset()); - ui->spinBox_ConnectionOffset->setMinimum(selected_connection_item->getMinOffset()); - onConnectionOffsetChanged(selected_connection_item->connection->offset.toInt()); -} - -void Editor::setSelectedConnectionFromMap(QString mapName) { - // Search for the first connection that connects to the given map map. - for (ConnectionPixmapItem* item : connection_edit_items) { - if (item->connection->map_name == mapName) { - onConnectionItemSelected(item); - break; - } - } -} - -void Editor::onConnectionItemDoubleClicked(ConnectionPixmapItem* connectionItem) { - emit loadMapRequested(connectionItem->connection->map_name, map->name); -} - -void Editor::onConnectionDirectionChanged(QString newDirection) { - ui->comboBox_ConnectionDirection->blockSignals(true); - ui->comboBox_ConnectionDirection->setCurrentText(newDirection); - ui->comboBox_ConnectionDirection->blockSignals(false); -} - -void Editor::onBorderMetatilesChanged() { - displayMapBorder(); -} - -void Editor::onHoveredMovementPermissionChanged(uint16_t collision, uint16_t elevation) { - this->ui->statusBar->showMessage(this->getMovementPermissionText(collision, elevation)); -} - -void Editor::onHoveredMovementPermissionCleared() { - this->ui->statusBar->clearMessage(); -} - -void Editor::onHoveredMetatileSelectionChanged(uint16_t metatileId) { - QString message = QString("Metatile: 0x%1") - .arg(QString("%1").arg(metatileId, 3, 16, QChar('0')).toUpper()); - this->ui->statusBar->showMessage(message); -} - -void Editor::onHoveredMetatileSelectionCleared() { - this->ui->statusBar->clearMessage(); -} - -void Editor::onSelectedMetatilesChanged() { - this->redrawCurrentMetatilesSelection(); -} - -void Editor::onHoveredMapMetatileChanged(int x, int y) { - if (x >= 0 && x < map->getWidth() && y >= 0 && y < map->getHeight()) { - int blockIndex = y * map->getWidth() + x; - int tile = map->layout->blockdata->blocks->at(blockIndex).tile; - this->ui->statusBar->showMessage(QString("X: %1, Y: %2, Metatile: 0x%3, Scale = %4x") - .arg(x) - .arg(y) - .arg(QString("%1").arg(tile, 3, 16, QChar('0')).toUpper()) - .arg(QString::number(pow(map->scale_base, map->scale_exp)))); - } -} - -void Editor::onHoveredMapMetatileCleared() { - this->ui->statusBar->clearMessage(); -} - -void Editor::onHoveredMapMovementPermissionChanged(int x, int y) { - if (x >= 0 && x < map->getWidth() && y >= 0 && y < map->getHeight()) { - int blockIndex = y * map->getWidth() + x; - uint16_t collision = map->layout->blockdata->blocks->at(blockIndex).collision; - uint16_t elevation = map->layout->blockdata->blocks->at(blockIndex).elevation; - QString message = QString("X: %1, Y: %2, %3") - .arg(x) - .arg(y) - .arg(this->getMovementPermissionText(collision, elevation)); - this->ui->statusBar->showMessage(message); - } -} - -void Editor::onHoveredMapMovementPermissionCleared() { - this->ui->statusBar->clearMessage(); -} - -QString Editor::getMovementPermissionText(uint16_t collision, uint16_t elevation){ - QString message; - if (collision == 0 && elevation == 0) { - message = "Collision: Transition between elevations"; - } else if (collision == 0 && elevation == 15) { - message = "Collision: Multi-Level (Bridge)"; - } else if (collision == 0 && elevation == 1) { - message = "Collision: Surf"; - } else if (collision == 0) { - message = QString("Collision: Passable, Elevation: %1").arg(elevation); - } else { - message = QString("Collision: Impassable, Elevation: %1").arg(elevation); - } - return message; -} - -void Editor::setConnectionsVisibility(bool visible) { - for (QGraphicsPixmapItem* item : connection_items) { - item->setVisible(visible); - item->setActive(visible); - } -} - -void Editor::setMap(QString map_name) { - if (map_name.isNull()) { - return; - } - if (project) { - map = project->loadMap(map_name); - selected_events->clear(); - displayMap(); - updateSelectedEvents(); - } -} - -void Editor::mouseEvent_map(QGraphicsSceneMouseEvent *event, MapPixmapItem *item) { - if (map_edit_mode == "paint") { - if (event->buttons() & Qt::RightButton) { - item->updateMetatileSelection(event); - } else if (event->buttons() & Qt::MiddleButton) { - item->floodFill(event); - } else { - item->paint(event); - } - } else if (map_edit_mode == "select") { - item->select(event); - } else if (map_edit_mode == "fill") { - if (event->buttons() & Qt::RightButton) { - item->updateMetatileSelection(event); - } else { - item->floodFill(event); - } - } else if (map_edit_mode == "pick") { - - if (event->buttons() & Qt::RightButton) { - item->updateMetatileSelection(event); - } else { - item->pick(event); - } - } else if (map_edit_mode == "shift") { - item->shift(event); - } -} -void Editor::mouseEvent_collision(QGraphicsSceneMouseEvent *event, CollisionPixmapItem *item) { - if (map_edit_mode == "paint") { - if (event->buttons() & Qt::RightButton) { - item->updateMovementPermissionSelection(event); - } else if (event->buttons() & Qt::MiddleButton) { - item->floodFill(event); - } else { - item->paint(event); - } - } else if (map_edit_mode == "select") { - item->select(event); - } else if (map_edit_mode == "fill") { - if (event->buttons() & Qt::RightButton) { - item->pick(event); - } else { - item->floodFill(event); - } - } else if (map_edit_mode == "pick") { - item->pick(event); - } else if (map_edit_mode == "shift") { - item->shift(event); - } -} - -void Editor::displayMap() { - if (!scene) - scene = new QGraphicsScene; - - if (map_item && scene) { - scene->removeItem(map_item); - delete map_item; - } - - displayMetatileSelector(); - displayMovementPermissionSelector(); - displayMapMetatiles(); - displayMapMovementPermissions(); - displayBorderMetatiles(); - displayCurrentMetatilesSelection(); - displayMapEvents(); - displayMapConnections(); - displayMapBorder(); - displayMapGrid(); - - if (map_item) { - map_item->setVisible(false); - } - if (collision_item) { - collision_item->setVisible(false); - } - if (events_group) { - events_group->setVisible(false); - } -} - -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; - 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::displayMapMetatiles() { - map_item = new MapPixmapItem(map, this->metatile_selector_item, this->settings); - connect(map_item, SIGNAL(mouseEvent(QGraphicsSceneMouseEvent*,MapPixmapItem*)), - this, SLOT(mouseEvent_map(QGraphicsSceneMouseEvent*,MapPixmapItem*))); - connect(map_item, SIGNAL(hoveredMapMetatileChanged(int, int)), - this, SLOT(onHoveredMapMetatileChanged(int, int))); - connect(map_item, SIGNAL(hoveredMapMetatileCleared()), - this, SLOT(onHoveredMapMetatileCleared())); - - map_item->draw(true); - scene->addItem(map_item); - - int tw = 16; - int th = 16; - scene->setSceneRect( - -6 * tw, - -6 * th, - map_item->pixmap().width() + 12 * tw, - map_item->pixmap().height() + 12 * th - ); -} - -void Editor::displayMapMovementPermissions() { - if (collision_item && scene) { - scene->removeItem(collision_item); - delete collision_item; - } - collision_item = new CollisionPixmapItem(map, this->movement_permissions_selector_item, this->metatile_selector_item, this->settings); - connect(collision_item, SIGNAL(mouseEvent(QGraphicsSceneMouseEvent*,CollisionPixmapItem*)), - this, SLOT(mouseEvent_collision(QGraphicsSceneMouseEvent*,CollisionPixmapItem*))); - connect(collision_item, SIGNAL(hoveredMapMovementPermissionChanged(int, int)), - this, SLOT(onHoveredMapMovementPermissionChanged(int, int))); - connect(collision_item, SIGNAL(hoveredMapMovementPermissionCleared()), - this, SLOT(onHoveredMapMovementPermissionCleared())); - - collision_item->draw(true); - scene->addItem(collision_item); -} - -void Editor::displayBorderMetatiles() { - if (selected_border_metatiles_item && selected_border_metatiles_item->scene()) { - selected_border_metatiles_item->scene()->removeItem(selected_border_metatiles_item); - delete selected_border_metatiles_item; - } - - scene_selected_border_metatiles = new QGraphicsScene; - selected_border_metatiles_item = new BorderMetatilesPixmapItem(map, this->metatile_selector_item); - selected_border_metatiles_item->draw(); - scene_selected_border_metatiles->addItem(selected_border_metatiles_item); - - connect(selected_border_metatiles_item, SIGNAL(borderMetatilesChanged()), this, SLOT(onBorderMetatilesChanged())); -} - -void Editor::displayCurrentMetatilesSelection() { - if (scene_current_metatile_selection_item && scene_current_metatile_selection_item->scene()) { - scene_current_metatile_selection_item->scene()->removeItem(scene_current_metatile_selection_item); - delete scene_current_metatile_selection_item; - } - - scene_current_metatile_selection = new QGraphicsScene; - scene_current_metatile_selection_item = new CurrentSelectedMetatilesPixmapItem(map, this->metatile_selector_item); - scene_current_metatile_selection_item->draw(); - scene_current_metatile_selection->addItem(scene_current_metatile_selection_item); -} - -void Editor::redrawCurrentMetatilesSelection() { - if (scene_current_metatile_selection_item) { - scene_current_metatile_selection_item->draw(); - emit currentMetatilesSelectionChanged(); - } -} - -void Editor::displayMovementPermissionSelector() { - if (movement_permissions_selector_item && movement_permissions_selector_item->scene()) { - movement_permissions_selector_item->scene()->removeItem(movement_permissions_selector_item); - delete scene_collision_metatiles; - } - - scene_collision_metatiles = new QGraphicsScene; - 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); -} - -void Editor::displayMapEvents() { - if (events_group) { - for (QGraphicsItem *child : events_group->childItems()) { - events_group->removeFromGroup(child); - delete child; - } - - if (events_group->scene()) { - events_group->scene()->removeItem(events_group); - } - - delete events_group; - } - - selected_events->clear(); - - events_group = new QGraphicsItemGroup; - scene->addItem(events_group); - - QList<Event *> events = map->getAllEvents(); - project->loadEventPixmaps(events); - for (Event *event : events) { - addMapEvent(event); - } - //objects_group->setFiltersChildEvents(false); - events_group->setHandlesChildEvents(false); - - emit objectsChanged(); -} - -DraggablePixmapItem *Editor::addMapEvent(Event *event) { - DraggablePixmapItem *object = new DraggablePixmapItem(event, this); - events_group->addToGroup(object); - return object; -} - -void Editor::displayMapConnections() { - for (QGraphicsPixmapItem* item : connection_items) { - if (item->scene()) { - item->scene()->removeItem(item); - } - delete item; - } - connection_items.clear(); - - for (ConnectionPixmapItem* item : connection_edit_items) { - if (item->scene()) { - item->scene()->removeItem(item); - } - delete item; - } - selected_connection_item = nullptr; - connection_edit_items.clear(); - - for (MapConnection *connection : map->connections) { - if (connection->direction == "dive" || connection->direction == "emerge") { - continue; - } - createConnectionItem(connection, false); - } - - if (!connection_edit_items.empty()) { - onConnectionItemSelected(connection_edit_items.first()); - } -} - -void Editor::createConnectionItem(MapConnection* connection, bool hide) { - Map *connected_map = project->getMap(connection->map_name); - QPixmap pixmap = connected_map->renderConnection(*connection); - int offset = connection->offset.toInt(nullptr, 0); - int x = 0, y = 0; - if (connection->direction == "up") { - x = offset * 16; - y = -pixmap.height(); - } else if (connection->direction == "down") { - x = offset * 16; - y = map->getHeight() * 16; - } else if (connection->direction == "left") { - x = -pixmap.width(); - y = offset * 16; - } else if (connection->direction == "right") { - x = map->getWidth() * 16; - y = offset * 16; - } - - QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap); - item->setZValue(-1); - item->setX(x); - item->setY(y); - scene->addItem(item); - connection_items.append(item); - item->setVisible(!hide); - - ConnectionPixmapItem *connection_edit_item = new ConnectionPixmapItem(pixmap, connection, x, y, map->getWidth(), map->getHeight()); - connection_edit_item->setX(x); - connection_edit_item->setY(y); - connection_edit_item->setZValue(-1); - scene->addItem(connection_edit_item); - connect(connection_edit_item, SIGNAL(connectionMoved(MapConnection*)), this, SLOT(onConnectionMoved(MapConnection*))); - connect(connection_edit_item, SIGNAL(connectionItemSelected(ConnectionPixmapItem*)), this, SLOT(onConnectionItemSelected(ConnectionPixmapItem*))); - connect(connection_edit_item, SIGNAL(connectionItemDoubleClicked(ConnectionPixmapItem*)), this, SLOT(onConnectionItemDoubleClicked(ConnectionPixmapItem*))); - connection_edit_items.append(connection_edit_item); -} - -void Editor::displayMapBorder() { - for (QGraphicsPixmapItem* item : borderItems) { - if (item->scene()) { - item->scene()->removeItem(item); - } - delete item; - } - borderItems.clear(); - - QPixmap pixmap = map->renderBorder(); - for (int y = -6; y < map->getHeight() + 6; y += 2) - for (int x = -6; x < map->getWidth() + 6; x += 2) { - QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap); - item->setX(x * 16); - item->setY(y * 16); - item->setZValue(-2); - scene->addItem(item); - borderItems.append(item); - } -} - -void Editor::displayMapGrid() { - for (QGraphicsLineItem* item : gridLines) { - if (item && item->scene()) { - item->scene()->removeItem(item); - } - delete item; - } - gridLines.clear(); - ui->checkBox_ToggleGrid->disconnect(); - - int pixelWidth = map->getWidth() * 16; - int pixelHeight = map->getHeight() * 16; - for (int i = 0; i <= map->getWidth(); i++) { - int x = i * 16; - QGraphicsLineItem *line = scene->addLine(x, 0, x, pixelHeight); - line->setVisible(ui->checkBox_ToggleGrid->isChecked()); - gridLines.append(line); - connect(ui->checkBox_ToggleGrid, &QCheckBox::toggled, [=](bool checked){line->setVisible(checked);}); - } - for (int j = 0; j <= map->getHeight(); j++) { - int y = j * 16; - QGraphicsLineItem *line = scene->addLine(0, y, pixelWidth, y); - line->setVisible(ui->checkBox_ToggleGrid->isChecked()); - gridLines.append(line); - connect(ui->checkBox_ToggleGrid, &QCheckBox::toggled, [=](bool checked){line->setVisible(checked);}); - } -} - -void Editor::updateConnectionOffset(int offset) { - if (!selected_connection_item) - return; - - selected_connection_item->blockSignals(true); - offset = qMin(offset, selected_connection_item->getMaxOffset()); - offset = qMax(offset, selected_connection_item->getMinOffset()); - selected_connection_item->connection->offset = QString::number(offset); - if (selected_connection_item->connection->direction == "up" || selected_connection_item->connection->direction == "down") { - selected_connection_item->setX(selected_connection_item->initialX + (offset - selected_connection_item->initialOffset) * 16); - } else if (selected_connection_item->connection->direction == "left" || selected_connection_item->connection->direction == "right") { - selected_connection_item->setY(selected_connection_item->initialY + (offset - selected_connection_item->initialOffset) * 16); - } - selected_connection_item->blockSignals(false); - updateMirroredConnectionOffset(selected_connection_item->connection); -} - -void Editor::setConnectionMap(QString mapName) { - if (!mapName.isEmpty() && !project->mapNames->contains(mapName)) { - qDebug() << "Invalid map name " << mapName << " specified for connection."; - return; - } - if (!selected_connection_item) - return; - - if (mapName.isEmpty()) { - removeCurrentConnection(); - return; - } - - QString originalMapName = selected_connection_item->connection->map_name; - setConnectionEditControlsEnabled(true); - selected_connection_item->connection->map_name = mapName; - setCurrentConnectionDirection(selected_connection_item->connection->direction); - updateMirroredConnectionMap(selected_connection_item->connection, originalMapName); -} - -void Editor::addNewConnection() { - // Find direction with least number of connections. - QMap<QString, int> directionCounts = QMap<QString, int>({{"up", 0}, {"right", 0}, {"down", 0}, {"left", 0}}); - for (MapConnection* connection : map->connections) { - directionCounts[connection->direction]++; - } - QString minDirection = "up"; - int minCount = INT_MAX; - for (QString direction : directionCounts.keys()) { - if (directionCounts[direction] < minCount) { - minDirection = direction; - minCount = directionCounts[direction]; - } - } - - // Don't connect the map to itself. - QString defaultMapName = project->mapNames->first(); - if (defaultMapName == map->name) { - defaultMapName = project->mapNames->value(1); - } - - MapConnection* newConnection = new MapConnection; - newConnection->direction = minDirection; - newConnection->offset = "0"; - newConnection->map_name = defaultMapName; - map->connections.append(newConnection); - createConnectionItem(newConnection, true); - onConnectionItemSelected(connection_edit_items.last()); - ui->label_NumConnections->setText(QString::number(map->connections.length())); - - updateMirroredConnection(newConnection, newConnection->direction, newConnection->map_name); -} - -void Editor::updateMirroredConnectionOffset(MapConnection* connection) { - updateMirroredConnection(connection, connection->direction, connection->map_name); -} -void Editor::updateMirroredConnectionDirection(MapConnection* connection, QString originalDirection) { - updateMirroredConnection(connection, originalDirection, connection->map_name); -} -void Editor::updateMirroredConnectionMap(MapConnection* connection, QString originalMapName) { - updateMirroredConnection(connection, connection->direction, originalMapName); -} -void Editor::removeMirroredConnection(MapConnection* connection) { - updateMirroredConnection(connection, connection->direction, connection->map_name, true); -} -void Editor::updateMirroredConnection(MapConnection* connection, QString originalDirection, QString originalMapName, bool isDelete) { - if (!ui->checkBox_MirrorConnections->isChecked()) - return; - - static QMap<QString, QString> oppositeDirections = QMap<QString, QString>({ - {"up", "down"}, {"right", "left"}, - {"down", "up"}, {"left", "right"}, - {"dive", "emerge"},{"emerge", "dive"}}); - QString oppositeDirection = oppositeDirections.value(originalDirection); - - // Find the matching connection in the connected map. - MapConnection* mirrorConnection = nullptr; - Map* otherMap = project->getMap(originalMapName); - for (MapConnection* conn : otherMap->connections) { - if (conn->direction == oppositeDirection && conn->map_name == map->name) { - mirrorConnection = conn; - } - } - - if (isDelete) { - if (mirrorConnection) { - otherMap->connections.removeOne(mirrorConnection); - delete mirrorConnection; - } - return; - } - - if (connection->direction != originalDirection || connection->map_name != originalMapName) { - if (mirrorConnection) { - otherMap->connections.removeOne(mirrorConnection); - delete mirrorConnection; - mirrorConnection = nullptr; - otherMap = project->getMap(connection->map_name); - } - } - - // Create a new mirrored connection, if a matching one doesn't already exist. - if (!mirrorConnection) { - mirrorConnection = new MapConnection; - mirrorConnection->direction = oppositeDirections.value(connection->direction); - mirrorConnection->map_name = map->name; - otherMap->connections.append(mirrorConnection); - } - - mirrorConnection->offset = QString::number(-connection->offset.toInt()); -} - -void Editor::removeCurrentConnection() { - if (!selected_connection_item) - return; - - map->connections.removeOne(selected_connection_item->connection); - connection_edit_items.removeOne(selected_connection_item); - removeMirroredConnection(selected_connection_item->connection); - - if (selected_connection_item && selected_connection_item->scene()) { - selected_connection_item->scene()->removeItem(selected_connection_item); - delete selected_connection_item; - } - - selected_connection_item = nullptr; - setConnectionEditControlsEnabled(false); - ui->spinBox_ConnectionOffset->setValue(0); - ui->label_NumConnections->setText(QString::number(map->connections.length())); - - if (connection_edit_items.length() > 0) { - onConnectionItemSelected(connection_edit_items.last()); - } -} - -void Editor::updateDiveMap(QString mapName) { - updateDiveEmergeMap(mapName, "dive"); -} - -void Editor::updateEmergeMap(QString mapName) { - updateDiveEmergeMap(mapName, "emerge"); -} - -void Editor::updateDiveEmergeMap(QString mapName, QString direction) { - if (!mapName.isEmpty() && !project->mapNamesToMapConstants->contains(mapName)) { - qDebug() << "Invalid " << direction << " map connection: " << mapName; - return; - } - - MapConnection* connection = nullptr; - for (MapConnection* conn : map->connections) { - if (conn->direction == direction) { - connection = conn; - break; - } - } - - if (mapName.isEmpty()) { - // Remove dive/emerge connection - if (connection) { - map->connections.removeOne(connection); - removeMirroredConnection(connection); - } - } else { - if (!connection) { - connection = new MapConnection; - connection->direction = direction; - connection->offset = "0"; - connection->map_name = mapName; - map->connections.append(connection); - updateMirroredConnection(connection, connection->direction, connection->map_name); - } else { - QString originalMapName = connection->map_name; - connection->map_name = mapName; - updateMirroredConnectionMap(connection, originalMapName); - } - } - - ui->label_NumConnections->setText(QString::number(map->connections.length())); -} - -void Editor::updatePrimaryTileset(QString tilesetLabel) -{ - if (map->layout->tileset_primary_label != tilesetLabel) - { - map->layout->tileset_primary_label = tilesetLabel; - map->layout->tileset_primary = project->getTileset(tilesetLabel); - emit tilesetChanged(map->name); - } -} - -void Editor::updateSecondaryTileset(QString tilesetLabel) -{ - if (map->layout->tileset_secondary_label != tilesetLabel) - { - map->layout->tileset_secondary_label = tilesetLabel; - map->layout->tileset_secondary = project->getTileset(tilesetLabel); - emit tilesetChanged(map->name); - } -} - -void Editor::toggleBorderVisibility(bool visible) -{ - this->setBorderItemsVisible(visible); - this->setConnectionsVisibility(visible); -} - -void DraggablePixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *mouse) { - active = true; - last_x = static_cast<int>(mouse->pos().x() + this->pos().x()) / 16; - last_y = static_cast<int>(mouse->pos().y() + this->pos().y()) / 16; - this->editor->selectMapEvent(this, mouse->modifiers() & Qt::ControlModifier); - this->editor->updateSelectedEvents(); - selectingEvent = true; - //qDebug() << QString("(%1, %2)").arg(event->get("x")).arg(event->get("y")); -} - -void DraggablePixmapItem::move(int x, int y) { - event->setX(event->x() + x); - event->setY(event->y() + y); - updatePosition(); - emitPositionChanged(); -} - -void DraggablePixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *mouse) { - if (active) { - int x = static_cast<int>(mouse->pos().x() + this->pos().x()) / 16; - int y = static_cast<int>(mouse->pos().y() + this->pos().y()) / 16; - if (x != last_x || y != last_y) { - if (editor->selected_events->contains(this)) { - for (DraggablePixmapItem *item : *editor->selected_events) { - item->move(x - last_x, y - last_y); - } - } else { - move(x - last_x, y - last_y); - } - last_x = x; - last_y = y; - //qDebug() << QString("(%1, %2)").arg(event->get("x")).arg(event->get("x")); - } - } -} - -void DraggablePixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *) { - active = false; -} - -void DraggablePixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) { - if (this->event->get("event_type") == EventType::Warp) { - QString destMap = this->event->get("destination_map_name"); - if (destMap != NONE_MAP_NAME) { - emit editor->warpEventDoubleClicked(this->event->get("destination_map_name"), this->event->get("destination_warp")); - } - } -} - -QList<DraggablePixmapItem *> *Editor::getObjects() { - QList<DraggablePixmapItem *> *list = new QList<DraggablePixmapItem *>; - for (Event *event : map->getAllEvents()) { - for (QGraphicsItem *child : events_group->childItems()) { - DraggablePixmapItem *item = static_cast<DraggablePixmapItem *>(child); - if (item->event == event) { - list->append(item); - break; - } - } - } - return list; -} - -void Editor::redrawObject(DraggablePixmapItem *item) { - if (item) { - item->setPixmap(item->event->pixmap); - item->setShapeMode(QGraphicsPixmapItem::BoundingRectShape); - if (selected_events && selected_events->contains(item)) { - QImage image = item->pixmap().toImage(); - QPainter painter(&image); - painter.setPen(QColor(250, 0, 255)); - painter.drawRect(0, 0, image.width() - 1, image.height() - 1); - painter.end(); - item->setPixmap(QPixmap::fromImage(image)); - } - } -} - -void Editor::updateSelectedEvents() { - for (DraggablePixmapItem *item : *(getObjects())) { - redrawObject(item); - } - emit selectedObjectsChanged(); -} - -void Editor::selectMapEvent(DraggablePixmapItem *object) { - selectMapEvent(object, false); -} - -void Editor::selectMapEvent(DraggablePixmapItem *object, bool toggle) { - if (selected_events && object) { - if (selected_events->contains(object)) { - if (toggle) { - selected_events->removeOne(object); - } - } else { - if (!toggle) { - selected_events->clear(); - } - selected_events->append(object); - } - updateSelectedEvents(); - } -} - -DraggablePixmapItem* Editor::addNewEvent(QString event_type) { - if (project && map) { - Event *event = Event::createNewEvent(event_type, map->name); - event->put("map_name", map->name); - map->addEvent(event); - project->loadEventPixmaps(map->getAllEvents()); - DraggablePixmapItem *object = addMapEvent(event); - return object; - } - return nullptr; -} - -void Editor::deleteEvent(Event *event) { - Map *map = project->getMap(event->get("map_name")); - if (map) { - map->removeEvent(event); - } - //selected_events->removeAll(event); - //updateSelectedObjects(); -} - -// It doesn't seem to be possible to prevent the mousePress event -// from triggering both event's DraggablePixmapItem and the background mousePress. -// Since the DraggablePixmapItem's event fires first, we can set a temp -// variable "selectingEvent" so that we can detect whether or not the user -// is clicking on the background instead of an event. -void Editor::objectsView_onMousePress(QMouseEvent *event) { - bool multiSelect = event->modifiers() & Qt::ControlModifier; - if (!selectingEvent && !multiSelect && selected_events->length() > 1) { - DraggablePixmapItem *first = selected_events->first(); - selected_events->clear(); - selected_events->append(first); - updateSelectedEvents(); - } - - selectingEvent = false; -} +#include "editor.h" +#include "event.h" +#include "imageproviders.h" +#include "mapconnection.h" +#include "currentselectedmetatilespixmapitem.h" +#include <QCheckBox> +#include <QPainter> +#include <QMouseEvent> +#include <math.h> + +static bool selectingEvent = false; + +Editor::Editor(Ui::MainWindow* ui) +{ + this->ui = ui; + this->selected_events = new QList<DraggablePixmapItem*>; + this->settings = new Settings(); +} + +void Editor::saveProject() { + if (project) { + project->saveAllMaps(); + project->saveAllDataStructures(); + } +} + +void Editor::save() { + if (project && map) { + project->saveMap(map); + project->saveAllDataStructures(); + } +} + +void Editor::undo() { + if (current_view) { + map->undo(); + map_item->draw(); + collision_item->draw(); + } +} + +void Editor::redo() { + if (current_view) { + map->redo(); + map_item->draw(); + collision_item->draw(); + } +} + +void Editor::setEditingMap() { + current_view = map_item; + if (map_item) { + displayMapConnections(); + map_item->draw(); + map_item->setVisible(true); + map_item->setEnabled(true); + setConnectionsVisibility(ui->checkBox_ToggleBorder->isChecked()); + } + if (collision_item) { + collision_item->setVisible(false); + } + if (events_group) { + events_group->setVisible(false); + } + setBorderItemsVisible(ui->checkBox_ToggleBorder->isChecked()); + setConnectionItemsVisible(false); +} + +void Editor::setEditingCollision() { + current_view = collision_item; + if (collision_item) { + displayMapConnections(); + collision_item->draw(); + collision_item->setVisible(true); + setConnectionsVisibility(ui->checkBox_ToggleBorder->isChecked()); + } + if (map_item) { + map_item->setVisible(false); + } + if (events_group) { + events_group->setVisible(false); + } + setBorderItemsVisible(ui->checkBox_ToggleBorder->isChecked()); + setConnectionItemsVisible(false); +} + +void Editor::setEditingObjects() { + current_view = map_item; + if (events_group) { + events_group->setVisible(true); + } + if (map_item) { + map_item->setVisible(true); + map_item->setEnabled(false); + setConnectionsVisibility(ui->checkBox_ToggleBorder->isChecked()); + } + if (collision_item) { + collision_item->setVisible(false); + } + setBorderItemsVisible(ui->checkBox_ToggleBorder->isChecked()); + setConnectionItemsVisible(false); +} + +void Editor::setEditingConnections() { + current_view = map_item; + if (map_item) { + map_item->draw(); + map_item->setVisible(true); + map_item->setEnabled(false); + populateConnectionMapPickers(); + ui->label_NumConnections->setText(QString::number(map->connections.length())); + setConnectionsVisibility(false); + setDiveEmergeControls(); + bool controlsEnabled = selected_connection_item != nullptr; + setConnectionEditControlsEnabled(controlsEnabled); + if (selected_connection_item) { + onConnectionOffsetChanged(selected_connection_item->connection->offset.toInt()); + setConnectionMap(selected_connection_item->connection->map_name); + setCurrentConnectionDirection(selected_connection_item->connection->direction); + } + } + if (collision_item) { + collision_item->setVisible(false); + } + if (events_group) { + events_group->setVisible(false); + } + setBorderItemsVisible(true, 0.4); + setConnectionItemsVisible(true); +} + +void Editor::setDiveEmergeControls() { + ui->comboBox_DiveMap->blockSignals(true); + ui->comboBox_EmergeMap->blockSignals(true); + ui->comboBox_DiveMap->setCurrentText(""); + ui->comboBox_EmergeMap->setCurrentText(""); + for (MapConnection* connection : map->connections) { + if (connection->direction == "dive") { + ui->comboBox_DiveMap->setCurrentText(connection->map_name); + } else if (connection->direction == "emerge") { + ui->comboBox_EmergeMap->setCurrentText(connection->map_name); + } + } + ui->comboBox_DiveMap->blockSignals(false); + ui->comboBox_EmergeMap->blockSignals(false); +} + +void Editor::populateConnectionMapPickers() { + ui->comboBox_ConnectedMap->blockSignals(true); + ui->comboBox_DiveMap->blockSignals(true); + ui->comboBox_EmergeMap->blockSignals(true); + + ui->comboBox_ConnectedMap->clear(); + ui->comboBox_ConnectedMap->addItems(*project->mapNames); + ui->comboBox_DiveMap->clear(); + ui->comboBox_DiveMap->addItems(*project->mapNames); + ui->comboBox_EmergeMap->clear(); + ui->comboBox_EmergeMap->addItems(*project->mapNames); + + ui->comboBox_ConnectedMap->blockSignals(false); + ui->comboBox_DiveMap->blockSignals(true); + ui->comboBox_EmergeMap->blockSignals(true); +} + +void Editor::setConnectionItemsVisible(bool visible) { + for (ConnectionPixmapItem* item : connection_edit_items) { + item->setVisible(visible); + item->setEnabled(visible); + } +} + +void Editor::setBorderItemsVisible(bool visible, qreal opacity) { + for (QGraphicsPixmapItem* item : borderItems) { + item->setVisible(visible); + item->setOpacity(opacity); + } +} + +void Editor::setCurrentConnectionDirection(QString curDirection) { + if (!selected_connection_item) + return; + + selected_connection_item->connection->direction = curDirection; + + Map *connected_map = project->getMap(selected_connection_item->connection->map_name); + QPixmap pixmap = connected_map->renderConnection(*selected_connection_item->connection); + int offset = selected_connection_item->connection->offset.toInt(nullptr, 0); + selected_connection_item->initialOffset = offset; + int x = 0, y = 0; + if (selected_connection_item->connection->direction == "up") { + x = offset * 16; + y = -pixmap.height(); + } else if (selected_connection_item->connection->direction == "down") { + x = offset * 16; + y = map->getHeight() * 16; + } else if (selected_connection_item->connection->direction == "left") { + x = -pixmap.width(); + y = offset * 16; + } else if (selected_connection_item->connection->direction == "right") { + x = map->getWidth() * 16; + y = offset * 16; + } + + selected_connection_item->basePixmap = pixmap; + QPainter painter(&pixmap); + painter.setPen(QColor(255, 0, 255)); + painter.drawRect(0, 0, pixmap.width() - 1, pixmap.height() - 1); + painter.end(); + selected_connection_item->setPixmap(pixmap); + selected_connection_item->initialX = x; + selected_connection_item->initialY = y; + selected_connection_item->blockSignals(true); + selected_connection_item->setX(x); + selected_connection_item->setY(y); + selected_connection_item->setZValue(-1); + selected_connection_item->blockSignals(false); + + setConnectionEditControlValues(selected_connection_item->connection); +} + +void Editor::updateCurrentConnectionDirection(QString curDirection) { + if (!selected_connection_item) + return; + + QString originalDirection = selected_connection_item->connection->direction; + setCurrentConnectionDirection(curDirection); + updateMirroredConnectionDirection(selected_connection_item->connection, originalDirection); +} + +void Editor::onConnectionMoved(MapConnection* connection) { + updateMirroredConnectionOffset(connection); + onConnectionOffsetChanged(connection->offset.toInt()); +} + +void Editor::onConnectionOffsetChanged(int newOffset) { + ui->spinBox_ConnectionOffset->blockSignals(true); + ui->spinBox_ConnectionOffset->setValue(newOffset); + ui->spinBox_ConnectionOffset->blockSignals(false); + +} + +void Editor::setConnectionEditControlValues(MapConnection* connection) { + QString mapName = connection ? connection->map_name : ""; + QString direction = connection ? connection->direction : ""; + int offset = connection ? connection->offset.toInt() : 0; + + ui->comboBox_ConnectedMap->blockSignals(true); + ui->comboBox_ConnectionDirection->blockSignals(true); + ui->spinBox_ConnectionOffset->blockSignals(true); + + ui->comboBox_ConnectedMap->setCurrentText(mapName); + ui->comboBox_ConnectionDirection->setCurrentText(direction); + ui->spinBox_ConnectionOffset->setValue(offset); + + ui->comboBox_ConnectedMap->blockSignals(false); + ui->comboBox_ConnectionDirection->blockSignals(false); + ui->spinBox_ConnectionOffset->blockSignals(false); +} + +void Editor::setConnectionEditControlsEnabled(bool enabled) { + ui->comboBox_ConnectionDirection->setEnabled(enabled); + ui->comboBox_ConnectedMap->setEnabled(enabled); + ui->spinBox_ConnectionOffset->setEnabled(enabled); + + if (!enabled) { + setConnectionEditControlValues(nullptr); + } +} + +void Editor::onConnectionItemSelected(ConnectionPixmapItem* connectionItem) { + if (!connectionItem) + return; + + for (ConnectionPixmapItem* item : connection_edit_items) { + bool isSelectedItem = item == connectionItem; + int zValue = isSelectedItem ? 0 : -1; + qreal opacity = isSelectedItem ? 1 : 0.75; + item->setZValue(zValue); + item->render(opacity); + if (isSelectedItem) { + QPixmap pixmap = item->pixmap(); + QPainter painter(&pixmap); + painter.setPen(QColor(255, 0, 255)); + painter.drawRect(0, 0, pixmap.width() - 1, pixmap.height() - 1); + painter.end(); + item->setPixmap(pixmap); + } + } + selected_connection_item = connectionItem; + setConnectionEditControlsEnabled(true); + setConnectionEditControlValues(selected_connection_item->connection); + ui->spinBox_ConnectionOffset->setMaximum(selected_connection_item->getMaxOffset()); + ui->spinBox_ConnectionOffset->setMinimum(selected_connection_item->getMinOffset()); + onConnectionOffsetChanged(selected_connection_item->connection->offset.toInt()); +} + +void Editor::setSelectedConnectionFromMap(QString mapName) { + // Search for the first connection that connects to the given map map. + for (ConnectionPixmapItem* item : connection_edit_items) { + if (item->connection->map_name == mapName) { + onConnectionItemSelected(item); + break; + } + } +} + +void Editor::onConnectionItemDoubleClicked(ConnectionPixmapItem* connectionItem) { + emit loadMapRequested(connectionItem->connection->map_name, map->name); +} + +void Editor::onConnectionDirectionChanged(QString newDirection) { + ui->comboBox_ConnectionDirection->blockSignals(true); + ui->comboBox_ConnectionDirection->setCurrentText(newDirection); + ui->comboBox_ConnectionDirection->blockSignals(false); +} + +void Editor::onBorderMetatilesChanged() { + displayMapBorder(); +} + +void Editor::onHoveredMovementPermissionChanged(uint16_t collision, uint16_t elevation) { + this->ui->statusBar->showMessage(this->getMovementPermissionText(collision, elevation)); +} + +void Editor::onHoveredMovementPermissionCleared() { + this->ui->statusBar->clearMessage(); +} + +void Editor::onHoveredMetatileSelectionChanged(uint16_t metatileId) { + QString message = QString("Metatile: 0x%1") + .arg(QString("%1").arg(metatileId, 3, 16, QChar('0')).toUpper()); + this->ui->statusBar->showMessage(message); +} + +void Editor::onHoveredMetatileSelectionCleared() { + this->ui->statusBar->clearMessage(); +} + +void Editor::onSelectedMetatilesChanged() { + this->redrawCurrentMetatilesSelection(); +} + +void Editor::onHoveredMapMetatileChanged(int x, int y) { + if (x >= 0 && x < map->getWidth() && y >= 0 && y < map->getHeight()) { + int blockIndex = y * map->getWidth() + x; + int tile = map->layout->blockdata->blocks->at(blockIndex).tile; + this->ui->statusBar->showMessage(QString("X: %1, Y: %2, Metatile: 0x%3, Scale = %4x") + .arg(x) + .arg(y) + .arg(QString("%1").arg(tile, 3, 16, QChar('0')).toUpper()) + .arg(QString::number(pow(map->scale_base, map->scale_exp)))); + } +} + +void Editor::onHoveredMapMetatileCleared() { + this->ui->statusBar->clearMessage(); +} + +void Editor::onHoveredMapMovementPermissionChanged(int x, int y) { + if (x >= 0 && x < map->getWidth() && y >= 0 && y < map->getHeight()) { + int blockIndex = y * map->getWidth() + x; + uint16_t collision = map->layout->blockdata->blocks->at(blockIndex).collision; + uint16_t elevation = map->layout->blockdata->blocks->at(blockIndex).elevation; + QString message = QString("X: %1, Y: %2, %3") + .arg(x) + .arg(y) + .arg(this->getMovementPermissionText(collision, elevation)); + this->ui->statusBar->showMessage(message); + } +} + +void Editor::onHoveredMapMovementPermissionCleared() { + this->ui->statusBar->clearMessage(); +} + +QString Editor::getMovementPermissionText(uint16_t collision, uint16_t elevation){ + QString message; + if (collision == 0 && elevation == 0) { + message = "Collision: Transition between elevations"; + } else if (collision == 0 && elevation == 15) { + message = "Collision: Multi-Level (Bridge)"; + } else if (collision == 0 && elevation == 1) { + message = "Collision: Surf"; + } else if (collision == 0) { + message = QString("Collision: Passable, Elevation: %1").arg(elevation); + } else { + message = QString("Collision: Impassable, Elevation: %1").arg(elevation); + } + return message; +} + +void Editor::setConnectionsVisibility(bool visible) { + for (QGraphicsPixmapItem* item : connection_items) { + item->setVisible(visible); + item->setActive(visible); + } +} + +void Editor::setMap(QString map_name) { + if (map_name.isNull()) { + return; + } + if (project) { + map = project->loadMap(map_name); + selected_events->clear(); + displayMap(); + updateSelectedEvents(); + } +} + +void Editor::mouseEvent_map(QGraphicsSceneMouseEvent *event, MapPixmapItem *item) { + if (map_edit_mode == "paint") { + if (event->buttons() & Qt::RightButton) { + item->updateMetatileSelection(event); + } else if (event->buttons() & Qt::MiddleButton) { + item->floodFill(event); + } else { + item->paint(event); + } + } else if (map_edit_mode == "select") { + item->select(event); + } else if (map_edit_mode == "fill") { + if (event->buttons() & Qt::RightButton) { + item->updateMetatileSelection(event); + } else { + item->floodFill(event); + } + } else if (map_edit_mode == "pick") { + + if (event->buttons() & Qt::RightButton) { + item->updateMetatileSelection(event); + } else { + item->pick(event); + } + } else if (map_edit_mode == "shift") { + item->shift(event); + } +} +void Editor::mouseEvent_collision(QGraphicsSceneMouseEvent *event, CollisionPixmapItem *item) { + if (map_edit_mode == "paint") { + if (event->buttons() & Qt::RightButton) { + item->updateMovementPermissionSelection(event); + } else if (event->buttons() & Qt::MiddleButton) { + item->floodFill(event); + } else { + item->paint(event); + } + } else if (map_edit_mode == "select") { + item->select(event); + } else if (map_edit_mode == "fill") { + if (event->buttons() & Qt::RightButton) { + item->pick(event); + } else { + item->floodFill(event); + } + } else if (map_edit_mode == "pick") { + item->pick(event); + } else if (map_edit_mode == "shift") { + item->shift(event); + } +} + +void Editor::displayMap() { + if (!scene) + scene = new QGraphicsScene; + + if (map_item && scene) { + scene->removeItem(map_item); + delete map_item; + } + + displayMetatileSelector(); + displayMovementPermissionSelector(); + displayMapMetatiles(); + displayMapMovementPermissions(); + displayBorderMetatiles(); + displayCurrentMetatilesSelection(); + displayMapEvents(); + displayMapConnections(); + displayMapBorder(); + displayMapGrid(); + + if (map_item) { + map_item->setVisible(false); + } + if (collision_item) { + collision_item->setVisible(false); + } + if (events_group) { + events_group->setVisible(false); + } +} + +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; + 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::displayMapMetatiles() { + map_item = new MapPixmapItem(map, this->metatile_selector_item, this->settings); + connect(map_item, SIGNAL(mouseEvent(QGraphicsSceneMouseEvent*,MapPixmapItem*)), + this, SLOT(mouseEvent_map(QGraphicsSceneMouseEvent*,MapPixmapItem*))); + connect(map_item, SIGNAL(hoveredMapMetatileChanged(int, int)), + this, SLOT(onHoveredMapMetatileChanged(int, int))); + connect(map_item, SIGNAL(hoveredMapMetatileCleared()), + this, SLOT(onHoveredMapMetatileCleared())); + + map_item->draw(true); + scene->addItem(map_item); + + int tw = 16; + int th = 16; + scene->setSceneRect( + -6 * tw, + -6 * th, + map_item->pixmap().width() + 12 * tw, + map_item->pixmap().height() + 12 * th + ); +} + +void Editor::displayMapMovementPermissions() { + if (collision_item && scene) { + scene->removeItem(collision_item); + delete collision_item; + } + collision_item = new CollisionPixmapItem(map, this->movement_permissions_selector_item, this->metatile_selector_item, this->settings); + connect(collision_item, SIGNAL(mouseEvent(QGraphicsSceneMouseEvent*,CollisionPixmapItem*)), + this, SLOT(mouseEvent_collision(QGraphicsSceneMouseEvent*,CollisionPixmapItem*))); + connect(collision_item, SIGNAL(hoveredMapMovementPermissionChanged(int, int)), + this, SLOT(onHoveredMapMovementPermissionChanged(int, int))); + connect(collision_item, SIGNAL(hoveredMapMovementPermissionCleared()), + this, SLOT(onHoveredMapMovementPermissionCleared())); + + collision_item->draw(true); + scene->addItem(collision_item); +} + +void Editor::displayBorderMetatiles() { + if (selected_border_metatiles_item && selected_border_metatiles_item->scene()) { + selected_border_metatiles_item->scene()->removeItem(selected_border_metatiles_item); + delete selected_border_metatiles_item; + } + + scene_selected_border_metatiles = new QGraphicsScene; + selected_border_metatiles_item = new BorderMetatilesPixmapItem(map, this->metatile_selector_item); + selected_border_metatiles_item->draw(); + scene_selected_border_metatiles->addItem(selected_border_metatiles_item); + + connect(selected_border_metatiles_item, SIGNAL(borderMetatilesChanged()), this, SLOT(onBorderMetatilesChanged())); +} + +void Editor::displayCurrentMetatilesSelection() { + if (scene_current_metatile_selection_item && scene_current_metatile_selection_item->scene()) { + scene_current_metatile_selection_item->scene()->removeItem(scene_current_metatile_selection_item); + delete scene_current_metatile_selection_item; + } + + scene_current_metatile_selection = new QGraphicsScene; + scene_current_metatile_selection_item = new CurrentSelectedMetatilesPixmapItem(map, this->metatile_selector_item); + scene_current_metatile_selection_item->draw(); + scene_current_metatile_selection->addItem(scene_current_metatile_selection_item); +} + +void Editor::redrawCurrentMetatilesSelection() { + if (scene_current_metatile_selection_item) { + scene_current_metatile_selection_item->draw(); + emit currentMetatilesSelectionChanged(); + } +} + +void Editor::displayMovementPermissionSelector() { + if (movement_permissions_selector_item && movement_permissions_selector_item->scene()) { + movement_permissions_selector_item->scene()->removeItem(movement_permissions_selector_item); + delete scene_collision_metatiles; + } + + scene_collision_metatiles = new QGraphicsScene; + 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); +} + +void Editor::displayMapEvents() { + if (events_group) { + for (QGraphicsItem *child : events_group->childItems()) { + events_group->removeFromGroup(child); + delete child; + } + + if (events_group->scene()) { + events_group->scene()->removeItem(events_group); + } + + delete events_group; + } + + selected_events->clear(); + + events_group = new QGraphicsItemGroup; + scene->addItem(events_group); + + QList<Event *> events = map->getAllEvents(); + project->loadEventPixmaps(events); + for (Event *event : events) { + addMapEvent(event); + } + //objects_group->setFiltersChildEvents(false); + events_group->setHandlesChildEvents(false); + + emit objectsChanged(); +} + +DraggablePixmapItem *Editor::addMapEvent(Event *event) { + DraggablePixmapItem *object = new DraggablePixmapItem(event, this); + events_group->addToGroup(object); + return object; +} + +void Editor::displayMapConnections() { + for (QGraphicsPixmapItem* item : connection_items) { + if (item->scene()) { + item->scene()->removeItem(item); + } + delete item; + } + connection_items.clear(); + + for (ConnectionPixmapItem* item : connection_edit_items) { + if (item->scene()) { + item->scene()->removeItem(item); + } + delete item; + } + selected_connection_item = nullptr; + connection_edit_items.clear(); + + for (MapConnection *connection : map->connections) { + if (connection->direction == "dive" || connection->direction == "emerge") { + continue; + } + createConnectionItem(connection, false); + } + + if (!connection_edit_items.empty()) { + onConnectionItemSelected(connection_edit_items.first()); + } +} + +void Editor::createConnectionItem(MapConnection* connection, bool hide) { + Map *connected_map = project->getMap(connection->map_name); + QPixmap pixmap = connected_map->renderConnection(*connection); + int offset = connection->offset.toInt(nullptr, 0); + int x = 0, y = 0; + if (connection->direction == "up") { + x = offset * 16; + y = -pixmap.height(); + } else if (connection->direction == "down") { + x = offset * 16; + y = map->getHeight() * 16; + } else if (connection->direction == "left") { + x = -pixmap.width(); + y = offset * 16; + } else if (connection->direction == "right") { + x = map->getWidth() * 16; + y = offset * 16; + } + + QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap); + item->setZValue(-1); + item->setX(x); + item->setY(y); + scene->addItem(item); + connection_items.append(item); + item->setVisible(!hide); + + ConnectionPixmapItem *connection_edit_item = new ConnectionPixmapItem(pixmap, connection, x, y, map->getWidth(), map->getHeight()); + connection_edit_item->setX(x); + connection_edit_item->setY(y); + connection_edit_item->setZValue(-1); + scene->addItem(connection_edit_item); + connect(connection_edit_item, SIGNAL(connectionMoved(MapConnection*)), this, SLOT(onConnectionMoved(MapConnection*))); + connect(connection_edit_item, SIGNAL(connectionItemSelected(ConnectionPixmapItem*)), this, SLOT(onConnectionItemSelected(ConnectionPixmapItem*))); + connect(connection_edit_item, SIGNAL(connectionItemDoubleClicked(ConnectionPixmapItem*)), this, SLOT(onConnectionItemDoubleClicked(ConnectionPixmapItem*))); + connection_edit_items.append(connection_edit_item); +} + +void Editor::displayMapBorder() { + for (QGraphicsPixmapItem* item : borderItems) { + if (item->scene()) { + item->scene()->removeItem(item); + } + delete item; + } + borderItems.clear(); + + QPixmap pixmap = map->renderBorder(); + for (int y = -6; y < map->getHeight() + 6; y += 2) + for (int x = -6; x < map->getWidth() + 6; x += 2) { + QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap); + item->setX(x * 16); + item->setY(y * 16); + item->setZValue(-2); + scene->addItem(item); + borderItems.append(item); + } +} + +void Editor::displayMapGrid() { + for (QGraphicsLineItem* item : gridLines) { + if (item && item->scene()) { + item->scene()->removeItem(item); + } + delete item; + } + gridLines.clear(); + ui->checkBox_ToggleGrid->disconnect(); + + int pixelWidth = map->getWidth() * 16; + int pixelHeight = map->getHeight() * 16; + for (int i = 0; i <= map->getWidth(); i++) { + int x = i * 16; + QGraphicsLineItem *line = scene->addLine(x, 0, x, pixelHeight); + line->setVisible(ui->checkBox_ToggleGrid->isChecked()); + gridLines.append(line); + connect(ui->checkBox_ToggleGrid, &QCheckBox::toggled, [=](bool checked){line->setVisible(checked);}); + } + for (int j = 0; j <= map->getHeight(); j++) { + int y = j * 16; + QGraphicsLineItem *line = scene->addLine(0, y, pixelWidth, y); + line->setVisible(ui->checkBox_ToggleGrid->isChecked()); + gridLines.append(line); + connect(ui->checkBox_ToggleGrid, &QCheckBox::toggled, [=](bool checked){line->setVisible(checked);}); + } +} + +void Editor::updateConnectionOffset(int offset) { + if (!selected_connection_item) + return; + + selected_connection_item->blockSignals(true); + offset = qMin(offset, selected_connection_item->getMaxOffset()); + offset = qMax(offset, selected_connection_item->getMinOffset()); + selected_connection_item->connection->offset = QString::number(offset); + if (selected_connection_item->connection->direction == "up" || selected_connection_item->connection->direction == "down") { + selected_connection_item->setX(selected_connection_item->initialX + (offset - selected_connection_item->initialOffset) * 16); + } else if (selected_connection_item->connection->direction == "left" || selected_connection_item->connection->direction == "right") { + selected_connection_item->setY(selected_connection_item->initialY + (offset - selected_connection_item->initialOffset) * 16); + } + selected_connection_item->blockSignals(false); + updateMirroredConnectionOffset(selected_connection_item->connection); +} + +void Editor::setConnectionMap(QString mapName) { + if (!mapName.isEmpty() && !project->mapNames->contains(mapName)) { + qDebug() << "Invalid map name " << mapName << " specified for connection."; + return; + } + if (!selected_connection_item) + return; + + if (mapName.isEmpty()) { + removeCurrentConnection(); + return; + } + + QString originalMapName = selected_connection_item->connection->map_name; + setConnectionEditControlsEnabled(true); + selected_connection_item->connection->map_name = mapName; + setCurrentConnectionDirection(selected_connection_item->connection->direction); + updateMirroredConnectionMap(selected_connection_item->connection, originalMapName); +} + +void Editor::addNewConnection() { + // Find direction with least number of connections. + QMap<QString, int> directionCounts = QMap<QString, int>({{"up", 0}, {"right", 0}, {"down", 0}, {"left", 0}}); + for (MapConnection* connection : map->connections) { + directionCounts[connection->direction]++; + } + QString minDirection = "up"; + int minCount = INT_MAX; + for (QString direction : directionCounts.keys()) { + if (directionCounts[direction] < minCount) { + minDirection = direction; + minCount = directionCounts[direction]; + } + } + + // Don't connect the map to itself. + QString defaultMapName = project->mapNames->first(); + if (defaultMapName == map->name) { + defaultMapName = project->mapNames->value(1); + } + + MapConnection* newConnection = new MapConnection; + newConnection->direction = minDirection; + newConnection->offset = "0"; + newConnection->map_name = defaultMapName; + map->connections.append(newConnection); + createConnectionItem(newConnection, true); + onConnectionItemSelected(connection_edit_items.last()); + ui->label_NumConnections->setText(QString::number(map->connections.length())); + + updateMirroredConnection(newConnection, newConnection->direction, newConnection->map_name); +} + +void Editor::updateMirroredConnectionOffset(MapConnection* connection) { + updateMirroredConnection(connection, connection->direction, connection->map_name); +} +void Editor::updateMirroredConnectionDirection(MapConnection* connection, QString originalDirection) { + updateMirroredConnection(connection, originalDirection, connection->map_name); +} +void Editor::updateMirroredConnectionMap(MapConnection* connection, QString originalMapName) { + updateMirroredConnection(connection, connection->direction, originalMapName); +} +void Editor::removeMirroredConnection(MapConnection* connection) { + updateMirroredConnection(connection, connection->direction, connection->map_name, true); +} +void Editor::updateMirroredConnection(MapConnection* connection, QString originalDirection, QString originalMapName, bool isDelete) { + if (!ui->checkBox_MirrorConnections->isChecked()) + return; + + static QMap<QString, QString> oppositeDirections = QMap<QString, QString>({ + {"up", "down"}, {"right", "left"}, + {"down", "up"}, {"left", "right"}, + {"dive", "emerge"},{"emerge", "dive"}}); + QString oppositeDirection = oppositeDirections.value(originalDirection); + + // Find the matching connection in the connected map. + MapConnection* mirrorConnection = nullptr; + Map* otherMap = project->getMap(originalMapName); + for (MapConnection* conn : otherMap->connections) { + if (conn->direction == oppositeDirection && conn->map_name == map->name) { + mirrorConnection = conn; + } + } + + if (isDelete) { + if (mirrorConnection) { + otherMap->connections.removeOne(mirrorConnection); + delete mirrorConnection; + } + return; + } + + if (connection->direction != originalDirection || connection->map_name != originalMapName) { + if (mirrorConnection) { + otherMap->connections.removeOne(mirrorConnection); + delete mirrorConnection; + mirrorConnection = nullptr; + otherMap = project->getMap(connection->map_name); + } + } + + // Create a new mirrored connection, if a matching one doesn't already exist. + if (!mirrorConnection) { + mirrorConnection = new MapConnection; + mirrorConnection->direction = oppositeDirections.value(connection->direction); + mirrorConnection->map_name = map->name; + otherMap->connections.append(mirrorConnection); + } + + mirrorConnection->offset = QString::number(-connection->offset.toInt()); +} + +void Editor::removeCurrentConnection() { + if (!selected_connection_item) + return; + + map->connections.removeOne(selected_connection_item->connection); + connection_edit_items.removeOne(selected_connection_item); + removeMirroredConnection(selected_connection_item->connection); + + if (selected_connection_item && selected_connection_item->scene()) { + selected_connection_item->scene()->removeItem(selected_connection_item); + delete selected_connection_item; + } + + selected_connection_item = nullptr; + setConnectionEditControlsEnabled(false); + ui->spinBox_ConnectionOffset->setValue(0); + ui->label_NumConnections->setText(QString::number(map->connections.length())); + + if (connection_edit_items.length() > 0) { + onConnectionItemSelected(connection_edit_items.last()); + } +} + +void Editor::updateDiveMap(QString mapName) { + updateDiveEmergeMap(mapName, "dive"); +} + +void Editor::updateEmergeMap(QString mapName) { + updateDiveEmergeMap(mapName, "emerge"); +} + +void Editor::updateDiveEmergeMap(QString mapName, QString direction) { + if (!mapName.isEmpty() && !project->mapNamesToMapConstants->contains(mapName)) { + qDebug() << "Invalid " << direction << " map connection: " << mapName; + return; + } + + MapConnection* connection = nullptr; + for (MapConnection* conn : map->connections) { + if (conn->direction == direction) { + connection = conn; + break; + } + } + + if (mapName.isEmpty()) { + // Remove dive/emerge connection + if (connection) { + map->connections.removeOne(connection); + removeMirroredConnection(connection); + } + } else { + if (!connection) { + connection = new MapConnection; + connection->direction = direction; + connection->offset = "0"; + connection->map_name = mapName; + map->connections.append(connection); + updateMirroredConnection(connection, connection->direction, connection->map_name); + } else { + QString originalMapName = connection->map_name; + connection->map_name = mapName; + updateMirroredConnectionMap(connection, originalMapName); + } + } + + ui->label_NumConnections->setText(QString::number(map->connections.length())); +} + +void Editor::updatePrimaryTileset(QString tilesetLabel) +{ + if (map->layout->tileset_primary_label != tilesetLabel) + { + map->layout->tileset_primary_label = tilesetLabel; + map->layout->tileset_primary = project->getTileset(tilesetLabel); + emit tilesetChanged(map->name); + } +} + +void Editor::updateSecondaryTileset(QString tilesetLabel) +{ + if (map->layout->tileset_secondary_label != tilesetLabel) + { + map->layout->tileset_secondary_label = tilesetLabel; + map->layout->tileset_secondary = project->getTileset(tilesetLabel); + emit tilesetChanged(map->name); + } +} + +void Editor::toggleBorderVisibility(bool visible) +{ + this->setBorderItemsVisible(visible); + this->setConnectionsVisibility(visible); +} + +void DraggablePixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *mouse) { + active = true; + last_x = static_cast<int>(mouse->pos().x() + this->pos().x()) / 16; + last_y = static_cast<int>(mouse->pos().y() + this->pos().y()) / 16; + this->editor->selectMapEvent(this, mouse->modifiers() & Qt::ControlModifier); + this->editor->updateSelectedEvents(); + selectingEvent = true; + //qDebug() << QString("(%1, %2)").arg(event->get("x")).arg(event->get("y")); +} + +void DraggablePixmapItem::move(int x, int y) { + event->setX(event->x() + x); + event->setY(event->y() + y); + updatePosition(); + emitPositionChanged(); +} + +void DraggablePixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *mouse) { + if (active) { + int x = static_cast<int>(mouse->pos().x() + this->pos().x()) / 16; + int y = static_cast<int>(mouse->pos().y() + this->pos().y()) / 16; + if (x != last_x || y != last_y) { + if (editor->selected_events->contains(this)) { + for (DraggablePixmapItem *item : *editor->selected_events) { + item->move(x - last_x, y - last_y); + } + } else { + move(x - last_x, y - last_y); + } + last_x = x; + last_y = y; + //qDebug() << QString("(%1, %2)").arg(event->get("x")).arg(event->get("x")); + } + } +} + +void DraggablePixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *) { + active = false; +} + +void DraggablePixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) { + if (this->event->get("event_type") == EventType::Warp) { + QString destMap = this->event->get("destination_map_name"); + if (destMap != NONE_MAP_NAME) { + emit editor->warpEventDoubleClicked(this->event->get("destination_map_name"), this->event->get("destination_warp")); + } + } +} + +QList<DraggablePixmapItem *> *Editor::getObjects() { + QList<DraggablePixmapItem *> *list = new QList<DraggablePixmapItem *>; + for (Event *event : map->getAllEvents()) { + for (QGraphicsItem *child : events_group->childItems()) { + DraggablePixmapItem *item = static_cast<DraggablePixmapItem *>(child); + if (item->event == event) { + list->append(item); + break; + } + } + } + return list; +} + +void Editor::redrawObject(DraggablePixmapItem *item) { + if (item) { + item->setPixmap(item->event->pixmap); + item->setShapeMode(QGraphicsPixmapItem::BoundingRectShape); + if (selected_events && selected_events->contains(item)) { + QImage image = item->pixmap().toImage(); + QPainter painter(&image); + painter.setPen(QColor(250, 0, 255)); + painter.drawRect(0, 0, image.width() - 1, image.height() - 1); + painter.end(); + item->setPixmap(QPixmap::fromImage(image)); + } + } +} + +void Editor::updateSelectedEvents() { + for (DraggablePixmapItem *item : *(getObjects())) { + redrawObject(item); + } + emit selectedObjectsChanged(); +} + +void Editor::selectMapEvent(DraggablePixmapItem *object) { + selectMapEvent(object, false); +} + +void Editor::selectMapEvent(DraggablePixmapItem *object, bool toggle) { + if (selected_events && object) { + if (selected_events->contains(object)) { + if (toggle) { + selected_events->removeOne(object); + } + } else { + if (!toggle) { + selected_events->clear(); + } + selected_events->append(object); + } + updateSelectedEvents(); + } +} + +DraggablePixmapItem* Editor::addNewEvent(QString event_type) { + if (project && map) { + Event *event = Event::createNewEvent(event_type, map->name); + event->put("map_name", map->name); + map->addEvent(event); + project->loadEventPixmaps(map->getAllEvents()); + DraggablePixmapItem *object = addMapEvent(event); + return object; + } + return nullptr; +} + +void Editor::deleteEvent(Event *event) { + Map *map = project->getMap(event->get("map_name")); + if (map) { + map->removeEvent(event); + } + //selected_events->removeAll(event); + //updateSelectedObjects(); +} + +// It doesn't seem to be possible to prevent the mousePress event +// from triggering both event's DraggablePixmapItem and the background mousePress. +// Since the DraggablePixmapItem's event fires first, we can set a temp +// variable "selectingEvent" so that we can detect whether or not the user +// is clicking on the background instead of an event. +void Editor::objectsView_onMousePress(QMouseEvent *event) { + bool multiSelect = event->modifiers() & Qt::ControlModifier; + if (!selectingEvent && !multiSelect && selected_events->length() > 1) { + DraggablePixmapItem *first = selected_events->first(); + selected_events->clear(); + selected_events->append(first); + updateSelectedEvents(); + } + + selectingEvent = false; +} diff --git a/editor.h b/src/editor.h old mode 100755 new mode 100644 similarity index 97% rename from editor.h rename to src/editor.h index 014e7d13..df2714d5 --- a/editor.h +++ b/src/editor.h @@ -1,259 +1,259 @@ -#ifndef EDITOR_H -#define EDITOR_H - -#include <QGraphicsScene> -#include <QGraphicsItemGroup> -#include <QGraphicsSceneMouseEvent> -#include <QGraphicsItemAnimation> -#include <QComboBox> -#include <QCheckBox> -#include <QCursor> - -#include "mapconnection.h" -#include "metatileselector.h" -#include "movementpermissionsselector.h" -#include "project.h" -#include "ui_mainwindow.h" -#include "bordermetatilespixmapitem.h" -#include "connectionpixmapitem.h" -#include "currentselectedmetatilespixmapitem.h" -#include "collisionpixmapitem.h" -#include "mappixmapitem.h" -#include "settings.h" - -class DraggablePixmapItem; -class MetatilesPixmapItem; - -class Editor : public QObject -{ - Q_OBJECT -public: - Editor(Ui::MainWindow* ui); -public: - Ui::MainWindow* ui; - QObject *parent = nullptr; - Project *project = nullptr; - Map *map = nullptr; - Settings *settings; - void saveProject(); - void save(); - void undo(); - void redo(); - void setMap(QString map_name); - void displayMap(); - void displayMetatileSelector(); - void displayMapMetatiles(); - void displayMapMovementPermissions(); - void displayBorderMetatiles(); - void displayCurrentMetatilesSelection(); - void redrawCurrentMetatilesSelection(); - void displayMovementPermissionSelector(); - void displayElevationMetatiles(); - void displayMapEvents(); - void displayMapConnections(); - void displayMapBorder(); - void displayMapGrid(); - - void setEditingMap(); - void setEditingCollision(); - void setEditingObjects(); - void setEditingConnections(); - void setCurrentConnectionDirection(QString curDirection); - void updateCurrentConnectionDirection(QString curDirection); - void setConnectionsVisibility(bool visible); - void updateConnectionOffset(int offset); - void setConnectionMap(QString mapName); - void addNewConnection(); - void removeCurrentConnection(); - void updateDiveMap(QString mapName); - void updateEmergeMap(QString mapName); - void setSelectedConnectionFromMap(QString mapName); - void updatePrimaryTileset(QString tilesetLabel); - void updateSecondaryTileset(QString tilesetLabel); - void toggleBorderVisibility(bool visible); - - DraggablePixmapItem *addMapEvent(Event *event); - void selectMapEvent(DraggablePixmapItem *object); - void selectMapEvent(DraggablePixmapItem *object, bool toggle); - DraggablePixmapItem *addNewEvent(QString event_type); - Event* createNewEvent(QString event_type); - void deleteEvent(Event *); - void updateSelectedEvents(); - void redrawObject(DraggablePixmapItem *item); - QList<DraggablePixmapItem *> *getObjects(); - - QGraphicsScene *scene = nullptr; - QGraphicsPixmapItem *current_view = nullptr; - MapPixmapItem *map_item = nullptr; - ConnectionPixmapItem* selected_connection_item = nullptr; - QList<QGraphicsPixmapItem*> connection_items; - QList<ConnectionPixmapItem*> connection_edit_items; - CollisionPixmapItem *collision_item = nullptr; - QGraphicsItemGroup *events_group = nullptr; - QList<QGraphicsPixmapItem*> borderItems; - QList<QGraphicsLineItem*> gridLines; - - QGraphicsScene *scene_metatiles = nullptr; - QGraphicsScene *scene_current_metatile_selection = nullptr; - QGraphicsScene *scene_selected_border_metatiles = nullptr; - QGraphicsScene *scene_collision_metatiles = nullptr; - QGraphicsScene *scene_elevation_metatiles = nullptr; - MetatileSelector *metatile_selector_item = nullptr; - - BorderMetatilesPixmapItem *selected_border_metatiles_item = nullptr; - CurrentSelectedMetatilesPixmapItem *scene_current_metatile_selection_item = nullptr; - MovementPermissionsSelector *movement_permissions_selector_item = nullptr; - - QList<DraggablePixmapItem*> *events = nullptr; - QList<DraggablePixmapItem*> *selected_events = nullptr; - - QString map_edit_mode; - QString prev_edit_mode; - - void objectsView_onMousePress(QMouseEvent *event); - void objectsView_onMouseMove(QMouseEvent *event); - void objectsView_onMouseRelease(QMouseEvent *event); - -private: - void setConnectionItemsVisible(bool); - void setBorderItemsVisible(bool, qreal = 1); - void setConnectionEditControlValues(MapConnection*); - void setConnectionEditControlsEnabled(bool); - void createConnectionItem(MapConnection* connection, bool hide); - void populateConnectionMapPickers(); - void setDiveEmergeControls(); - void updateDiveEmergeMap(QString mapName, QString direction); - void onConnectionOffsetChanged(int newOffset); - void removeMirroredConnection(MapConnection*); - void updateMirroredConnectionOffset(MapConnection*); - void updateMirroredConnectionDirection(MapConnection*, QString); - void updateMirroredConnectionMap(MapConnection*, QString); - void updateMirroredConnection(MapConnection*, QString, QString, bool isDelete = false); - Event* createNewObjectEvent(); - Event* createNewWarpEvent(); - Event* createNewHealLocationEvent(); - Event* createNewCoordScriptEvent(); - Event* createNewCoordWeatherEvent(); - Event* createNewSignEvent(); - Event* createNewHiddenItemEvent(); - Event* createNewSecretBaseEvent(); - QString getMovementPermissionText(uint16_t collision, uint16_t elevation); - -private slots: - void mouseEvent_map(QGraphicsSceneMouseEvent *event, MapPixmapItem *item); - void mouseEvent_collision(QGraphicsSceneMouseEvent *event, CollisionPixmapItem *item); - void onConnectionMoved(MapConnection*); - void onConnectionItemSelected(ConnectionPixmapItem* connectionItem); - void onConnectionItemDoubleClicked(ConnectionPixmapItem* connectionItem); - void onConnectionDirectionChanged(QString newDirection); - void onBorderMetatilesChanged(); - void onHoveredMovementPermissionChanged(uint16_t, uint16_t); - void onHoveredMovementPermissionCleared(); - void onHoveredMetatileSelectionChanged(uint16_t); - void onHoveredMetatileSelectionCleared(); - void onHoveredMapMetatileChanged(int, int); - void onHoveredMapMetatileCleared(); - void onHoveredMapMovementPermissionChanged(int, int); - void onHoveredMapMovementPermissionCleared(); - void onSelectedMetatilesChanged(); - -signals: - void objectsChanged(); - void selectedObjectsChanged(); - void loadMapRequested(QString, QString); - void tilesetChanged(QString); - void warpEventDoubleClicked(QString mapName, QString warpNum); - void currentMetatilesSelectionChanged(); -}; - - - -class DraggablePixmapItem : public QObject, public QGraphicsPixmapItem { - Q_OBJECT -public: - DraggablePixmapItem(QPixmap pixmap): QGraphicsPixmapItem(pixmap) { - } - Editor *editor = nullptr; - Event *event = nullptr; - QGraphicsItemAnimation *pos_anim = nullptr; - DraggablePixmapItem(Event *event_, Editor *editor_) : QGraphicsPixmapItem(event_->pixmap) { - event = event_; - editor = editor_; - updatePosition(); - } - bool active; - int last_x; - int last_y; - void updatePosition() { - int x = event->getPixelX(); - int y = event->getPixelY(); - setX(x); - setY(y); - setZValue(event->y()); - } - void move(int x, int y); - void emitPositionChanged() { - emit xChanged(event->x()); - emit yChanged(event->y()); - emit elevationChanged(event->elevation()); - } - void updatePixmap() { - QList<Event*> objects; - objects.append(event); - event->pixmap = QPixmap(); - editor->project->loadEventPixmaps(objects); - this->updatePosition(); - editor->redrawObject(this); - emit spriteChanged(event->pixmap); - } - void bind(QComboBox *combo, QString key) { - connect(combo, static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged), - this, [this, key](QString value){ - this->event->put(key, value); - }); - connect(this, &DraggablePixmapItem::onPropertyChanged, - this, [combo, key](QString key2, QString value){ - if (key2 == key) { - combo->addItem(value); - combo->setCurrentText(value); - } - }); - } - -signals: - void positionChanged(Event *event); - void xChanged(int); - void yChanged(int); - void elevationChanged(int); - void spriteChanged(QPixmap pixmap); - void onPropertyChanged(QString key, QString value); - -public slots: - void set_x(const QString &text) { - event->put("x", text); - updatePosition(); - } - void set_y(const QString &text) { - event->put("y", text); - updatePosition(); - } - void set_elevation(const QString &text) { - event->put("elevation", text); - updatePosition(); - } - void set_sprite(const QString &text) { - event->put("sprite", text); - updatePixmap(); - } - void set_script(const QString &text) { - event->put("script_label", text); - } - -protected: - void mousePressEvent(QGraphicsSceneMouseEvent*); - void mouseMoveEvent(QGraphicsSceneMouseEvent*); - void mouseReleaseEvent(QGraphicsSceneMouseEvent*); - void mouseDoubleClickEvent(QGraphicsSceneMouseEvent*); -}; - -#endif // EDITOR_H +#ifndef EDITOR_H +#define EDITOR_H + +#include <QGraphicsScene> +#include <QGraphicsItemGroup> +#include <QGraphicsSceneMouseEvent> +#include <QGraphicsItemAnimation> +#include <QComboBox> +#include <QCheckBox> +#include <QCursor> + +#include "mapconnection.h" +#include "metatileselector.h" +#include "movementpermissionsselector.h" +#include "project.h" +#include "ui_mainwindow.h" +#include "bordermetatilespixmapitem.h" +#include "connectionpixmapitem.h" +#include "currentselectedmetatilespixmapitem.h" +#include "collisionpixmapitem.h" +#include "mappixmapitem.h" +#include "settings.h" + +class DraggablePixmapItem; +class MetatilesPixmapItem; + +class Editor : public QObject +{ + Q_OBJECT +public: + Editor(Ui::MainWindow* ui); +public: + Ui::MainWindow* ui; + QObject *parent = nullptr; + Project *project = nullptr; + Map *map = nullptr; + Settings *settings; + void saveProject(); + void save(); + void undo(); + void redo(); + void setMap(QString map_name); + void displayMap(); + void displayMetatileSelector(); + void displayMapMetatiles(); + void displayMapMovementPermissions(); + void displayBorderMetatiles(); + void displayCurrentMetatilesSelection(); + void redrawCurrentMetatilesSelection(); + void displayMovementPermissionSelector(); + void displayElevationMetatiles(); + void displayMapEvents(); + void displayMapConnections(); + void displayMapBorder(); + void displayMapGrid(); + + void setEditingMap(); + void setEditingCollision(); + void setEditingObjects(); + void setEditingConnections(); + void setCurrentConnectionDirection(QString curDirection); + void updateCurrentConnectionDirection(QString curDirection); + void setConnectionsVisibility(bool visible); + void updateConnectionOffset(int offset); + void setConnectionMap(QString mapName); + void addNewConnection(); + void removeCurrentConnection(); + void updateDiveMap(QString mapName); + void updateEmergeMap(QString mapName); + void setSelectedConnectionFromMap(QString mapName); + void updatePrimaryTileset(QString tilesetLabel); + void updateSecondaryTileset(QString tilesetLabel); + void toggleBorderVisibility(bool visible); + + DraggablePixmapItem *addMapEvent(Event *event); + void selectMapEvent(DraggablePixmapItem *object); + void selectMapEvent(DraggablePixmapItem *object, bool toggle); + DraggablePixmapItem *addNewEvent(QString event_type); + Event* createNewEvent(QString event_type); + void deleteEvent(Event *); + void updateSelectedEvents(); + void redrawObject(DraggablePixmapItem *item); + QList<DraggablePixmapItem *> *getObjects(); + + QGraphicsScene *scene = nullptr; + QGraphicsPixmapItem *current_view = nullptr; + MapPixmapItem *map_item = nullptr; + ConnectionPixmapItem* selected_connection_item = nullptr; + QList<QGraphicsPixmapItem*> connection_items; + QList<ConnectionPixmapItem*> connection_edit_items; + CollisionPixmapItem *collision_item = nullptr; + QGraphicsItemGroup *events_group = nullptr; + QList<QGraphicsPixmapItem*> borderItems; + QList<QGraphicsLineItem*> gridLines; + + QGraphicsScene *scene_metatiles = nullptr; + QGraphicsScene *scene_current_metatile_selection = nullptr; + QGraphicsScene *scene_selected_border_metatiles = nullptr; + QGraphicsScene *scene_collision_metatiles = nullptr; + QGraphicsScene *scene_elevation_metatiles = nullptr; + MetatileSelector *metatile_selector_item = nullptr; + + BorderMetatilesPixmapItem *selected_border_metatiles_item = nullptr; + CurrentSelectedMetatilesPixmapItem *scene_current_metatile_selection_item = nullptr; + MovementPermissionsSelector *movement_permissions_selector_item = nullptr; + + QList<DraggablePixmapItem*> *events = nullptr; + QList<DraggablePixmapItem*> *selected_events = nullptr; + + QString map_edit_mode; + QString prev_edit_mode; + + void objectsView_onMousePress(QMouseEvent *event); + void objectsView_onMouseMove(QMouseEvent *event); + void objectsView_onMouseRelease(QMouseEvent *event); + +private: + void setConnectionItemsVisible(bool); + void setBorderItemsVisible(bool, qreal = 1); + void setConnectionEditControlValues(MapConnection*); + void setConnectionEditControlsEnabled(bool); + void createConnectionItem(MapConnection* connection, bool hide); + void populateConnectionMapPickers(); + void setDiveEmergeControls(); + void updateDiveEmergeMap(QString mapName, QString direction); + void onConnectionOffsetChanged(int newOffset); + void removeMirroredConnection(MapConnection*); + void updateMirroredConnectionOffset(MapConnection*); + void updateMirroredConnectionDirection(MapConnection*, QString); + void updateMirroredConnectionMap(MapConnection*, QString); + void updateMirroredConnection(MapConnection*, QString, QString, bool isDelete = false); + Event* createNewObjectEvent(); + Event* createNewWarpEvent(); + Event* createNewHealLocationEvent(); + Event* createNewCoordScriptEvent(); + Event* createNewCoordWeatherEvent(); + Event* createNewSignEvent(); + Event* createNewHiddenItemEvent(); + Event* createNewSecretBaseEvent(); + QString getMovementPermissionText(uint16_t collision, uint16_t elevation); + +private slots: + void mouseEvent_map(QGraphicsSceneMouseEvent *event, MapPixmapItem *item); + void mouseEvent_collision(QGraphicsSceneMouseEvent *event, CollisionPixmapItem *item); + void onConnectionMoved(MapConnection*); + void onConnectionItemSelected(ConnectionPixmapItem* connectionItem); + void onConnectionItemDoubleClicked(ConnectionPixmapItem* connectionItem); + void onConnectionDirectionChanged(QString newDirection); + void onBorderMetatilesChanged(); + void onHoveredMovementPermissionChanged(uint16_t, uint16_t); + void onHoveredMovementPermissionCleared(); + void onHoveredMetatileSelectionChanged(uint16_t); + void onHoveredMetatileSelectionCleared(); + void onHoveredMapMetatileChanged(int, int); + void onHoveredMapMetatileCleared(); + void onHoveredMapMovementPermissionChanged(int, int); + void onHoveredMapMovementPermissionCleared(); + void onSelectedMetatilesChanged(); + +signals: + void objectsChanged(); + void selectedObjectsChanged(); + void loadMapRequested(QString, QString); + void tilesetChanged(QString); + void warpEventDoubleClicked(QString mapName, QString warpNum); + void currentMetatilesSelectionChanged(); +}; + + + +class DraggablePixmapItem : public QObject, public QGraphicsPixmapItem { + Q_OBJECT +public: + DraggablePixmapItem(QPixmap pixmap): QGraphicsPixmapItem(pixmap) { + } + Editor *editor = nullptr; + Event *event = nullptr; + QGraphicsItemAnimation *pos_anim = nullptr; + DraggablePixmapItem(Event *event_, Editor *editor_) : QGraphicsPixmapItem(event_->pixmap) { + event = event_; + editor = editor_; + updatePosition(); + } + bool active; + int last_x; + int last_y; + void updatePosition() { + int x = event->getPixelX(); + int y = event->getPixelY(); + setX(x); + setY(y); + setZValue(event->y()); + } + void move(int x, int y); + void emitPositionChanged() { + emit xChanged(event->x()); + emit yChanged(event->y()); + emit elevationChanged(event->elevation()); + } + void updatePixmap() { + QList<Event*> objects; + objects.append(event); + event->pixmap = QPixmap(); + editor->project->loadEventPixmaps(objects); + this->updatePosition(); + editor->redrawObject(this); + emit spriteChanged(event->pixmap); + } + void bind(QComboBox *combo, QString key) { + connect(combo, static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged), + this, [this, key](QString value){ + this->event->put(key, value); + }); + connect(this, &DraggablePixmapItem::onPropertyChanged, + this, [combo, key](QString key2, QString value){ + if (key2 == key) { + combo->addItem(value); + combo->setCurrentText(value); + } + }); + } + +signals: + void positionChanged(Event *event); + void xChanged(int); + void yChanged(int); + void elevationChanged(int); + void spriteChanged(QPixmap pixmap); + void onPropertyChanged(QString key, QString value); + +public slots: + void set_x(const QString &text) { + event->put("x", text); + updatePosition(); + } + void set_y(const QString &text) { + event->put("y", text); + updatePosition(); + } + void set_elevation(const QString &text) { + event->put("elevation", text); + updatePosition(); + } + void set_sprite(const QString &text) { + event->put("sprite", text); + updatePixmap(); + } + void set_script(const QString &text) { + event->put("script_label", text); + } + +protected: + void mousePressEvent(QGraphicsSceneMouseEvent*); + void mouseMoveEvent(QGraphicsSceneMouseEvent*); + void mouseReleaseEvent(QGraphicsSceneMouseEvent*); + void mouseDoubleClickEvent(QGraphicsSceneMouseEvent*); +}; + +#endif // EDITOR_H diff --git a/eventpropertiesframe.ui b/src/eventpropertiesframe.ui old mode 100755 new mode 100644 similarity index 96% rename from eventpropertiesframe.ui rename to src/eventpropertiesframe.ui index 5ff1fa32..2030aa09 --- a/eventpropertiesframe.ui +++ b/src/eventpropertiesframe.ui @@ -1,286 +1,286 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>ObjectPropertiesFrame</class> - <widget class="QFrame" name="ObjectPropertiesFrame"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>284</width> - <height>146</height> - </rect> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>284</width> - <height>90</height> - </size> - </property> - <property name="windowTitle"> - <string>Frame</string> - </property> - <property name="layoutDirection"> - <enum>Qt::LeftToRight</enum> - </property> - <property name="frameShape"> - <enum>QFrame::Box</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <property name="lineWidth"> - <number>1</number> - </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <item> - <widget class="QWidget" name="widget" native="true"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <item> - <widget class="QLabel" name="label_spritePixmap"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>64</width> - <height>64</height> - </size> - </property> - <property name="frameShape"> - <enum>QFrame::Box</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Sunken</enum> - </property> - <property name="text"> - <string/> - </property> - <property name="scaledContents"> - <bool>false</bool> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - <property name="indent"> - <number>-1</number> - </property> - </widget> - </item> - <item> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QLabel" name="label_name"> - <property name="text"> - <string>Object 1</string> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <layout class="QHBoxLayout" name="x"> - <item> - <widget class="QLabel" name="label_x"> - <property name="text"> - <string>X</string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item> - <widget class="NoScrollSpinBox" name="spinBox_x"> - <property name="focusPolicy"> - <enum>Qt::StrongFocus</enum> - </property> - <property name="toolTip"> - <string><html><head/><body><p>The X coordinate of this object.</p></body></html></string> - </property> - <property name="minimum"> - <number>-32768</number> - </property> - <property name="maximum"> - <number>32767</number> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="y"> - <item> - <widget class="QLabel" name="label_y"> - <property name="text"> - <string>Y</string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item> - <widget class="NoScrollSpinBox" name="spinBox_y"> - <property name="focusPolicy"> - <enum>Qt::StrongFocus</enum> - </property> - <property name="toolTip"> - <string><html><head/><body><p>The Y coordinate of this object.</p></body></html></string> - </property> - <property name="minimum"> - <number>-32768</number> - </property> - <property name="maximum"> - <number>32767</number> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="z"> - <item> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Z</string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item> - <widget class="NoScrollSpinBox" name="spinBox_z"> - <property name="focusPolicy"> - <enum>Qt::StrongFocus</enum> - </property> - <property name="toolTip"> - <string><html><head/><body><p>The elevation of this object.</p></body></html></string> - </property> - <property name="maximum"> - <number>15</number> - </property> - </widget> - </item> - </layout> - </item> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - </layout> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QWidget" name="sprite" native="true"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <layout class="QFormLayout" name="formLayout_sprite"> - <property name="leftMargin"> - <number>9</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item row="0" column="0"> - <widget class="QLabel" name="label_sprite"> - <property name="text"> - <string>Sprite</string> - </property> - <property name="buddy"> - <cstring>comboBox_sprite</cstring> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="NoScrollComboBox" name="comboBox_sprite"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="focusPolicy"> - <enum>Qt::StrongFocus</enum> - </property> - <property name="toolTip"> - <string><html><head/><body><p>The sprite graphics to use for this object.</p></body></html></string> - </property> - <property name="editable"> - <bool>true</bool> - </property> - <property name="currentText"> - <string/> - </property> - <property name="maxVisibleItems"> - <number>25</number> - </property> - <property name="sizeAdjustPolicy"> - <enum>QComboBox::AdjustToContentsOnFirstShow</enum> - </property> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - <customwidgets> - <customwidget> - <class>NoScrollComboBox</class> - <extends>QComboBox</extends> - <header>noscrollcombobox.h</header> - </customwidget> - <customwidget> - <class>NoScrollSpinBox</class> - <extends>QSpinBox</extends> - <header>noscrollspinbox.h</header> - </customwidget> - </customwidgets> - <tabstops> - <tabstop>spinBox_x</tabstop> - <tabstop>spinBox_y</tabstop> - <tabstop>spinBox_z</tabstop> - <tabstop>comboBox_sprite</tabstop> - </tabstops> - <resources/> - <connections/> -</ui> +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ObjectPropertiesFrame</class> + <widget class="QFrame" name="ObjectPropertiesFrame"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>284</width> + <height>146</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>284</width> + <height>90</height> + </size> + </property> + <property name="windowTitle"> + <string>Frame</string> + </property> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="frameShape"> + <enum>QFrame::Box</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="lineWidth"> + <number>1</number> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QWidget" name="widget" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLabel" name="label_spritePixmap"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>64</width> + <height>64</height> + </size> + </property> + <property name="frameShape"> + <enum>QFrame::Box</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Sunken</enum> + </property> + <property name="text"> + <string/> + </property> + <property name="scaledContents"> + <bool>false</bool> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="indent"> + <number>-1</number> + </property> + </widget> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="label_name"> + <property name="text"> + <string>Object 1</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <layout class="QHBoxLayout" name="x"> + <item> + <widget class="QLabel" name="label_x"> + <property name="text"> + <string>X</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item> + <widget class="NoScrollSpinBox" name="spinBox_x"> + <property name="focusPolicy"> + <enum>Qt::StrongFocus</enum> + </property> + <property name="toolTip"> + <string><html><head/><body><p>The X coordinate of this object.</p></body></html></string> + </property> + <property name="minimum"> + <number>-32768</number> + </property> + <property name="maximum"> + <number>32767</number> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="y"> + <item> + <widget class="QLabel" name="label_y"> + <property name="text"> + <string>Y</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item> + <widget class="NoScrollSpinBox" name="spinBox_y"> + <property name="focusPolicy"> + <enum>Qt::StrongFocus</enum> + </property> + <property name="toolTip"> + <string><html><head/><body><p>The Y coordinate of this object.</p></body></html></string> + </property> + <property name="minimum"> + <number>-32768</number> + </property> + <property name="maximum"> + <number>32767</number> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="z"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Z</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item> + <widget class="NoScrollSpinBox" name="spinBox_z"> + <property name="focusPolicy"> + <enum>Qt::StrongFocus</enum> + </property> + <property name="toolTip"> + <string><html><head/><body><p>The elevation of this object.</p></body></html></string> + </property> + <property name="maximum"> + <number>15</number> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QWidget" name="sprite" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QFormLayout" name="formLayout_sprite"> + <property name="leftMargin"> + <number>9</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label_sprite"> + <property name="text"> + <string>Sprite</string> + </property> + <property name="buddy"> + <cstring>comboBox_sprite</cstring> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="NoScrollComboBox" name="comboBox_sprite"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="focusPolicy"> + <enum>Qt::StrongFocus</enum> + </property> + <property name="toolTip"> + <string><html><head/><body><p>The sprite graphics to use for this object.</p></body></html></string> + </property> + <property name="editable"> + <bool>true</bool> + </property> + <property name="currentText"> + <string/> + </property> + <property name="maxVisibleItems"> + <number>25</number> + </property> + <property name="sizeAdjustPolicy"> + <enum>QComboBox::AdjustToContentsOnFirstShow</enum> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>NoScrollComboBox</class> + <extends>QComboBox</extends> + <header>noscrollcombobox.h</header> + </customwidget> + <customwidget> + <class>NoScrollSpinBox</class> + <extends>QSpinBox</extends> + <header>noscrollspinbox.h</header> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>spinBox_x</tabstop> + <tabstop>spinBox_y</tabstop> + <tabstop>spinBox_z</tabstop> + <tabstop>comboBox_sprite</tabstop> + </tabstops> + <resources/> + <connections/> +</ui> diff --git a/main.cpp b/src/main.cpp old mode 100755 new mode 100644 similarity index 94% rename from main.cpp rename to src/main.cpp index 94e1c1b8..ab638672 --- a/main.cpp +++ b/src/main.cpp @@ -1,12 +1,12 @@ -#include "mainwindow.h" -#include <QApplication> - -int main(int argc, char *argv[]) -{ - QApplication a(argc, argv); - a.setStyle("fusion"); - MainWindow w; - w.show(); - - return a.exec(); -} +#include "mainwindow.h" +#include <QApplication> + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + a.setStyle("fusion"); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/mainwindow.cpp b/src/mainwindow.cpp old mode 100755 new mode 100644 similarity index 97% rename from mainwindow.cpp rename to src/mainwindow.cpp index bf626c6a..53974d30 --- a/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1,1198 +1,1198 @@ -#include "mainwindow.h" -#include "ui_mainwindow.h" -#include "project.h" -#include "editor.h" -#include "eventpropertiesframe.h" -#include "ui_objectpropertiesframe.h" -#include "bordermetatilespixmapitem.h" -#include "currentselectedmetatilespixmapitem.h" - -#include <QDebug> -#include <QFileDialog> -#include <QStandardItemModel> -#include <QShortcut> -#include <QSettings> -#include <QSpinBox> -#include <QTextEdit> -#include <QSpacerItem> -#include <QFont> -#include <QScrollBar> -#include <QPushButton> -#include <QMessageBox> -#include <QDialogButtonBox> -#include <QScroller> -#include <math.h> -#include <QProcess> -#include <QSysInfo> -#include <QDesktopServices> - -MainWindow::MainWindow(QWidget *parent) : - QMainWindow(parent), - ui(new Ui::MainWindow) -{ - QCoreApplication::setOrganizationName("pret"); - QCoreApplication::setApplicationName("porymap"); - QApplication::setWindowIcon(QIcon(":/icons/porymap-icon-1.ico")); - - ui->setupUi(this); - this->initExtraSignals(); - this->initExtraShortcuts(); - this->initEditor(); - this->openRecentProject(); - - on_toolButton_Paint_clicked(); -} - -MainWindow::~MainWindow() -{ - delete ui; -} - -void MainWindow::initExtraShortcuts() { - new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Z), this, SLOT(redo())); -} - -void MainWindow::initExtraSignals() { - connect(ui->newEventToolButton, SIGNAL(newEventAdded(QString)), this, SLOT(addNewEvent(QString))); -} - -void MainWindow::initEditor() { - this->editor = new Editor(ui); - connect(this->editor, SIGNAL(objectsChanged()), this, SLOT(updateSelectedObjects())); - connect(this->editor, SIGNAL(selectedObjectsChanged()), this, SLOT(updateSelectedObjects())); - connect(this->editor, SIGNAL(loadMapRequested(QString, QString)), this, SLOT(onLoadMapRequested(QString, QString))); - connect(this->editor, SIGNAL(tilesetChanged(QString)), this, SLOT(onTilesetChanged(QString))); - connect(this->editor, SIGNAL(warpEventDoubleClicked(QString,QString)), this, SLOT(openWarpMap(QString,QString))); - connect(this->editor, SIGNAL(currentMetatilesSelectionChanged()), this, SLOT(currentMetatilesSelectionChanged())); - - this->loadUserSettings(); -} - -void MainWindow::loadUserSettings() { - QSettings settings; - - bool betterCursors = settings.contains("cursor_mode") && settings.value("cursor_mode") != "0"; - ui->actionBetter_Cursors->setChecked(betterCursors); - this->editor->settings->betterCursors = betterCursors; -} - -void MainWindow::openRecentProject() { - QSettings settings; - QString key = "recent_projects"; - if (settings.contains(key)) { - QString default_dir = settings.value(key).toStringList().last(); - if (!default_dir.isNull()) { - qDebug() << QString("default_dir: '%1'").arg(default_dir); - openProject(default_dir); - } - } -} - -void MainWindow::openProject(QString dir) { - if (dir.isNull()) { - return; - } - - this->statusBar()->showMessage(QString("Opening project %1").arg(dir)); - - bool already_open = ( - (editor && editor != nullptr) - && (editor->project && editor->project != nullptr) - && (editor->project->root == dir) - ); - if (!already_open) { - editor->project = new Project; - editor->project->root = dir; - setWindowTitle(editor->project->getProjectTitle() + " - porymap"); - loadDataStructures(); - populateMapList(); - setMap(getDefaultMap()); - } else { - setWindowTitle(editor->project->getProjectTitle() + " - porymap"); - loadDataStructures(); - populateMapList(); - } - - this->statusBar()->showMessage(QString("Opened project %1").arg(dir)); -} - -QString MainWindow::getDefaultMap() { - if (editor && editor->project) { - QList<QStringList> names = editor->project->groupedMapNames; - if (!names.isEmpty()) { - QSettings settings; - QString key = "project:" + editor->project->root; - if (settings.contains(key)) { - QMap<QString, QVariant> qmap = settings.value(key).toMap(); - if (qmap.contains("recent_map")) { - QString map_name = qmap.value("recent_map").toString(); - for (int i = 0; i < names.length(); i++) { - if (names.value(i).contains(map_name)) { - return map_name; - } - } - } - } - // Failing that, just get the first map in the list. - for (int i = 0; i < names.length(); i++) { - QStringList list = names.value(i); - if (list.length()) { - return list.value(0); - } - } - } - } - return QString(); -} - -QString MainWindow::getExistingDirectory(QString dir) { - return QFileDialog::getExistingDirectory(this, "Open Directory", dir, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); -} - -void MainWindow::on_action_Open_Project_triggered() -{ - QSettings settings; - QString key = "recent_projects"; - QString recent = "."; - if (settings.contains(key)) { - recent = settings.value(key).toStringList().last(); - } - QString dir = getExistingDirectory(recent); - if (!dir.isEmpty()) { - QStringList recents; - if (settings.contains(key)) { - recents = settings.value(key).toStringList(); - } - recents.removeAll(dir); - recents.append(dir); - settings.setValue(key, recents); - - openProject(dir); - } -} - -void MainWindow::setMap(QString map_name) { - qDebug() << QString("setMap(%1)").arg(map_name); - if (map_name.isNull()) { - return; - } - editor->setMap(map_name); - redrawMapScene(); - displayMapProperties(); - - setWindowTitle(map_name + " - " + editor->project->getProjectTitle() + " - porymap"); - - connect(editor->map, SIGNAL(mapChanged(Map*)), this, SLOT(onMapChanged(Map *))); - connect(editor->map, SIGNAL(mapNeedsRedrawing()), this, SLOT(onMapNeedsRedrawing())); - - setRecentMap(map_name); - updateMapList(); -} - -void MainWindow::redrawMapScene() -{ - editor->displayMap(); - on_tabWidget_currentChanged(ui->tabWidget->currentIndex()); - - ui->graphicsView_Map->setScene(editor->scene); - ui->graphicsView_Map->setSceneRect(editor->scene->sceneRect()); - ui->graphicsView_Map->setFixedSize(static_cast<int>(editor->scene->width()) + 2, static_cast<int>(editor->scene->height()) + 2); - - ui->graphicsView_Objects_Map->setScene(editor->scene); - ui->graphicsView_Objects_Map->setSceneRect(editor->scene->sceneRect()); - ui->graphicsView_Objects_Map->setFixedSize(static_cast<int>(editor->scene->width()) + 2, static_cast<int>(editor->scene->height()) + 2); - ui->graphicsView_Objects_Map->editor = editor; - - ui->graphicsView_Connections->setScene(editor->scene); - ui->graphicsView_Connections->setSceneRect(editor->scene->sceneRect()); - ui->graphicsView_Connections->setFixedSize(static_cast<int>(editor->scene->width()) + 2, static_cast<int>(editor->scene->height()) + 2); - - ui->graphicsView_Metatiles->setScene(editor->scene_metatiles); - //ui->graphicsView_Metatiles->setSceneRect(editor->scene_metatiles->sceneRect()); - 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); - - ui->graphicsView_currentMetatileSelection->setScene(editor->scene_current_metatile_selection); - ui->graphicsView_currentMetatileSelection->setFixedSize(editor->scene_current_metatile_selection_item->pixmap().width() + 2, editor->scene_current_metatile_selection_item->pixmap().height() + 2); - - ui->graphicsView_Collision->setScene(editor->scene_collision_metatiles); - //ui->graphicsView_Collision->setSceneRect(editor->scene_collision_metatiles->sceneRect()); - ui->graphicsView_Collision->setFixedSize(editor->movement_permissions_selector_item->pixmap().width() + 2, editor->movement_permissions_selector_item->pixmap().height() + 2); -} - -void MainWindow::openWarpMap(QString map_name, QString warp_num) { - // Ensure valid destination map name. - if (!editor->project->mapNames->contains(map_name)) { - qDebug() << QString("Invalid warp destination map name '%1'").arg(map_name); - return; - } - - // Ensure valid destination warp number. - bool ok; - int warpNum = warp_num.toInt(&ok, 0); - if (!ok) { - qDebug() << QString("Invalid warp number '%1' for destination map '%2'").arg(warp_num).arg(map_name); - return; - } - - // Open the destination map, and select the target warp event. - setMap(map_name); - QList<Event*> warp_events = editor->map->events["warp_event_group"]; - if (warp_events.length() > warpNum) { - Event *warp_event = warp_events.at(warpNum); - QList<DraggablePixmapItem *> *all_events = editor->getObjects(); - for (DraggablePixmapItem *item : *all_events) { - if (item->event == warp_event) { - editor->selected_events->clear(); - editor->selected_events->append(item); - editor->updateSelectedEvents(); - } - } - - delete all_events; - } -} - -void MainWindow::setRecentMap(QString map_name) { - QSettings settings; - QString key = "project:" + editor->project->root; - QMap<QString, QVariant> qmap; - if (settings.contains(key)) { - qmap = settings.value(key).toMap(); - } - qmap.insert("recent_map", map_name); - settings.setValue(key, qmap); -} - -void MainWindow::displayMapProperties() { - ui->comboBox_Song->clear(); - ui->comboBox_Location->clear(); - ui->checkBox_Visibility->setChecked(false); - ui->comboBox_Weather->clear(); - ui->comboBox_Type->clear(); - ui->comboBox_BattleScene->clear(); - ui->comboBox_PrimaryTileset->clear(); - ui->comboBox_SecondaryTileset->clear(); - ui->checkBox_ShowLocation->setChecked(false); - if (!editor || !editor->map || !editor->project) { - ui->frame_3->setEnabled(false); - return; - } - ui->frame_3->setEnabled(true); - Map *map = editor->map; - Project *project = editor->project; - - QStringList songs = project->getSongNames(); - ui->comboBox_Song->addItems(songs); - ui->comboBox_Song->setCurrentText(map->song); - - ui->comboBox_Location->addItems(*project->regionMapSections); - ui->comboBox_Location->setCurrentText(map->location); - - QMap<QString, QStringList> tilesets = project->getTilesets(); - ui->comboBox_PrimaryTileset->addItems(tilesets.value("primary")); - ui->comboBox_PrimaryTileset->setCurrentText(map->layout->tileset_primary_label); - ui->comboBox_SecondaryTileset->addItems(tilesets.value("secondary")); - ui->comboBox_SecondaryTileset->setCurrentText(map->layout->tileset_secondary_label); - - ui->checkBox_Visibility->setChecked(map->requiresFlash.toInt() > 0 || map->requiresFlash == "TRUE"); - - ui->comboBox_Weather->addItems(*project->weatherNames); - ui->comboBox_Weather->setCurrentText(map->weather); - - ui->comboBox_Type->addItems(*project->mapTypes); - ui->comboBox_Type->setCurrentText(map->type); - - ui->comboBox_BattleScene->addItems(*project->mapBattleScenes); - ui->comboBox_BattleScene->setCurrentText(map->battle_scene); - - ui->checkBox_ShowLocation->setChecked(map->show_location.toInt() > 0 || map->show_location == "TRUE"); -} - -void MainWindow::on_comboBox_Song_activated(const QString &song) -{ - if (editor && editor->map) { - editor->map->song = song; - } -} - -void MainWindow::on_comboBox_Location_activated(const QString &location) -{ - if (editor && editor->map) { - editor->map->location = location; - } -} - -void MainWindow::on_comboBox_Visibility_activated(const QString &requiresFlash) -{ - if (editor && editor->map) { - editor->map->requiresFlash = requiresFlash; - } -} - -void MainWindow::on_comboBox_Weather_activated(const QString &weather) -{ - if (editor && editor->map) { - editor->map->weather = weather; - } -} - -void MainWindow::on_comboBox_Type_activated(const QString &type) -{ - if (editor && editor->map) { - editor->map->type = type; - } -} - -void MainWindow::on_comboBox_BattleScene_activated(const QString &battle_scene) -{ - if (editor && editor->map) { - editor->map->battle_scene = battle_scene; - } -} - -void MainWindow::on_checkBox_Visibility_clicked(bool checked) -{ - if (editor && editor->map) { - if (checked) { - editor->map->requiresFlash = "TRUE"; - } else { - editor->map->requiresFlash = "FALSE"; - } - } -} - -void MainWindow::on_checkBox_ShowLocation_clicked(bool checked) -{ - if (editor && editor->map) { - if (checked) { - editor->map->show_location = "TRUE"; - } else { - editor->map->show_location = "FALSE"; - } - } -} - -void MainWindow::loadDataStructures() { - Project *project = editor->project; - project->readMapLayoutsTable(); - project->readAllMapLayouts(); - project->readRegionMapSections(); - project->readItemNames(); - project->readFlagNames(); - project->readVarNames(); - project->readMovementTypes(); - project->readMapTypes(); - project->readMapBattleScenes(); - project->readWeatherNames(); - project->readCoordEventWeatherNames(); - project->readSecretBaseIds(); - project->readBgEventFacingDirections(); - project->readMapsWithConnections(); - project->readTilesetProperties(); -} - -void MainWindow::populateMapList() { - Project *project = editor->project; - - QIcon mapFolderIcon; - mapFolderIcon.addFile(QStringLiteral(":/icons/folder_closed_map.ico"), QSize(), QIcon::Normal, QIcon::Off); - mapFolderIcon.addFile(QStringLiteral(":/icons/folder_map.ico"), QSize(), QIcon::Normal, QIcon::On); - - QIcon folderIcon; - folderIcon.addFile(QStringLiteral(":/icons/folder_closed.ico"), QSize(), QIcon::Normal, QIcon::Off); - - mapIcon = new QIcon; - mapIcon->addFile(QStringLiteral(":/icons/map.ico"), QSize(), QIcon::Normal, QIcon::Off); - mapIcon->addFile(QStringLiteral(":/icons/image.ico"), QSize(), QIcon::Normal, QIcon::On); - - mapListModel = new QStandardItemModel; - mapGroupsModel = new QList<QStandardItem*>; - - QStandardItem *entry = new QStandardItem; - entry->setText(project->getProjectTitle()); - entry->setIcon(folderIcon); - entry->setEditable(false); - mapListModel->appendRow(entry); - - QStandardItem *maps = new QStandardItem; - maps->setText("maps"); - maps->setIcon(folderIcon); - maps->setEditable(false); - entry->appendRow(maps); - - project->readMapGroups(); - for (int i = 0; i < project->groupNames->length(); i++) { - QString group_name = project->groupNames->value(i); - QStandardItem *group = new QStandardItem; - group->setText(group_name); - group->setIcon(mapFolderIcon); - group->setEditable(false); - group->setData(group_name, Qt::UserRole); - group->setData("map_group", MapListUserRoles::TypeRole); - group->setData(i, MapListUserRoles::GroupRole); - maps->appendRow(group); - mapGroupsModel->append(group); - QStringList names = project->groupedMapNames.value(i); - for (int j = 0; j < names.length(); j++) { - QString map_name = names.value(j); - QStandardItem *map = createMapItem(map_name, i, j); - group->appendRow(map); - } - } - - // Right-clicking on items in the map list tree view brings up a context menu. - ui->mapList->setContextMenuPolicy(Qt::CustomContextMenu); - connect(ui->mapList, SIGNAL(customContextMenuRequested(const QPoint &)), - this, SLOT(onOpenMapListContextMenu(const QPoint &))); - - ui->mapList->setModel(mapListModel); - ui->mapList->setUpdatesEnabled(true); - ui->mapList->expandToDepth(2); - ui->mapList->repaint(); -} - -QStandardItem* MainWindow::createMapItem(QString mapName, int groupNum, int inGroupNum) { - QStandardItem *map = new QStandardItem; - map->setText(QString("[%1.%2] ").arg(groupNum).arg(inGroupNum, 2, 10, QLatin1Char('0')) + mapName); - map->setIcon(*mapIcon); - map->setEditable(false); - map->setData(mapName, Qt::UserRole); - map->setData("map_name", MapListUserRoles::TypeRole); - return map; -} - -void MainWindow::onOpenMapListContextMenu(const QPoint &point) -{ - QModelIndex index = ui->mapList->indexAt(point); - if (!index.isValid()) { - return; - } - - QStandardItem *selectedItem = mapListModel->itemFromIndex(index); - QVariant itemType = selectedItem->data(MapListUserRoles::TypeRole); - if (!itemType.isValid()) { - return; - } - - // Build custom context menu depending on which type of item was selected (map group, map name, etc.) - if (itemType == "map_group") { - QString groupName = selectedItem->data(Qt::UserRole).toString(); - int groupNum = selectedItem->data(MapListUserRoles::GroupRole).toInt(); - QMenu* menu = new QMenu(); - QActionGroup* actions = new QActionGroup(menu); - actions->addAction(menu->addAction("Add New Map to Group"))->setData(groupNum); - connect(actions, SIGNAL(triggered(QAction*)), this, SLOT(onAddNewMapToGroupClick(QAction*))); - menu->exec(QCursor::pos()); - } -} - -void MainWindow::onAddNewMapToGroupClick(QAction* triggeredAction) -{ - int groupNum = triggeredAction->data().toInt(); - QStandardItem* groupItem = mapGroupsModel->at(groupNum); - - QString newMapName = editor->project->getNewMapName(); - Map* newMap = editor->project->addNewMapToGroup(newMapName, groupNum); - editor->project->saveMap(newMap); - editor->project->saveAllDataStructures(); - - int numMapsInGroup = groupItem->rowCount(); - QStandardItem *newMapItem = createMapItem(newMapName, groupNum, numMapsInGroup); - groupItem->appendRow(newMapItem); - - setMap(newMapName); -} - -void MainWindow::onTilesetChanged(QString mapName) -{ - setMap(mapName); -} - -void MainWindow::currentMetatilesSelectionChanged() -{ - ui->graphicsView_currentMetatileSelection->setFixedSize(editor->scene_current_metatile_selection_item->pixmap().width() + 2, editor->scene_current_metatile_selection_item->pixmap().height() + 2); - ui->graphicsView_currentMetatileSelection->setSceneRect(0, 0, editor->scene_current_metatile_selection_item->pixmap().width(), editor->scene_current_metatile_selection_item->pixmap().height()); -} - -void MainWindow::on_mapList_activated(const QModelIndex &index) -{ - QVariant data = index.data(Qt::UserRole); - if (!data.isNull()) { - setMap(data.toString()); - } -} - -void MainWindow::markAllEdited(QAbstractItemModel *model) { - QList<QModelIndex> list; - list.append(QModelIndex()); - while (list.length()) { - QModelIndex parent = list.takeFirst(); - for (int i = 0; i < model->rowCount(parent); i++) { - QModelIndex index = model->index(i, 0, parent); - if (model->hasChildren(index)) { - list.append(index); - } - markEdited(index); - } - } -} - -void MainWindow::markEdited(QModelIndex index) { - QVariant data = index.data(Qt::UserRole); - if (!data.isNull()) { - QString map_name = data.toString(); - if (editor->project) { - if (editor->project->map_cache->contains(map_name)) { - // Just mark anything that's been opened for now. - // TODO if (project->getMap()->saved) - //ui->mapList->setExpanded(index, true); - ui->mapList->setExpanded(index, editor->project->map_cache->value(map_name)->hasUnsavedChanges()); - } - } - } -} - -void MainWindow::updateMapList() { - QAbstractItemModel *model = ui->mapList->model(); - markAllEdited(model); -} - -void MainWindow::on_action_Save_Project_triggered() -{ - editor->saveProject(); - updateMapList(); -} - -void MainWindow::undo() { - editor->undo(); -} - -void MainWindow::redo() { - editor->redo(); -} - -// Open current map scripts in system default editor for .inc files -void MainWindow::openInTextEditor() { - QString path = QDir::cleanPath("file://" + editor->project->root + QDir::separator() + "data/maps/" + editor->map->name + "/scripts.inc"); - QDesktopServices::openUrl(QUrl(path)); -} - -void MainWindow::on_action_Save_triggered() { - editor->save(); - updateMapList(); -} - -void MainWindow::on_tabWidget_2_currentChanged(int index) -{ - if (index == 0) { - editor->setEditingMap(); - } else if (index == 1) { - editor->setEditingCollision(); - } -} - -void MainWindow::on_action_Exit_triggered() -{ - QApplication::quit(); -} - -void MainWindow::on_tabWidget_currentChanged(int index) -{ - if (index == 0) { - on_tabWidget_2_currentChanged(ui->tabWidget_2->currentIndex()); - } else if (index == 1) { - editor->setEditingObjects(); - } else if (index == 3) { - editor->setEditingConnections(); - } -} - -void MainWindow::on_actionUndo_triggered() -{ - undo(); -} - -void MainWindow::on_actionRedo_triggered() -{ - redo(); -} - -void MainWindow::on_actionZoom_In_triggered() { - scaleMapView(1); -} - -void MainWindow::on_actionZoom_Out_triggered() { - scaleMapView(-1); -} - -void MainWindow::on_actionBetter_Cursors_triggered() { - QSettings settings; - settings.setValue("cursor_mode", QString::number(ui->actionBetter_Cursors->isChecked())); - this->editor->settings->betterCursors = ui->actionBetter_Cursors->isChecked(); -} - -void MainWindow::on_actionPencil_triggered() -{ - on_toolButton_Paint_clicked(); -} - -void MainWindow::on_actionPointer_triggered() -{ - on_toolButton_Select_clicked(); -} - -void MainWindow::on_actionFlood_Fill_triggered() -{ - on_toolButton_Fill_clicked(); -} - -void MainWindow::on_actionEyedropper_triggered() -{ - on_toolButton_Dropper_clicked(); -} - -void MainWindow::on_actionMove_triggered() -{ - on_toolButton_Move_clicked(); -} - -void MainWindow::on_actionMap_Shift_triggered() -{ - on_toolButton_Shift_clicked(); -} - -void MainWindow::scaleMapView(int s) { - editor->map->scale_exp += s; - - double base = editor->map->scale_base; - double exp = editor->map->scale_exp; - double sfactor = pow(base,s); - - ui->graphicsView_Map->scale(sfactor,sfactor); - ui->graphicsView_Objects_Map->scale(sfactor,sfactor); - - int width = static_cast<int>((editor->scene->width() + 2) * pow(base,exp)); - int height = static_cast<int>((editor->scene->height() + 2) * pow(base,exp)); - ui->graphicsView_Map->setFixedSize(width, height); - ui->graphicsView_Objects_Map->setFixedSize(width, height); -} - -void MainWindow::addNewEvent(QString event_type) -{ - if (editor) { - DraggablePixmapItem *object = editor->addNewEvent(event_type); - if (object) { - editor->selectMapEvent(object, false); - } - updateSelectedObjects(); - } -} - -// Should probably just pass layout and let the editor work it out -void MainWindow::updateSelectedObjects() { - QList<DraggablePixmapItem *> *all_events = editor->getObjects(); - QList<DraggablePixmapItem *> *events = nullptr; - - if (editor->selected_events && editor->selected_events->length()) { - events = editor->selected_events; - } else { - events = new QList<DraggablePixmapItem*>; - if (all_events && all_events->length()) { - DraggablePixmapItem *selectedEvent = all_events->first(); - editor->selected_events->append(selectedEvent); - editor->redrawObject(selectedEvent); - events->append(selectedEvent); - } - } - - QMap<QString, int> event_obj_gfx_constants = editor->project->getEventObjGfxConstants(); - - QList<EventPropertiesFrame *> frames; - - for (DraggablePixmapItem *item : *events) { - EventPropertiesFrame *frame = new EventPropertiesFrame; -// frame->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - - QSpinBox *x = frame->ui->spinBox_x; - QSpinBox *y = frame->ui->spinBox_y; - QSpinBox *z = frame->ui->spinBox_z; - - x->setValue(item->event->x()); - connect(x, SIGNAL(valueChanged(QString)), item, SLOT(set_x(QString))); - connect(item, SIGNAL(xChanged(int)), x, SLOT(setValue(int))); - - y->setValue(item->event->y()); - connect(y, SIGNAL(valueChanged(QString)), item, SLOT(set_y(QString))); - connect(item, SIGNAL(yChanged(int)), y, SLOT(setValue(int))); - - z->setValue(item->event->elevation()); - connect(z, SIGNAL(valueChanged(QString)), item, SLOT(set_elevation(QString))); - connect(item, SIGNAL(elevationChanged(int)), z, SLOT(setValue(int))); - - QFont font; - font.setCapitalization(QFont::Capitalize); - frame->ui->label_name->setFont(font); - QString event_type = item->event->get("event_type"); - QString event_group_type = item->event->get("event_group_type"); - QString map_name = item->event->get("map_name"); - int event_offs; - if (event_type == "event_warp") { event_offs = 0; } - else { event_offs = 1; } - frame->ui->label_name->setText( - QString("%1: %2 %3") - .arg(editor->project->getMap(map_name)->events.value(event_group_type).indexOf(item->event) + event_offs) - .arg(map_name) - .arg(event_type) - ); - - frame->ui->label_spritePixmap->setPixmap(item->event->pixmap); - connect(item, SIGNAL(spriteChanged(QPixmap)), frame->ui->label_spritePixmap, SLOT(setPixmap(QPixmap))); - - frame->ui->sprite->setVisible(false); - - QMap<QString, QString> field_labels; - field_labels["script_label"] = "Script"; - field_labels["event_flag"] = "Event Flag"; - field_labels["movement_type"] = "Movement"; - field_labels["radius_x"] = "Movement Radius X"; - field_labels["radius_y"] = "Movement Radius Y"; - field_labels["is_trainer"] = "Trainer"; - field_labels["sight_radius_tree_id"] = "Sight Radius / Berry Tree ID"; - field_labels["destination_warp"] = "Destination Warp"; - field_labels["destination_map_name"] = "Destination Map"; - field_labels["script_var"] = "Var"; - field_labels["script_var_value"] = "Var Value"; - field_labels["player_facing_direction"] = "Player Facing Direction"; - field_labels["item"] = "Item"; - field_labels["item_unknown5"] = "Unknown 5"; - field_labels["item_unknown6"] = "Unknown 6"; - field_labels["weather"] = "Weather"; - field_labels["flag"] = "Flag"; - field_labels["secret_base_id"] = "Secret Base Id"; - - QStringList fields; - - if (event_type == EventType::Object) { - - frame->ui->sprite->setVisible(true); - frame->ui->comboBox_sprite->addItems(event_obj_gfx_constants.keys()); - frame->ui->comboBox_sprite->setCurrentText(item->event->get("sprite")); - connect(frame->ui->comboBox_sprite, SIGNAL(activated(QString)), item, SLOT(set_sprite(QString))); - - /* - frame->ui->script->setVisible(true); - frame->ui->comboBox_script->addItem(item->event->get("script_label")); - frame->ui->comboBox_script->setCurrentText(item->event->get("script_label")); - //item->bind(frame->ui->comboBox_script, "script_label"); - connect(frame->ui->comboBox_script, SIGNAL(activated(QString)), item, SLOT(set_script(QString))); - //connect(frame->ui->comboBox_script, static_cast<void (QComboBox::*)(const QString&)>(&QComboBox::activated), item, [item](QString script_label){ item->event->put("script_label", script_label); }); - //connect(item, SIGNAL(scriptChanged(QString)), frame->ui->comboBox_script, SLOT(setValue(QString))); - */ - - fields << "movement_type"; - fields << "radius_x"; - fields << "radius_y"; - fields << "script_label"; - fields << "event_flag"; - fields << "is_trainer"; - fields << "sight_radius_tree_id"; - } - else if (event_type == EventType::Warp) { - fields << "destination_map_name"; - fields << "destination_warp"; - } - else if (event_type == EventType::CoordScript) { - fields << "script_label"; - fields << "script_var"; - fields << "script_var_value"; - } - else if (event_type == EventType::CoordWeather) { - fields << "weather"; - } - else if (event_type == EventType::Sign) { - fields << "player_facing_direction"; - fields << "script_label"; - } - else if (event_type == EventType::HiddenItem) { - fields << "item"; - fields << "flag"; - } - else if (event_type == EventType::SecretBase) { - fields << "secret_base_id"; - } - - for (QString key : fields) { - QString value = item->event->get(key); - QWidget *widget = new QWidget(frame); - QFormLayout *fl = new QFormLayout(widget); - fl->setContentsMargins(9, 0, 9, 0); - - // is_trainer is the only non-combobox item. - if (key == "is_trainer") { - QCheckBox *checkbox = new QCheckBox(widget); - checkbox->setEnabled(true); - checkbox->setChecked(value.toInt() != 0 && value != "FALSE"); - checkbox->setToolTip("Whether or not this object is trainer."); - fl->addRow(new QLabel(field_labels[key], widget), checkbox); - widget->setLayout(fl); - frame->layout()->addWidget(widget); - connect(checkbox, &QCheckBox::stateChanged, [=](int state) { - QString isTrainer = state == Qt::Checked ? "TRUE" : "FALSE"; - item->event->put("is_trainer", isTrainer); - }); - continue; - } - - NoScrollComboBox *combo = new NoScrollComboBox(widget); - combo->setEditable(true); - - if (key == "destination_map_name") { - if (!editor->project->mapNames->contains(value)) { - combo->addItem(value); - } - combo->addItems(*editor->project->mapNames); - combo->setToolTip("The destination map name of the warp."); - } else if (key == "destination_warp") { - combo->setToolTip("The warp id on the destination map."); - } else if (key == "item") { - if (!editor->project->itemNames->contains(value)) { - combo->addItem(value); - } - combo->addItems(*editor->project->itemNames); - } else if (key == "flag" || key == "event_flag") { - if (!editor->project->flagNames->contains(value)) { - combo->addItem(value); - } - combo->addItems(*editor->project->flagNames); - if (key == "flag") - combo->setToolTip("The flag which is set when the hidden item is picked up."); - else if (key == "event_flag") - combo->setToolTip("The flag which hides the object when set."); - } else if (key == "script_var") { - if (!editor->project->varNames->contains(value)) { - combo->addItem(value); - } - combo->addItems(*editor->project->varNames); - combo->setToolTip("The variable by which the script is triggered. The script is triggered when this variable's value matches 'Var Value'."); - } else if (key == "script_var_value") { - combo->setToolTip("The variable's value which triggers the script."); - } else if (key == "movement_type") { - if (!editor->project->movementTypes->contains(value)) { - combo->addItem(value); - } - combo->addItems(*editor->project->movementTypes); - combo->setToolTip("The object's natural movement behavior when the player is not interacting with it."); - } else if (key == "weather") { - if (!editor->project->coordEventWeatherNames->contains(value)) { - combo->addItem(value); - } - combo->addItems(*editor->project->coordEventWeatherNames); - combo->setToolTip("The weather that starts when the player steps on this spot."); - } else if (key == "secret_base_id") { - if (!editor->project->secretBaseIds->contains(value)) { - combo->addItem(value); - } - combo->addItems(*editor->project->secretBaseIds); - combo->setToolTip("The secret base id which is inside this secret base entrance. Secret base ids are meant to be unique to each and every secret base entrance."); - } else if (key == "player_facing_direction") { - if (!editor->project->bgEventFacingDirections->contains(value)) { - combo->addItem(value); - } - combo->addItems(*editor->project->bgEventFacingDirections); - combo->setToolTip("The direction which the player must be facing to be able to interact with this event."); - } else if (key == "radius_x") { - combo->setToolTip("The maximum number of metatiles this object is allowed to move left or right during its normal movement behavior actions."); - } else if (key == "radius_y") { - combo->setToolTip("The maximum number of metatiles this object is allowed to move up or down during its normal movement behavior actions."); - } else if (key == "script_label") { - combo->setToolTip("The script which is executed with this event."); - } else if (key == "sight_radius_tree_id") { - combo->setToolTip("The maximum sight range of a trainer, OR the unique id of the berry tree."); - } else { - combo->addItem(value); - } - combo->setCurrentText(value); - - fl->addRow(new QLabel(field_labels[key], widget), combo); - widget->setLayout(fl); - frame->layout()->addWidget(widget); - - item->bind(combo, key); - } - - frames.append(frame); - - } - - //int scroll = ui->scrollArea_4->verticalScrollBar()->value(); - - QWidget *target = ui->scrollAreaWidgetContents; - - if (target->children().length()) { - qDeleteAll(target->children()); - } - - QVBoxLayout *layout = new QVBoxLayout(target); - target->setLayout(layout); - ui->scrollArea_4->setWidgetResizable(true); - ui->scrollArea_4->setWidget(target); - - for (EventPropertiesFrame *frame : frames) { - layout->addWidget(frame); - } - - layout->addStretch(1); - - // doesn't work - //QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); - //ui->scrollArea_4->ensureVisible(0, scroll); -} - -void MainWindow::on_toolButton_deleteObject_clicked() -{ - if (editor && editor->selected_events) { - if (editor->selected_events->length()) { - for (DraggablePixmapItem *item : *editor->selected_events) { - if (item->event->get("event_type") != EventType::HealLocation) { - editor->deleteEvent(item->event); - if (editor->scene->items().contains(item)) { - editor->scene->removeItem(item); - } - editor->selected_events->removeOne(item); - } - else { // don't allow deletion of heal locations - qDebug() << "Cannot delete event of type " << item->event->get("event_type"); - } - } - updateSelectedObjects(); - } - } -} - -void MainWindow::on_toolButton_Open_Scripts_clicked() -{ - openInTextEditor(); -} - -void MainWindow::on_toolButton_Paint_clicked() -{ - editor->map_edit_mode = "paint"; - editor->settings->mapCursor = QCursor(QPixmap(":/icons/pencil_cursor.ico"), 10, 10); - - ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); - ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - QScroller::ungrabGesture(ui->scrollArea); - - checkToolButtons(); -} - -void MainWindow::on_toolButton_Select_clicked() -{ - editor->map_edit_mode = "select"; - editor->settings->mapCursor = QCursor(QPixmap(":/icons/cursor.ico"), 0, 0); - - ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); - ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - QScroller::ungrabGesture(ui->scrollArea); - - checkToolButtons(); -} - -void MainWindow::on_toolButton_Fill_clicked() -{ - editor->map_edit_mode = "fill"; - editor->settings->mapCursor = QCursor(QPixmap(":/icons/fill_color_cursor.ico"), 10, 10); - - ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); - ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - QScroller::ungrabGesture(ui->scrollArea); - - checkToolButtons(); -} - -void MainWindow::on_toolButton_Dropper_clicked() -{ - editor->map_edit_mode = "pick"; - editor->settings->mapCursor = QCursor(QPixmap(":/icons/pipette_cursor.ico"), 10, 10); - - ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); - ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - QScroller::ungrabGesture(ui->scrollArea); - - checkToolButtons(); -} - -void MainWindow::on_toolButton_Move_clicked() -{ - editor->map_edit_mode = "move"; - editor->settings->mapCursor = QCursor(QPixmap(":/icons/move.ico"), 7, 7); - - ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - QScroller::grabGesture(ui->scrollArea, QScroller::LeftMouseButtonGesture); - - checkToolButtons(); -} - -void MainWindow::on_toolButton_Shift_clicked() -{ - editor->map_edit_mode = "shift"; - editor->settings->mapCursor = QCursor(QPixmap(":/icons/shift_cursor.ico"), 10, 10); - - ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); - ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - QScroller::ungrabGesture(ui->scrollArea); - - checkToolButtons(); -} - -void MainWindow::checkToolButtons() { - ui->toolButton_Paint->setChecked(editor->map_edit_mode == "paint"); - ui->toolButton_Select->setChecked(editor->map_edit_mode == "select"); - ui->toolButton_Fill->setChecked(editor->map_edit_mode == "fill"); - ui->toolButton_Dropper->setChecked(editor->map_edit_mode == "pick"); - ui->toolButton_Move->setChecked(editor->map_edit_mode == "move"); - ui->toolButton_Shift->setChecked(editor->map_edit_mode == "shift"); -} - -void MainWindow::onLoadMapRequested(QString mapName, QString fromMapName) { - setMap(mapName); - editor->setSelectedConnectionFromMap(fromMapName); -} - -void MainWindow::onMapChanged(Map *map) { - map->layout->has_unsaved_changes = true; - updateMapList(); -} - -void MainWindow::onMapNeedsRedrawing() { - redrawMapScene(); -} - -void MainWindow::on_action_Export_Map_Image_triggered() -{ - QString defaultFilepath = QString("%1/%2.png").arg(editor->project->root).arg(editor->map->name); - QString filepath = QFileDialog::getSaveFileName(this, "Export Map Image", defaultFilepath, "Image Files (*.png *.jpg *.bmp)"); - if (!filepath.isEmpty()) { - editor->map_item->pixmap().save(filepath); - } -} - -void MainWindow::on_comboBox_ConnectionDirection_currentIndexChanged(const QString &direction) -{ - editor->updateCurrentConnectionDirection(direction); -} - -void MainWindow::on_spinBox_ConnectionOffset_valueChanged(int offset) -{ - editor->updateConnectionOffset(offset); -} - -void MainWindow::on_comboBox_ConnectedMap_currentTextChanged(const QString &mapName) -{ - editor->setConnectionMap(mapName); -} - -void MainWindow::on_pushButton_AddConnection_clicked() -{ - editor->addNewConnection(); -} - -void MainWindow::on_pushButton_RemoveConnection_clicked() -{ - editor->removeCurrentConnection(); -} - -void MainWindow::on_comboBox_DiveMap_currentTextChanged(const QString &mapName) -{ - editor->updateDiveMap(mapName); -} - -void MainWindow::on_comboBox_EmergeMap_currentTextChanged(const QString &mapName) -{ - editor->updateEmergeMap(mapName); -} - -void MainWindow::on_comboBox_PrimaryTileset_activated(const QString &tilesetLabel) -{ - editor->updatePrimaryTileset(tilesetLabel); -} - -void MainWindow::on_comboBox_SecondaryTileset_activated(const QString &tilesetLabel) -{ - editor->updateSecondaryTileset(tilesetLabel); -} - -void MainWindow::on_pushButton_clicked() -{ - QDialog dialog(this, Qt::WindowTitleHint | Qt::WindowCloseButtonHint); - dialog.setWindowTitle("Change Map Dimensions"); - dialog.setWindowModality(Qt::NonModal); - - QFormLayout form(&dialog); - - QSpinBox *widthSpinBox = new QSpinBox(); - QSpinBox *heightSpinBox = new QSpinBox(); - widthSpinBox->setMinimum(1); - heightSpinBox->setMinimum(1); - // See below for explanation of maximum map dimensions - widthSpinBox->setMaximum(0x1E7); - heightSpinBox->setMaximum(0x1D1); - widthSpinBox->setValue(editor->map->getWidth()); - heightSpinBox->setValue(editor->map->getHeight()); - form.addRow(new QLabel("Width"), widthSpinBox); - form.addRow(new QLabel("Height"), heightSpinBox); - - QLabel *errorLabel = new QLabel(); - QPalette errorPalette; - errorPalette.setColor(QPalette::WindowText, Qt::red); - errorLabel->setPalette(errorPalette); - errorLabel->setVisible(false); - - QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog); - form.addRow(&buttonBox); - connect(&buttonBox, &QDialogButtonBox::accepted, [&dialog, &widthSpinBox, &heightSpinBox, &errorLabel](){ - // Ensure width and height are an acceptable size. - // The maximum number of metatiles in a map is the following: - // max = (width + 15) * (height + 14) - // This limit can be found in fieldmap.c in pokeruby/pokeemerald. - int realWidth = widthSpinBox->value() + 15; - int realHeight = heightSpinBox->value() + 14; - int numMetatiles = realWidth * realHeight; - if (numMetatiles <= 0x2800) { - dialog.accept(); - } else { - QString errorText = QString("Error: The specified width and height are too large.\n" - "The maximum width and height is the following: (width + 15) * (height + 14) <= 10240\n" - "The specified width and height was: (%1 + 15) * (%2 + 14) = %3") - .arg(widthSpinBox->value()) - .arg(heightSpinBox->value()) - .arg(numMetatiles); - errorLabel->setText(errorText); - errorLabel->setVisible(true); - } - }); - connect(&buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject())); - - form.addRow(errorLabel); - - if (dialog.exec() == QDialog::Accepted) { - editor->map->setDimensions(widthSpinBox->value(), heightSpinBox->value()); - editor->map->commit(); - onMapNeedsRedrawing(); - } -} - -void MainWindow::on_checkBox_smartPaths_stateChanged(int selected) -{ - editor->settings->smartPathsEnabled = selected == Qt::Checked; -} - -void MainWindow::on_checkBox_ToggleBorder_stateChanged(int selected) -{ - bool visible = selected != 0; - editor->toggleBorderVisibility(visible); -} +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include "project.h" +#include "editor.h" +#include "eventpropertiesframe.h" +#include "ui_objectpropertiesframe.h" +#include "bordermetatilespixmapitem.h" +#include "currentselectedmetatilespixmapitem.h" + +#include <QDebug> +#include <QFileDialog> +#include <QStandardItemModel> +#include <QShortcut> +#include <QSettings> +#include <QSpinBox> +#include <QTextEdit> +#include <QSpacerItem> +#include <QFont> +#include <QScrollBar> +#include <QPushButton> +#include <QMessageBox> +#include <QDialogButtonBox> +#include <QScroller> +#include <math.h> +#include <QProcess> +#include <QSysInfo> +#include <QDesktopServices> + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + QCoreApplication::setOrganizationName("pret"); + QCoreApplication::setApplicationName("porymap"); + QApplication::setWindowIcon(QIcon(":/icons/porymap-icon-1.ico")); + + ui->setupUi(this); + this->initExtraSignals(); + this->initExtraShortcuts(); + this->initEditor(); + this->openRecentProject(); + + on_toolButton_Paint_clicked(); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::initExtraShortcuts() { + new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Z), this, SLOT(redo())); +} + +void MainWindow::initExtraSignals() { + connect(ui->newEventToolButton, SIGNAL(newEventAdded(QString)), this, SLOT(addNewEvent(QString))); +} + +void MainWindow::initEditor() { + this->editor = new Editor(ui); + connect(this->editor, SIGNAL(objectsChanged()), this, SLOT(updateSelectedObjects())); + connect(this->editor, SIGNAL(selectedObjectsChanged()), this, SLOT(updateSelectedObjects())); + connect(this->editor, SIGNAL(loadMapRequested(QString, QString)), this, SLOT(onLoadMapRequested(QString, QString))); + connect(this->editor, SIGNAL(tilesetChanged(QString)), this, SLOT(onTilesetChanged(QString))); + connect(this->editor, SIGNAL(warpEventDoubleClicked(QString,QString)), this, SLOT(openWarpMap(QString,QString))); + connect(this->editor, SIGNAL(currentMetatilesSelectionChanged()), this, SLOT(currentMetatilesSelectionChanged())); + + this->loadUserSettings(); +} + +void MainWindow::loadUserSettings() { + QSettings settings; + + bool betterCursors = settings.contains("cursor_mode") && settings.value("cursor_mode") != "0"; + ui->actionBetter_Cursors->setChecked(betterCursors); + this->editor->settings->betterCursors = betterCursors; +} + +void MainWindow::openRecentProject() { + QSettings settings; + QString key = "recent_projects"; + if (settings.contains(key)) { + QString default_dir = settings.value(key).toStringList().last(); + if (!default_dir.isNull()) { + qDebug() << QString("default_dir: '%1'").arg(default_dir); + openProject(default_dir); + } + } +} + +void MainWindow::openProject(QString dir) { + if (dir.isNull()) { + return; + } + + this->statusBar()->showMessage(QString("Opening project %1").arg(dir)); + + bool already_open = ( + (editor && editor != nullptr) + && (editor->project && editor->project != nullptr) + && (editor->project->root == dir) + ); + if (!already_open) { + editor->project = new Project; + editor->project->root = dir; + setWindowTitle(editor->project->getProjectTitle() + " - porymap"); + loadDataStructures(); + populateMapList(); + setMap(getDefaultMap()); + } else { + setWindowTitle(editor->project->getProjectTitle() + " - porymap"); + loadDataStructures(); + populateMapList(); + } + + this->statusBar()->showMessage(QString("Opened project %1").arg(dir)); +} + +QString MainWindow::getDefaultMap() { + if (editor && editor->project) { + QList<QStringList> names = editor->project->groupedMapNames; + if (!names.isEmpty()) { + QSettings settings; + QString key = "project:" + editor->project->root; + if (settings.contains(key)) { + QMap<QString, QVariant> qmap = settings.value(key).toMap(); + if (qmap.contains("recent_map")) { + QString map_name = qmap.value("recent_map").toString(); + for (int i = 0; i < names.length(); i++) { + if (names.value(i).contains(map_name)) { + return map_name; + } + } + } + } + // Failing that, just get the first map in the list. + for (int i = 0; i < names.length(); i++) { + QStringList list = names.value(i); + if (list.length()) { + return list.value(0); + } + } + } + } + return QString(); +} + +QString MainWindow::getExistingDirectory(QString dir) { + return QFileDialog::getExistingDirectory(this, "Open Directory", dir, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); +} + +void MainWindow::on_action_Open_Project_triggered() +{ + QSettings settings; + QString key = "recent_projects"; + QString recent = "."; + if (settings.contains(key)) { + recent = settings.value(key).toStringList().last(); + } + QString dir = getExistingDirectory(recent); + if (!dir.isEmpty()) { + QStringList recents; + if (settings.contains(key)) { + recents = settings.value(key).toStringList(); + } + recents.removeAll(dir); + recents.append(dir); + settings.setValue(key, recents); + + openProject(dir); + } +} + +void MainWindow::setMap(QString map_name) { + qDebug() << QString("setMap(%1)").arg(map_name); + if (map_name.isNull()) { + return; + } + editor->setMap(map_name); + redrawMapScene(); + displayMapProperties(); + + setWindowTitle(map_name + " - " + editor->project->getProjectTitle() + " - porymap"); + + connect(editor->map, SIGNAL(mapChanged(Map*)), this, SLOT(onMapChanged(Map *))); + connect(editor->map, SIGNAL(mapNeedsRedrawing()), this, SLOT(onMapNeedsRedrawing())); + + setRecentMap(map_name); + updateMapList(); +} + +void MainWindow::redrawMapScene() +{ + editor->displayMap(); + on_tabWidget_currentChanged(ui->tabWidget->currentIndex()); + + ui->graphicsView_Map->setScene(editor->scene); + ui->graphicsView_Map->setSceneRect(editor->scene->sceneRect()); + ui->graphicsView_Map->setFixedSize(static_cast<int>(editor->scene->width()) + 2, static_cast<int>(editor->scene->height()) + 2); + + ui->graphicsView_Objects_Map->setScene(editor->scene); + ui->graphicsView_Objects_Map->setSceneRect(editor->scene->sceneRect()); + ui->graphicsView_Objects_Map->setFixedSize(static_cast<int>(editor->scene->width()) + 2, static_cast<int>(editor->scene->height()) + 2); + ui->graphicsView_Objects_Map->editor = editor; + + ui->graphicsView_Connections->setScene(editor->scene); + ui->graphicsView_Connections->setSceneRect(editor->scene->sceneRect()); + ui->graphicsView_Connections->setFixedSize(static_cast<int>(editor->scene->width()) + 2, static_cast<int>(editor->scene->height()) + 2); + + ui->graphicsView_Metatiles->setScene(editor->scene_metatiles); + //ui->graphicsView_Metatiles->setSceneRect(editor->scene_metatiles->sceneRect()); + 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); + + ui->graphicsView_currentMetatileSelection->setScene(editor->scene_current_metatile_selection); + ui->graphicsView_currentMetatileSelection->setFixedSize(editor->scene_current_metatile_selection_item->pixmap().width() + 2, editor->scene_current_metatile_selection_item->pixmap().height() + 2); + + ui->graphicsView_Collision->setScene(editor->scene_collision_metatiles); + //ui->graphicsView_Collision->setSceneRect(editor->scene_collision_metatiles->sceneRect()); + ui->graphicsView_Collision->setFixedSize(editor->movement_permissions_selector_item->pixmap().width() + 2, editor->movement_permissions_selector_item->pixmap().height() + 2); +} + +void MainWindow::openWarpMap(QString map_name, QString warp_num) { + // Ensure valid destination map name. + if (!editor->project->mapNames->contains(map_name)) { + qDebug() << QString("Invalid warp destination map name '%1'").arg(map_name); + return; + } + + // Ensure valid destination warp number. + bool ok; + int warpNum = warp_num.toInt(&ok, 0); + if (!ok) { + qDebug() << QString("Invalid warp number '%1' for destination map '%2'").arg(warp_num).arg(map_name); + return; + } + + // Open the destination map, and select the target warp event. + setMap(map_name); + QList<Event*> warp_events = editor->map->events["warp_event_group"]; + if (warp_events.length() > warpNum) { + Event *warp_event = warp_events.at(warpNum); + QList<DraggablePixmapItem *> *all_events = editor->getObjects(); + for (DraggablePixmapItem *item : *all_events) { + if (item->event == warp_event) { + editor->selected_events->clear(); + editor->selected_events->append(item); + editor->updateSelectedEvents(); + } + } + + delete all_events; + } +} + +void MainWindow::setRecentMap(QString map_name) { + QSettings settings; + QString key = "project:" + editor->project->root; + QMap<QString, QVariant> qmap; + if (settings.contains(key)) { + qmap = settings.value(key).toMap(); + } + qmap.insert("recent_map", map_name); + settings.setValue(key, qmap); +} + +void MainWindow::displayMapProperties() { + ui->comboBox_Song->clear(); + ui->comboBox_Location->clear(); + ui->checkBox_Visibility->setChecked(false); + ui->comboBox_Weather->clear(); + ui->comboBox_Type->clear(); + ui->comboBox_BattleScene->clear(); + ui->comboBox_PrimaryTileset->clear(); + ui->comboBox_SecondaryTileset->clear(); + ui->checkBox_ShowLocation->setChecked(false); + if (!editor || !editor->map || !editor->project) { + ui->frame_3->setEnabled(false); + return; + } + ui->frame_3->setEnabled(true); + Map *map = editor->map; + Project *project = editor->project; + + QStringList songs = project->getSongNames(); + ui->comboBox_Song->addItems(songs); + ui->comboBox_Song->setCurrentText(map->song); + + ui->comboBox_Location->addItems(*project->regionMapSections); + ui->comboBox_Location->setCurrentText(map->location); + + QMap<QString, QStringList> tilesets = project->getTilesets(); + ui->comboBox_PrimaryTileset->addItems(tilesets.value("primary")); + ui->comboBox_PrimaryTileset->setCurrentText(map->layout->tileset_primary_label); + ui->comboBox_SecondaryTileset->addItems(tilesets.value("secondary")); + ui->comboBox_SecondaryTileset->setCurrentText(map->layout->tileset_secondary_label); + + ui->checkBox_Visibility->setChecked(map->requiresFlash.toInt() > 0 || map->requiresFlash == "TRUE"); + + ui->comboBox_Weather->addItems(*project->weatherNames); + ui->comboBox_Weather->setCurrentText(map->weather); + + ui->comboBox_Type->addItems(*project->mapTypes); + ui->comboBox_Type->setCurrentText(map->type); + + ui->comboBox_BattleScene->addItems(*project->mapBattleScenes); + ui->comboBox_BattleScene->setCurrentText(map->battle_scene); + + ui->checkBox_ShowLocation->setChecked(map->show_location.toInt() > 0 || map->show_location == "TRUE"); +} + +void MainWindow::on_comboBox_Song_activated(const QString &song) +{ + if (editor && editor->map) { + editor->map->song = song; + } +} + +void MainWindow::on_comboBox_Location_activated(const QString &location) +{ + if (editor && editor->map) { + editor->map->location = location; + } +} + +void MainWindow::on_comboBox_Visibility_activated(const QString &requiresFlash) +{ + if (editor && editor->map) { + editor->map->requiresFlash = requiresFlash; + } +} + +void MainWindow::on_comboBox_Weather_activated(const QString &weather) +{ + if (editor && editor->map) { + editor->map->weather = weather; + } +} + +void MainWindow::on_comboBox_Type_activated(const QString &type) +{ + if (editor && editor->map) { + editor->map->type = type; + } +} + +void MainWindow::on_comboBox_BattleScene_activated(const QString &battle_scene) +{ + if (editor && editor->map) { + editor->map->battle_scene = battle_scene; + } +} + +void MainWindow::on_checkBox_Visibility_clicked(bool checked) +{ + if (editor && editor->map) { + if (checked) { + editor->map->requiresFlash = "TRUE"; + } else { + editor->map->requiresFlash = "FALSE"; + } + } +} + +void MainWindow::on_checkBox_ShowLocation_clicked(bool checked) +{ + if (editor && editor->map) { + if (checked) { + editor->map->show_location = "TRUE"; + } else { + editor->map->show_location = "FALSE"; + } + } +} + +void MainWindow::loadDataStructures() { + Project *project = editor->project; + project->readMapLayoutsTable(); + project->readAllMapLayouts(); + project->readRegionMapSections(); + project->readItemNames(); + project->readFlagNames(); + project->readVarNames(); + project->readMovementTypes(); + project->readMapTypes(); + project->readMapBattleScenes(); + project->readWeatherNames(); + project->readCoordEventWeatherNames(); + project->readSecretBaseIds(); + project->readBgEventFacingDirections(); + project->readMapsWithConnections(); + project->readTilesetProperties(); +} + +void MainWindow::populateMapList() { + Project *project = editor->project; + + QIcon mapFolderIcon; + mapFolderIcon.addFile(QStringLiteral(":/icons/folder_closed_map.ico"), QSize(), QIcon::Normal, QIcon::Off); + mapFolderIcon.addFile(QStringLiteral(":/icons/folder_map.ico"), QSize(), QIcon::Normal, QIcon::On); + + QIcon folderIcon; + folderIcon.addFile(QStringLiteral(":/icons/folder_closed.ico"), QSize(), QIcon::Normal, QIcon::Off); + + mapIcon = new QIcon; + mapIcon->addFile(QStringLiteral(":/icons/map.ico"), QSize(), QIcon::Normal, QIcon::Off); + mapIcon->addFile(QStringLiteral(":/icons/image.ico"), QSize(), QIcon::Normal, QIcon::On); + + mapListModel = new QStandardItemModel; + mapGroupsModel = new QList<QStandardItem*>; + + QStandardItem *entry = new QStandardItem; + entry->setText(project->getProjectTitle()); + entry->setIcon(folderIcon); + entry->setEditable(false); + mapListModel->appendRow(entry); + + QStandardItem *maps = new QStandardItem; + maps->setText("maps"); + maps->setIcon(folderIcon); + maps->setEditable(false); + entry->appendRow(maps); + + project->readMapGroups(); + for (int i = 0; i < project->groupNames->length(); i++) { + QString group_name = project->groupNames->value(i); + QStandardItem *group = new QStandardItem; + group->setText(group_name); + group->setIcon(mapFolderIcon); + group->setEditable(false); + group->setData(group_name, Qt::UserRole); + group->setData("map_group", MapListUserRoles::TypeRole); + group->setData(i, MapListUserRoles::GroupRole); + maps->appendRow(group); + mapGroupsModel->append(group); + QStringList names = project->groupedMapNames.value(i); + for (int j = 0; j < names.length(); j++) { + QString map_name = names.value(j); + QStandardItem *map = createMapItem(map_name, i, j); + group->appendRow(map); + } + } + + // Right-clicking on items in the map list tree view brings up a context menu. + ui->mapList->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui->mapList, SIGNAL(customContextMenuRequested(const QPoint &)), + this, SLOT(onOpenMapListContextMenu(const QPoint &))); + + ui->mapList->setModel(mapListModel); + ui->mapList->setUpdatesEnabled(true); + ui->mapList->expandToDepth(2); + ui->mapList->repaint(); +} + +QStandardItem* MainWindow::createMapItem(QString mapName, int groupNum, int inGroupNum) { + QStandardItem *map = new QStandardItem; + map->setText(QString("[%1.%2] ").arg(groupNum).arg(inGroupNum, 2, 10, QLatin1Char('0')) + mapName); + map->setIcon(*mapIcon); + map->setEditable(false); + map->setData(mapName, Qt::UserRole); + map->setData("map_name", MapListUserRoles::TypeRole); + return map; +} + +void MainWindow::onOpenMapListContextMenu(const QPoint &point) +{ + QModelIndex index = ui->mapList->indexAt(point); + if (!index.isValid()) { + return; + } + + QStandardItem *selectedItem = mapListModel->itemFromIndex(index); + QVariant itemType = selectedItem->data(MapListUserRoles::TypeRole); + if (!itemType.isValid()) { + return; + } + + // Build custom context menu depending on which type of item was selected (map group, map name, etc.) + if (itemType == "map_group") { + QString groupName = selectedItem->data(Qt::UserRole).toString(); + int groupNum = selectedItem->data(MapListUserRoles::GroupRole).toInt(); + QMenu* menu = new QMenu(); + QActionGroup* actions = new QActionGroup(menu); + actions->addAction(menu->addAction("Add New Map to Group"))->setData(groupNum); + connect(actions, SIGNAL(triggered(QAction*)), this, SLOT(onAddNewMapToGroupClick(QAction*))); + menu->exec(QCursor::pos()); + } +} + +void MainWindow::onAddNewMapToGroupClick(QAction* triggeredAction) +{ + int groupNum = triggeredAction->data().toInt(); + QStandardItem* groupItem = mapGroupsModel->at(groupNum); + + QString newMapName = editor->project->getNewMapName(); + Map* newMap = editor->project->addNewMapToGroup(newMapName, groupNum); + editor->project->saveMap(newMap); + editor->project->saveAllDataStructures(); + + int numMapsInGroup = groupItem->rowCount(); + QStandardItem *newMapItem = createMapItem(newMapName, groupNum, numMapsInGroup); + groupItem->appendRow(newMapItem); + + setMap(newMapName); +} + +void MainWindow::onTilesetChanged(QString mapName) +{ + setMap(mapName); +} + +void MainWindow::currentMetatilesSelectionChanged() +{ + ui->graphicsView_currentMetatileSelection->setFixedSize(editor->scene_current_metatile_selection_item->pixmap().width() + 2, editor->scene_current_metatile_selection_item->pixmap().height() + 2); + ui->graphicsView_currentMetatileSelection->setSceneRect(0, 0, editor->scene_current_metatile_selection_item->pixmap().width(), editor->scene_current_metatile_selection_item->pixmap().height()); +} + +void MainWindow::on_mapList_activated(const QModelIndex &index) +{ + QVariant data = index.data(Qt::UserRole); + if (!data.isNull()) { + setMap(data.toString()); + } +} + +void MainWindow::markAllEdited(QAbstractItemModel *model) { + QList<QModelIndex> list; + list.append(QModelIndex()); + while (list.length()) { + QModelIndex parent = list.takeFirst(); + for (int i = 0; i < model->rowCount(parent); i++) { + QModelIndex index = model->index(i, 0, parent); + if (model->hasChildren(index)) { + list.append(index); + } + markEdited(index); + } + } +} + +void MainWindow::markEdited(QModelIndex index) { + QVariant data = index.data(Qt::UserRole); + if (!data.isNull()) { + QString map_name = data.toString(); + if (editor->project) { + if (editor->project->map_cache->contains(map_name)) { + // Just mark anything that's been opened for now. + // TODO if (project->getMap()->saved) + //ui->mapList->setExpanded(index, true); + ui->mapList->setExpanded(index, editor->project->map_cache->value(map_name)->hasUnsavedChanges()); + } + } + } +} + +void MainWindow::updateMapList() { + QAbstractItemModel *model = ui->mapList->model(); + markAllEdited(model); +} + +void MainWindow::on_action_Save_Project_triggered() +{ + editor->saveProject(); + updateMapList(); +} + +void MainWindow::undo() { + editor->undo(); +} + +void MainWindow::redo() { + editor->redo(); +} + +// Open current map scripts in system default editor for .inc files +void MainWindow::openInTextEditor() { + QString path = QDir::cleanPath("file://" + editor->project->root + QDir::separator() + "data/maps/" + editor->map->name + "/scripts.inc"); + QDesktopServices::openUrl(QUrl(path)); +} + +void MainWindow::on_action_Save_triggered() { + editor->save(); + updateMapList(); +} + +void MainWindow::on_tabWidget_2_currentChanged(int index) +{ + if (index == 0) { + editor->setEditingMap(); + } else if (index == 1) { + editor->setEditingCollision(); + } +} + +void MainWindow::on_action_Exit_triggered() +{ + QApplication::quit(); +} + +void MainWindow::on_tabWidget_currentChanged(int index) +{ + if (index == 0) { + on_tabWidget_2_currentChanged(ui->tabWidget_2->currentIndex()); + } else if (index == 1) { + editor->setEditingObjects(); + } else if (index == 3) { + editor->setEditingConnections(); + } +} + +void MainWindow::on_actionUndo_triggered() +{ + undo(); +} + +void MainWindow::on_actionRedo_triggered() +{ + redo(); +} + +void MainWindow::on_actionZoom_In_triggered() { + scaleMapView(1); +} + +void MainWindow::on_actionZoom_Out_triggered() { + scaleMapView(-1); +} + +void MainWindow::on_actionBetter_Cursors_triggered() { + QSettings settings; + settings.setValue("cursor_mode", QString::number(ui->actionBetter_Cursors->isChecked())); + this->editor->settings->betterCursors = ui->actionBetter_Cursors->isChecked(); +} + +void MainWindow::on_actionPencil_triggered() +{ + on_toolButton_Paint_clicked(); +} + +void MainWindow::on_actionPointer_triggered() +{ + on_toolButton_Select_clicked(); +} + +void MainWindow::on_actionFlood_Fill_triggered() +{ + on_toolButton_Fill_clicked(); +} + +void MainWindow::on_actionEyedropper_triggered() +{ + on_toolButton_Dropper_clicked(); +} + +void MainWindow::on_actionMove_triggered() +{ + on_toolButton_Move_clicked(); +} + +void MainWindow::on_actionMap_Shift_triggered() +{ + on_toolButton_Shift_clicked(); +} + +void MainWindow::scaleMapView(int s) { + editor->map->scale_exp += s; + + double base = editor->map->scale_base; + double exp = editor->map->scale_exp; + double sfactor = pow(base,s); + + ui->graphicsView_Map->scale(sfactor,sfactor); + ui->graphicsView_Objects_Map->scale(sfactor,sfactor); + + int width = static_cast<int>((editor->scene->width() + 2) * pow(base,exp)); + int height = static_cast<int>((editor->scene->height() + 2) * pow(base,exp)); + ui->graphicsView_Map->setFixedSize(width, height); + ui->graphicsView_Objects_Map->setFixedSize(width, height); +} + +void MainWindow::addNewEvent(QString event_type) +{ + if (editor) { + DraggablePixmapItem *object = editor->addNewEvent(event_type); + if (object) { + editor->selectMapEvent(object, false); + } + updateSelectedObjects(); + } +} + +// Should probably just pass layout and let the editor work it out +void MainWindow::updateSelectedObjects() { + QList<DraggablePixmapItem *> *all_events = editor->getObjects(); + QList<DraggablePixmapItem *> *events = nullptr; + + if (editor->selected_events && editor->selected_events->length()) { + events = editor->selected_events; + } else { + events = new QList<DraggablePixmapItem*>; + if (all_events && all_events->length()) { + DraggablePixmapItem *selectedEvent = all_events->first(); + editor->selected_events->append(selectedEvent); + editor->redrawObject(selectedEvent); + events->append(selectedEvent); + } + } + + QMap<QString, int> event_obj_gfx_constants = editor->project->getEventObjGfxConstants(); + + QList<EventPropertiesFrame *> frames; + + for (DraggablePixmapItem *item : *events) { + EventPropertiesFrame *frame = new EventPropertiesFrame; +// frame->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + + QSpinBox *x = frame->ui->spinBox_x; + QSpinBox *y = frame->ui->spinBox_y; + QSpinBox *z = frame->ui->spinBox_z; + + x->setValue(item->event->x()); + connect(x, SIGNAL(valueChanged(QString)), item, SLOT(set_x(QString))); + connect(item, SIGNAL(xChanged(int)), x, SLOT(setValue(int))); + + y->setValue(item->event->y()); + connect(y, SIGNAL(valueChanged(QString)), item, SLOT(set_y(QString))); + connect(item, SIGNAL(yChanged(int)), y, SLOT(setValue(int))); + + z->setValue(item->event->elevation()); + connect(z, SIGNAL(valueChanged(QString)), item, SLOT(set_elevation(QString))); + connect(item, SIGNAL(elevationChanged(int)), z, SLOT(setValue(int))); + + QFont font; + font.setCapitalization(QFont::Capitalize); + frame->ui->label_name->setFont(font); + QString event_type = item->event->get("event_type"); + QString event_group_type = item->event->get("event_group_type"); + QString map_name = item->event->get("map_name"); + int event_offs; + if (event_type == "event_warp") { event_offs = 0; } + else { event_offs = 1; } + frame->ui->label_name->setText( + QString("%1: %2 %3") + .arg(editor->project->getMap(map_name)->events.value(event_group_type).indexOf(item->event) + event_offs) + .arg(map_name) + .arg(event_type) + ); + + frame->ui->label_spritePixmap->setPixmap(item->event->pixmap); + connect(item, SIGNAL(spriteChanged(QPixmap)), frame->ui->label_spritePixmap, SLOT(setPixmap(QPixmap))); + + frame->ui->sprite->setVisible(false); + + QMap<QString, QString> field_labels; + field_labels["script_label"] = "Script"; + field_labels["event_flag"] = "Event Flag"; + field_labels["movement_type"] = "Movement"; + field_labels["radius_x"] = "Movement Radius X"; + field_labels["radius_y"] = "Movement Radius Y"; + field_labels["is_trainer"] = "Trainer"; + field_labels["sight_radius_tree_id"] = "Sight Radius / Berry Tree ID"; + field_labels["destination_warp"] = "Destination Warp"; + field_labels["destination_map_name"] = "Destination Map"; + field_labels["script_var"] = "Var"; + field_labels["script_var_value"] = "Var Value"; + field_labels["player_facing_direction"] = "Player Facing Direction"; + field_labels["item"] = "Item"; + field_labels["item_unknown5"] = "Unknown 5"; + field_labels["item_unknown6"] = "Unknown 6"; + field_labels["weather"] = "Weather"; + field_labels["flag"] = "Flag"; + field_labels["secret_base_id"] = "Secret Base Id"; + + QStringList fields; + + if (event_type == EventType::Object) { + + frame->ui->sprite->setVisible(true); + frame->ui->comboBox_sprite->addItems(event_obj_gfx_constants.keys()); + frame->ui->comboBox_sprite->setCurrentText(item->event->get("sprite")); + connect(frame->ui->comboBox_sprite, SIGNAL(activated(QString)), item, SLOT(set_sprite(QString))); + + /* + frame->ui->script->setVisible(true); + frame->ui->comboBox_script->addItem(item->event->get("script_label")); + frame->ui->comboBox_script->setCurrentText(item->event->get("script_label")); + //item->bind(frame->ui->comboBox_script, "script_label"); + connect(frame->ui->comboBox_script, SIGNAL(activated(QString)), item, SLOT(set_script(QString))); + //connect(frame->ui->comboBox_script, static_cast<void (QComboBox::*)(const QString&)>(&QComboBox::activated), item, [item](QString script_label){ item->event->put("script_label", script_label); }); + //connect(item, SIGNAL(scriptChanged(QString)), frame->ui->comboBox_script, SLOT(setValue(QString))); + */ + + fields << "movement_type"; + fields << "radius_x"; + fields << "radius_y"; + fields << "script_label"; + fields << "event_flag"; + fields << "is_trainer"; + fields << "sight_radius_tree_id"; + } + else if (event_type == EventType::Warp) { + fields << "destination_map_name"; + fields << "destination_warp"; + } + else if (event_type == EventType::CoordScript) { + fields << "script_label"; + fields << "script_var"; + fields << "script_var_value"; + } + else if (event_type == EventType::CoordWeather) { + fields << "weather"; + } + else if (event_type == EventType::Sign) { + fields << "player_facing_direction"; + fields << "script_label"; + } + else if (event_type == EventType::HiddenItem) { + fields << "item"; + fields << "flag"; + } + else if (event_type == EventType::SecretBase) { + fields << "secret_base_id"; + } + + for (QString key : fields) { + QString value = item->event->get(key); + QWidget *widget = new QWidget(frame); + QFormLayout *fl = new QFormLayout(widget); + fl->setContentsMargins(9, 0, 9, 0); + + // is_trainer is the only non-combobox item. + if (key == "is_trainer") { + QCheckBox *checkbox = new QCheckBox(widget); + checkbox->setEnabled(true); + checkbox->setChecked(value.toInt() != 0 && value != "FALSE"); + checkbox->setToolTip("Whether or not this object is trainer."); + fl->addRow(new QLabel(field_labels[key], widget), checkbox); + widget->setLayout(fl); + frame->layout()->addWidget(widget); + connect(checkbox, &QCheckBox::stateChanged, [=](int state) { + QString isTrainer = state == Qt::Checked ? "TRUE" : "FALSE"; + item->event->put("is_trainer", isTrainer); + }); + continue; + } + + NoScrollComboBox *combo = new NoScrollComboBox(widget); + combo->setEditable(true); + + if (key == "destination_map_name") { + if (!editor->project->mapNames->contains(value)) { + combo->addItem(value); + } + combo->addItems(*editor->project->mapNames); + combo->setToolTip("The destination map name of the warp."); + } else if (key == "destination_warp") { + combo->setToolTip("The warp id on the destination map."); + } else if (key == "item") { + if (!editor->project->itemNames->contains(value)) { + combo->addItem(value); + } + combo->addItems(*editor->project->itemNames); + } else if (key == "flag" || key == "event_flag") { + if (!editor->project->flagNames->contains(value)) { + combo->addItem(value); + } + combo->addItems(*editor->project->flagNames); + if (key == "flag") + combo->setToolTip("The flag which is set when the hidden item is picked up."); + else if (key == "event_flag") + combo->setToolTip("The flag which hides the object when set."); + } else if (key == "script_var") { + if (!editor->project->varNames->contains(value)) { + combo->addItem(value); + } + combo->addItems(*editor->project->varNames); + combo->setToolTip("The variable by which the script is triggered. The script is triggered when this variable's value matches 'Var Value'."); + } else if (key == "script_var_value") { + combo->setToolTip("The variable's value which triggers the script."); + } else if (key == "movement_type") { + if (!editor->project->movementTypes->contains(value)) { + combo->addItem(value); + } + combo->addItems(*editor->project->movementTypes); + combo->setToolTip("The object's natural movement behavior when the player is not interacting with it."); + } else if (key == "weather") { + if (!editor->project->coordEventWeatherNames->contains(value)) { + combo->addItem(value); + } + combo->addItems(*editor->project->coordEventWeatherNames); + combo->setToolTip("The weather that starts when the player steps on this spot."); + } else if (key == "secret_base_id") { + if (!editor->project->secretBaseIds->contains(value)) { + combo->addItem(value); + } + combo->addItems(*editor->project->secretBaseIds); + combo->setToolTip("The secret base id which is inside this secret base entrance. Secret base ids are meant to be unique to each and every secret base entrance."); + } else if (key == "player_facing_direction") { + if (!editor->project->bgEventFacingDirections->contains(value)) { + combo->addItem(value); + } + combo->addItems(*editor->project->bgEventFacingDirections); + combo->setToolTip("The direction which the player must be facing to be able to interact with this event."); + } else if (key == "radius_x") { + combo->setToolTip("The maximum number of metatiles this object is allowed to move left or right during its normal movement behavior actions."); + } else if (key == "radius_y") { + combo->setToolTip("The maximum number of metatiles this object is allowed to move up or down during its normal movement behavior actions."); + } else if (key == "script_label") { + combo->setToolTip("The script which is executed with this event."); + } else if (key == "sight_radius_tree_id") { + combo->setToolTip("The maximum sight range of a trainer, OR the unique id of the berry tree."); + } else { + combo->addItem(value); + } + combo->setCurrentText(value); + + fl->addRow(new QLabel(field_labels[key], widget), combo); + widget->setLayout(fl); + frame->layout()->addWidget(widget); + + item->bind(combo, key); + } + + frames.append(frame); + + } + + //int scroll = ui->scrollArea_4->verticalScrollBar()->value(); + + QWidget *target = ui->scrollAreaWidgetContents; + + if (target->children().length()) { + qDeleteAll(target->children()); + } + + QVBoxLayout *layout = new QVBoxLayout(target); + target->setLayout(layout); + ui->scrollArea_4->setWidgetResizable(true); + ui->scrollArea_4->setWidget(target); + + for (EventPropertiesFrame *frame : frames) { + layout->addWidget(frame); + } + + layout->addStretch(1); + + // doesn't work + //QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + //ui->scrollArea_4->ensureVisible(0, scroll); +} + +void MainWindow::on_toolButton_deleteObject_clicked() +{ + if (editor && editor->selected_events) { + if (editor->selected_events->length()) { + for (DraggablePixmapItem *item : *editor->selected_events) { + if (item->event->get("event_type") != EventType::HealLocation) { + editor->deleteEvent(item->event); + if (editor->scene->items().contains(item)) { + editor->scene->removeItem(item); + } + editor->selected_events->removeOne(item); + } + else { // don't allow deletion of heal locations + qDebug() << "Cannot delete event of type " << item->event->get("event_type"); + } + } + updateSelectedObjects(); + } + } +} + +void MainWindow::on_toolButton_Open_Scripts_clicked() +{ + openInTextEditor(); +} + +void MainWindow::on_toolButton_Paint_clicked() +{ + editor->map_edit_mode = "paint"; + editor->settings->mapCursor = QCursor(QPixmap(":/icons/pencil_cursor.ico"), 10, 10); + + ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + QScroller::ungrabGesture(ui->scrollArea); + + checkToolButtons(); +} + +void MainWindow::on_toolButton_Select_clicked() +{ + editor->map_edit_mode = "select"; + editor->settings->mapCursor = QCursor(QPixmap(":/icons/cursor.ico"), 0, 0); + + ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + QScroller::ungrabGesture(ui->scrollArea); + + checkToolButtons(); +} + +void MainWindow::on_toolButton_Fill_clicked() +{ + editor->map_edit_mode = "fill"; + editor->settings->mapCursor = QCursor(QPixmap(":/icons/fill_color_cursor.ico"), 10, 10); + + ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + QScroller::ungrabGesture(ui->scrollArea); + + checkToolButtons(); +} + +void MainWindow::on_toolButton_Dropper_clicked() +{ + editor->map_edit_mode = "pick"; + editor->settings->mapCursor = QCursor(QPixmap(":/icons/pipette_cursor.ico"), 10, 10); + + ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + QScroller::ungrabGesture(ui->scrollArea); + + checkToolButtons(); +} + +void MainWindow::on_toolButton_Move_clicked() +{ + editor->map_edit_mode = "move"; + editor->settings->mapCursor = QCursor(QPixmap(":/icons/move.ico"), 7, 7); + + ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + QScroller::grabGesture(ui->scrollArea, QScroller::LeftMouseButtonGesture); + + checkToolButtons(); +} + +void MainWindow::on_toolButton_Shift_clicked() +{ + editor->map_edit_mode = "shift"; + editor->settings->mapCursor = QCursor(QPixmap(":/icons/shift_cursor.ico"), 10, 10); + + ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + QScroller::ungrabGesture(ui->scrollArea); + + checkToolButtons(); +} + +void MainWindow::checkToolButtons() { + ui->toolButton_Paint->setChecked(editor->map_edit_mode == "paint"); + ui->toolButton_Select->setChecked(editor->map_edit_mode == "select"); + ui->toolButton_Fill->setChecked(editor->map_edit_mode == "fill"); + ui->toolButton_Dropper->setChecked(editor->map_edit_mode == "pick"); + ui->toolButton_Move->setChecked(editor->map_edit_mode == "move"); + ui->toolButton_Shift->setChecked(editor->map_edit_mode == "shift"); +} + +void MainWindow::onLoadMapRequested(QString mapName, QString fromMapName) { + setMap(mapName); + editor->setSelectedConnectionFromMap(fromMapName); +} + +void MainWindow::onMapChanged(Map *map) { + map->layout->has_unsaved_changes = true; + updateMapList(); +} + +void MainWindow::onMapNeedsRedrawing() { + redrawMapScene(); +} + +void MainWindow::on_action_Export_Map_Image_triggered() +{ + QString defaultFilepath = QString("%1/%2.png").arg(editor->project->root).arg(editor->map->name); + QString filepath = QFileDialog::getSaveFileName(this, "Export Map Image", defaultFilepath, "Image Files (*.png *.jpg *.bmp)"); + if (!filepath.isEmpty()) { + editor->map_item->pixmap().save(filepath); + } +} + +void MainWindow::on_comboBox_ConnectionDirection_currentIndexChanged(const QString &direction) +{ + editor->updateCurrentConnectionDirection(direction); +} + +void MainWindow::on_spinBox_ConnectionOffset_valueChanged(int offset) +{ + editor->updateConnectionOffset(offset); +} + +void MainWindow::on_comboBox_ConnectedMap_currentTextChanged(const QString &mapName) +{ + editor->setConnectionMap(mapName); +} + +void MainWindow::on_pushButton_AddConnection_clicked() +{ + editor->addNewConnection(); +} + +void MainWindow::on_pushButton_RemoveConnection_clicked() +{ + editor->removeCurrentConnection(); +} + +void MainWindow::on_comboBox_DiveMap_currentTextChanged(const QString &mapName) +{ + editor->updateDiveMap(mapName); +} + +void MainWindow::on_comboBox_EmergeMap_currentTextChanged(const QString &mapName) +{ + editor->updateEmergeMap(mapName); +} + +void MainWindow::on_comboBox_PrimaryTileset_activated(const QString &tilesetLabel) +{ + editor->updatePrimaryTileset(tilesetLabel); +} + +void MainWindow::on_comboBox_SecondaryTileset_activated(const QString &tilesetLabel) +{ + editor->updateSecondaryTileset(tilesetLabel); +} + +void MainWindow::on_pushButton_clicked() +{ + QDialog dialog(this, Qt::WindowTitleHint | Qt::WindowCloseButtonHint); + dialog.setWindowTitle("Change Map Dimensions"); + dialog.setWindowModality(Qt::NonModal); + + QFormLayout form(&dialog); + + QSpinBox *widthSpinBox = new QSpinBox(); + QSpinBox *heightSpinBox = new QSpinBox(); + widthSpinBox->setMinimum(1); + heightSpinBox->setMinimum(1); + // See below for explanation of maximum map dimensions + widthSpinBox->setMaximum(0x1E7); + heightSpinBox->setMaximum(0x1D1); + widthSpinBox->setValue(editor->map->getWidth()); + heightSpinBox->setValue(editor->map->getHeight()); + form.addRow(new QLabel("Width"), widthSpinBox); + form.addRow(new QLabel("Height"), heightSpinBox); + + QLabel *errorLabel = new QLabel(); + QPalette errorPalette; + errorPalette.setColor(QPalette::WindowText, Qt::red); + errorLabel->setPalette(errorPalette); + errorLabel->setVisible(false); + + QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog); + form.addRow(&buttonBox); + connect(&buttonBox, &QDialogButtonBox::accepted, [&dialog, &widthSpinBox, &heightSpinBox, &errorLabel](){ + // Ensure width and height are an acceptable size. + // The maximum number of metatiles in a map is the following: + // max = (width + 15) * (height + 14) + // This limit can be found in fieldmap.c in pokeruby/pokeemerald. + int realWidth = widthSpinBox->value() + 15; + int realHeight = heightSpinBox->value() + 14; + int numMetatiles = realWidth * realHeight; + if (numMetatiles <= 0x2800) { + dialog.accept(); + } else { + QString errorText = QString("Error: The specified width and height are too large.\n" + "The maximum width and height is the following: (width + 15) * (height + 14) <= 10240\n" + "The specified width and height was: (%1 + 15) * (%2 + 14) = %3") + .arg(widthSpinBox->value()) + .arg(heightSpinBox->value()) + .arg(numMetatiles); + errorLabel->setText(errorText); + errorLabel->setVisible(true); + } + }); + connect(&buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject())); + + form.addRow(errorLabel); + + if (dialog.exec() == QDialog::Accepted) { + editor->map->setDimensions(widthSpinBox->value(), heightSpinBox->value()); + editor->map->commit(); + onMapNeedsRedrawing(); + } +} + +void MainWindow::on_checkBox_smartPaths_stateChanged(int selected) +{ + editor->settings->smartPathsEnabled = selected == Qt::Checked; +} + +void MainWindow::on_checkBox_ToggleBorder_stateChanged(int selected) +{ + bool visible = selected != 0; + editor->toggleBorderVisibility(visible); +} diff --git a/mainwindow.h b/src/mainwindow.h old mode 100755 new mode 100644 similarity index 96% rename from mainwindow.h rename to src/mainwindow.h index 30e48fdf..9b39debe --- a/mainwindow.h +++ b/src/mainwindow.h @@ -1,157 +1,157 @@ -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -#include <QString> -#include <QModelIndex> -#include <QMainWindow> -#include <QStandardItemModel> -#include <QGraphicsPixmapItem> -#include <QGraphicsItemGroup> -#include <QGraphicsSceneMouseEvent> -#include <QAbstractItemModel> -#include "project.h" -#include "map.h" -#include "editor.h" - -namespace Ui { -class MainWindow; -} - -class MainWindow : public QMainWindow -{ - Q_OBJECT - -public: - explicit MainWindow(QWidget *parent = nullptr); - ~MainWindow(); - -private slots: - void on_action_Open_Project_triggered(); - void on_mapList_activated(const QModelIndex &index); - void on_action_Save_Project_triggered(); - void openWarpMap(QString map_name, QString warp_num); - - void undo(); - void redo(); - - void openInTextEditor(); - - void onLoadMapRequested(QString, QString); - void onMapChanged(Map *map); - void onMapNeedsRedrawing(); - - void on_action_Save_triggered(); - void on_tabWidget_2_currentChanged(int index); - void on_action_Exit_triggered(); - void on_comboBox_Song_activated(const QString &arg1); - void on_comboBox_Location_activated(const QString &arg1); - void on_comboBox_Visibility_activated(const QString &arg1); - void on_comboBox_Weather_activated(const QString &arg1); - void on_comboBox_Type_activated(const QString &arg1); - void on_comboBox_BattleScene_activated(const QString &arg1); - void on_checkBox_ShowLocation_clicked(bool checked); - - void on_tabWidget_currentChanged(int index); - - void on_actionUndo_triggered(); - - void on_actionRedo_triggered(); - - void on_actionZoom_In_triggered(); - void on_actionZoom_Out_triggered(); - void on_actionBetter_Cursors_triggered(); - void on_actionPencil_triggered(); - void on_actionPointer_triggered(); - void on_actionFlood_Fill_triggered(); - void on_actionEyedropper_triggered(); - void on_actionMove_triggered(); - void on_actionMap_Shift_triggered(); - - void on_toolButton_deleteObject_clicked(); - void on_toolButton_Open_Scripts_clicked(); - - void addNewEvent(QString); - void updateSelectedObjects(); - - void on_toolButton_Paint_clicked(); - - void on_toolButton_Select_clicked(); - - void on_toolButton_Fill_clicked(); - - void on_toolButton_Dropper_clicked(); - - void on_toolButton_Move_clicked(); - - void on_toolButton_Shift_clicked(); - - void onOpenMapListContextMenu(const QPoint &point); - void onAddNewMapToGroupClick(QAction* triggeredAction); - void onTilesetChanged(QString); - void currentMetatilesSelectionChanged(); - - void on_action_Export_Map_Image_triggered(); - - void on_comboBox_ConnectionDirection_currentIndexChanged(const QString &arg1); - - void on_spinBox_ConnectionOffset_valueChanged(int offset); - - void on_comboBox_ConnectedMap_currentTextChanged(const QString &mapName); - - void on_pushButton_AddConnection_clicked(); - - void on_pushButton_RemoveConnection_clicked(); - - void on_comboBox_DiveMap_currentTextChanged(const QString &mapName); - - void on_comboBox_EmergeMap_currentTextChanged(const QString &mapName); - - void on_comboBox_PrimaryTileset_activated(const QString &arg1); - - void on_comboBox_SecondaryTileset_activated(const QString &arg1); - - void on_pushButton_clicked(); - - void on_checkBox_smartPaths_stateChanged(int selected); - - void on_checkBox_Visibility_clicked(bool checked); - - void on_checkBox_ToggleBorder_stateChanged(int arg1); - -private: - Ui::MainWindow *ui; - QStandardItemModel *mapListModel; - QList<QStandardItem*> *mapGroupsModel; - Editor *editor = nullptr; - QIcon* mapIcon; - void setMap(QString); - void redrawMapScene(); - void loadDataStructures(); - void populateMapList(); - QString getExistingDirectory(QString); - void openProject(QString dir); - QString getDefaultMap(); - void setRecentMap(QString map_name); - QStandardItem* createMapItem(QString mapName, int groupNum, int inGroupNum); - - void markAllEdited(QAbstractItemModel *model); - void markEdited(QModelIndex index); - void updateMapList(); - - void displayMapProperties(); - void checkToolButtons(); - - void scaleMapView(int); - void initExtraShortcuts(); - void initExtraSignals(); - void initEditor(); - void loadUserSettings(); - void openRecentProject(); -}; - -enum MapListUserRoles { - GroupRole = Qt::UserRole + 1, // Used to hold the map group number. - TypeRole = Qt::UserRole + 2, // Used to differentiate between the different layers of the map list tree view. -}; - -#endif // MAINWINDOW_H +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <QString> +#include <QModelIndex> +#include <QMainWindow> +#include <QStandardItemModel> +#include <QGraphicsPixmapItem> +#include <QGraphicsItemGroup> +#include <QGraphicsSceneMouseEvent> +#include <QAbstractItemModel> +#include "project.h" +#include "map.h" +#include "editor.h" + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + +private slots: + void on_action_Open_Project_triggered(); + void on_mapList_activated(const QModelIndex &index); + void on_action_Save_Project_triggered(); + void openWarpMap(QString map_name, QString warp_num); + + void undo(); + void redo(); + + void openInTextEditor(); + + void onLoadMapRequested(QString, QString); + void onMapChanged(Map *map); + void onMapNeedsRedrawing(); + + void on_action_Save_triggered(); + void on_tabWidget_2_currentChanged(int index); + void on_action_Exit_triggered(); + void on_comboBox_Song_activated(const QString &arg1); + void on_comboBox_Location_activated(const QString &arg1); + void on_comboBox_Visibility_activated(const QString &arg1); + void on_comboBox_Weather_activated(const QString &arg1); + void on_comboBox_Type_activated(const QString &arg1); + void on_comboBox_BattleScene_activated(const QString &arg1); + void on_checkBox_ShowLocation_clicked(bool checked); + + void on_tabWidget_currentChanged(int index); + + void on_actionUndo_triggered(); + + void on_actionRedo_triggered(); + + void on_actionZoom_In_triggered(); + void on_actionZoom_Out_triggered(); + void on_actionBetter_Cursors_triggered(); + void on_actionPencil_triggered(); + void on_actionPointer_triggered(); + void on_actionFlood_Fill_triggered(); + void on_actionEyedropper_triggered(); + void on_actionMove_triggered(); + void on_actionMap_Shift_triggered(); + + void on_toolButton_deleteObject_clicked(); + void on_toolButton_Open_Scripts_clicked(); + + void addNewEvent(QString); + void updateSelectedObjects(); + + void on_toolButton_Paint_clicked(); + + void on_toolButton_Select_clicked(); + + void on_toolButton_Fill_clicked(); + + void on_toolButton_Dropper_clicked(); + + void on_toolButton_Move_clicked(); + + void on_toolButton_Shift_clicked(); + + void onOpenMapListContextMenu(const QPoint &point); + void onAddNewMapToGroupClick(QAction* triggeredAction); + void onTilesetChanged(QString); + void currentMetatilesSelectionChanged(); + + void on_action_Export_Map_Image_triggered(); + + void on_comboBox_ConnectionDirection_currentIndexChanged(const QString &arg1); + + void on_spinBox_ConnectionOffset_valueChanged(int offset); + + void on_comboBox_ConnectedMap_currentTextChanged(const QString &mapName); + + void on_pushButton_AddConnection_clicked(); + + void on_pushButton_RemoveConnection_clicked(); + + void on_comboBox_DiveMap_currentTextChanged(const QString &mapName); + + void on_comboBox_EmergeMap_currentTextChanged(const QString &mapName); + + void on_comboBox_PrimaryTileset_activated(const QString &arg1); + + void on_comboBox_SecondaryTileset_activated(const QString &arg1); + + void on_pushButton_clicked(); + + void on_checkBox_smartPaths_stateChanged(int selected); + + void on_checkBox_Visibility_clicked(bool checked); + + void on_checkBox_ToggleBorder_stateChanged(int arg1); + +private: + Ui::MainWindow *ui; + QStandardItemModel *mapListModel; + QList<QStandardItem*> *mapGroupsModel; + Editor *editor = nullptr; + QIcon* mapIcon; + void setMap(QString); + void redrawMapScene(); + void loadDataStructures(); + void populateMapList(); + QString getExistingDirectory(QString); + void openProject(QString dir); + QString getDefaultMap(); + void setRecentMap(QString map_name); + QStandardItem* createMapItem(QString mapName, int groupNum, int inGroupNum); + + void markAllEdited(QAbstractItemModel *model); + void markEdited(QModelIndex index); + void updateMapList(); + + void displayMapProperties(); + void checkToolButtons(); + + void scaleMapView(int); + void initExtraShortcuts(); + void initExtraSignals(); + void initEditor(); + void loadUserSettings(); + void openRecentProject(); +}; + +enum MapListUserRoles { + GroupRole = Qt::UserRole + 1, // Used to hold the map group number. + TypeRole = Qt::UserRole + 2, // Used to differentiate between the different layers of the map list tree view. +}; + +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/src/mainwindow.ui old mode 100755 new mode 100644 similarity index 97% rename from mainwindow.ui rename to src/mainwindow.ui index 36600ee5..a01fb7c4 --- a/mainwindow.ui +++ b/src/mainwindow.ui @@ -1,2294 +1,2294 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>MainWindow</class> - <widget class="QMainWindow" name="MainWindow"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>1117</width> - <height>747</height> - </rect> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="windowTitle"> - <string>porymap</string> - </property> - <widget class="QWidget" name="centralWidget"> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0"> - <widget class="QSplitter" name="splitter"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <widget class="QTreeView" name="mapList"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>100</width> - <height>0</height> - </size> - </property> - <property name="selectionMode"> - <enum>QAbstractItemView::SingleSelection</enum> - </property> - <property name="selectionBehavior"> - <enum>QAbstractItemView::SelectItems</enum> - </property> - <attribute name="headerVisible"> - <bool>false</bool> - </attribute> - </widget> - <widget class="QTabWidget" name="tabWidget"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>1</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="currentIndex"> - <number>0</number> - </property> - <property name="tabsClosable"> - <bool>false</bool> - </property> - <property name="movable"> - <bool>false</bool> - </property> - <widget class="QWidget" name="tab_Map"> - <property name="toolTip"> - <string/> - </property> - <attribute name="icon"> - <iconset resource="resources/images.qrc"> - <normaloff>:/icons/map.ico</normaloff>:/icons/map.ico</iconset> - </attribute> - <attribute name="title"> - <string>Map</string> - </attribute> - <attribute name="toolTip"> - <string><html><head/><body><p>Edit the map layout.</p><p>Select metatiles or collision attributes from the right panel, and paint them onto the map.</p></body></html></string> - </attribute> - <layout class="QGridLayout" name="gridLayout_9"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <property name="verticalSpacing"> - <number>6</number> - </property> - <item row="0" column="0"> - <widget class="QSplitter" name="splitter_2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <widget class="QFrame" name="frame_9"> - <property name="frameShape"> - <enum>QFrame::StyledPanel</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <property name="lineWidth"> - <number>1</number> - </property> - <layout class="QGridLayout" name="gridLayout_4"> - <property name="leftMargin"> - <number>3</number> - </property> - <property name="topMargin"> - <number>3</number> - </property> - <property name="rightMargin"> - <number>3</number> - </property> - <property name="bottomMargin"> - <number>3</number> - </property> - <property name="spacing"> - <number>6</number> - </property> - <item row="0" column="0"> - <widget class="QFrame" name="frame_6"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>0</width> - <height>32</height> - </size> - </property> - <property name="frameShape"> - <enum>QFrame::StyledPanel</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <property name="spacing"> - <number>4</number> - </property> - <property name="leftMargin"> - <number>4</number> - </property> - <property name="topMargin"> - <number>4</number> - </property> - <property name="rightMargin"> - <number>4</number> - </property> - <property name="bottomMargin"> - <number>4</number> - </property> - <item> - <widget class="QToolButton" name="toolButton_Paint"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="toolTip"> - <string><html><head/><body><p>Pencil</p><p><span style=" font-weight:600;">Click</span> and drag to draw on the map.</p><p><span style=" font-weight:600;">Right-click</span> and drag to select tiles.</p></body></html></string> - </property> - <property name="text"> - <string>Paint</string> - </property> - <property name="icon"> - <iconset resource="resources/images.qrc"> - <normaloff>:/icons/pencil.ico</normaloff>:/icons/pencil.ico</iconset> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - <property name="checked"> - <bool>true</bool> - </property> - <property name="autoRaise"> - <bool>false</bool> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="toolButton_Select"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="toolTip"> - <string><html><head/><body><p>Pointer</p><p>Does nothing</p></body></html></string> - </property> - <property name="text"> - <string>Select</string> - </property> - <property name="icon"> - <iconset resource="resources/images.qrc"> - <normaloff>:/icons/cursor.ico</normaloff>:/icons/cursor.ico</iconset> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="toolButton_Fill"> - <property name="toolTip"> - <string><html><head/><body><p>Bucket Fill</p><p>Fills all similar tiles in a region with the selected metatiles or collision attributes</p></body></html></string> - </property> - <property name="text"> - <string>Fill</string> - </property> - <property name="icon"> - <iconset resource="resources/images.qrc"> - <normaloff>:/icons/fill_color.ico</normaloff>:/icons/fill_color.ico</iconset> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="toolButton_Dropper"> - <property name="toolTip"> - <string><html><head/><body><p>Eyedropper</p><p><span style=" font-weight:600;">Click</span> to select a metatile or collision attribute.</p></body></html></string> - </property> - <property name="text"> - <string>Dropper</string> - </property> - <property name="icon"> - <iconset resource="resources/images.qrc"> - <normaloff>:/icons/pipette.ico</normaloff>:/icons/pipette.ico</iconset> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="toolButton_Move"> - <property name="toolTip"> - <string><html><head/><body><p>Move</p><p>Click to drag map around.</p></body></html></string> - </property> - <property name="text"> - <string>...</string> - </property> - <property name="icon"> - <iconset resource="resources/images.qrc"> - <normaloff>:/icons/move.ico</normaloff>:/icons/move.ico</iconset> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="toolButton_Shift"> - <property name="toolTip"> - <string><html><head/><body><p>Map Shift</p><p><span style=" font-weight:600;">Click and drag</span> on the map to shift the positions all metatiles at once. This is useful after resizing a map.</p></body></html></string> - </property> - <property name="text"> - <string>Shift</string> - </property> - <property name="icon"> - <iconset resource="resources/images.qrc"> - <normaloff>:/icons/shift.ico</normaloff>:/icons/shift.ico</iconset> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="checkBox_smartPaths"> - <property name="toolTip"> - <string><html><head/><body><p>Smart-path mode allows easier drawing of paths. If a 3x3 metatile block is selcted in the right panel, then smart path mode will automatically form a pathway using those selected blocks.</p><p>When smart-path mode is <span style=" font-weight:600;">not</span> enabled, clicking and dragging a selection will tile it in a grid.</p><p>Hold down the <span style=" font-weight:600;">shift</span> key while editing to quickly enable smart-path mode.</p></body></html></string> - </property> - <property name="styleSheet"> - <string notr="true">margin-left: 10px</string> - </property> - <property name="text"> - <string>Smart Paths</string> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="checkBox_ToggleGrid"> - <property name="toolTip"> - <string><html><head/><body><p>Toggles a grid over the map's metatile boundaries.</p></body></html></string> - </property> - <property name="styleSheet"> - <string notr="true"/> - </property> - <property name="text"> - <string>Grid</string> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="checkBox_ToggleBorder"> - <property name="text"> - <string>Border</string> - </property> - <property name="checked"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="pushButton"> - <property name="toolTip"> - <string><html><head/><body><p>Change a map layout's width and height.</p></body></html></string> - </property> - <property name="text"> - <string>Change Dimensions</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item row="1" column="0"> - <widget class="QFrame" name="frame_7"> - <property name="frameShape"> - <enum>QFrame::StyledPanel</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QGridLayout" name="gridLayout_2"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item row="0" column="0"> - <widget class="QScrollArea" name="scrollArea"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>1</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="widgetResizable"> - <bool>true</bool> - </property> - <widget class="QWidget" name="scrollAreaWidgetContents_5"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>469</width> - <height>608</height> - </rect> - </property> - <layout class="QGridLayout" name="gridLayout_8"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <property name="spacing"> - <number>0</number> - </property> - <item row="1" column="1"> - <widget class="QGraphicsView" name="graphicsView_Map"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="mouseTracking"> - <bool>false</bool> - </property> - <property name="autoFillBackground"> - <bool>false</bool> - </property> - <property name="sizeAdjustPolicy"> - <enum>QAbstractScrollArea::AdjustIgnored</enum> - </property> - <property name="dragMode"> - <enum>QGraphicsView::NoDrag</enum> - </property> - </widget> - </item> - <item row="1" column="0"> - <spacer name="horizontalSpacer_4"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>166</width> - <height>16</height> - </size> - </property> - </spacer> - </item> - <item row="2" column="1"> - <spacer name="verticalSpacer_3"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>16</width> - <height>166</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="2"> - <spacer name="horizontalSpacer_5"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>166</width> - <height>16</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="1"> - <spacer name="verticalSpacer_4"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>16</width> - <height>166</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - <widget class="QFrame" name="frame_8"> - <property name="frameShape"> - <enum>QFrame::StyledPanel</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QVBoxLayout" name="verticalLayout_6"> - <property name="leftMargin"> - <number>3</number> - </property> - <property name="topMargin"> - <number>3</number> - </property> - <property name="rightMargin"> - <number>3</number> - </property> - <property name="bottomMargin"> - <number>3</number> - </property> - <item> - <widget class="QTabWidget" name="tabWidget_2"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>156</width> - <height>0</height> - </size> - </property> - <property name="currentIndex"> - <number>0</number> - </property> - <widget class="QWidget" name="tab_blocks"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <attribute name="title"> - <string>Metatiles</string> - </attribute> - <layout class="QGridLayout" name="gridLayout_3"> - <property name="leftMargin"> - <number>3</number> - </property> - <property name="topMargin"> - <number>3</number> - </property> - <property name="rightMargin"> - <number>3</number> - </property> - <property name="bottomMargin"> - <number>3</number> - </property> - <property name="spacing"> - <number>3</number> - </property> - <item row="0" column="0"> - <widget class="QFrame" name="frame_Tilesets"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShape"> - <enum>QFrame::StyledPanel</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QFormLayout" name="formLayout"> - <item row="0" column="0"> - <widget class="QLabel" name="label_PrimaryTileset"> - <property name="text"> - <string>Primary Tileset</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="NoScrollComboBox" name="comboBox_PrimaryTileset"> - <property name="focusPolicy"> - <enum>Qt::StrongFocus</enum> - </property> - <property name="toolTip"> - <string><html><head/><body><p>Primary Tileset</p><p>Defines the first 0x200 metatiles available for the map.</p></body></html></string> - </property> - <property name="editable"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_SecondaryTileset"> - <property name="text"> - <string>Secondary Tileset</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="NoScrollComboBox" name="comboBox_SecondaryTileset"> - <property name="focusPolicy"> - <enum>Qt::StrongFocus</enum> - </property> - <property name="toolTip"> - <string><html><head/><body><p>Secondary Tileset</p><p>Defines the second 0x200 metatiles available for the map.</p></body></html></string> - </property> - <property name="editable"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item row="2" column="0"> - <widget class="QFrame" name="frame_currentMetatileSelection"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>0</width> - <height>92</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>16777215</width> - <height>92</height> - </size> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QHBoxLayout" name="horizontalLayout_5"> - <property name="spacing"> - <number>0</number> - </property> - <property name="sizeConstraint"> - <enum>QLayout::SetDefaultConstraint</enum> - </property> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QGroupBox" name="groupBox_2"> - <property name="title"> - <string>Selection</string> - </property> - <layout class="QGridLayout" name="gridLayout_17"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <property name="spacing"> - <number>0</number> - </property> - <item row="0" column="0"> - <widget class="QScrollArea" name="scrollArea_6"> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="widgetResizable"> - <bool>true</bool> - </property> - <widget class="QWidget" name="scrollAreaWidgetContents_6"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>324</width> - <height>77</height> - </rect> - </property> - <layout class="QHBoxLayout" name="horizontalLayout_7"> - <property name="spacing"> - <number>0</number> - </property> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <spacer name="horizontalSpacer_16"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QGraphicsView" name="graphicsView_currentMetatileSelection"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="maximumSize"> - <size> - <width>16777215</width> - <height>16777215</height> - </size> - </property> - <property name="verticalScrollBarPolicy"> - <enum>Qt::ScrollBarAlwaysOff</enum> - </property> - <property name="horizontalScrollBarPolicy"> - <enum>Qt::ScrollBarAlwaysOff</enum> - </property> - <property name="interactive"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_17"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - </item> - <item row="3" column="0"> - <widget class="QScrollArea" name="scrollArea_2"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="verticalScrollBarPolicy"> - <enum>Qt::ScrollBarAlwaysOn</enum> - </property> - <property name="horizontalScrollBarPolicy"> - <enum>Qt::ScrollBarAsNeeded</enum> - </property> - <property name="sizeAdjustPolicy"> - <enum>QAbstractScrollArea::AdjustIgnored</enum> - </property> - <property name="widgetResizable"> - <bool>true</bool> - </property> - <property name="alignment"> - <set>Qt::AlignHCenter|Qt::AlignTop</set> - </property> - <widget class="QWidget" name="scrollAreaWidgetContents_2"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>307</width> - <height>387</height> - </rect> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <layout class="QGridLayout" name="gridLayout_5"> - <property name="sizeConstraint"> - <enum>QLayout::SetDefaultConstraint</enum> - </property> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <property name="spacing"> - <number>0</number> - </property> - <item row="1" column="1"> - <spacer name="verticalSpacer_5"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="1"> - <widget class="QGraphicsView" name="graphicsView_Metatiles"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="verticalScrollBarPolicy"> - <enum>Qt::ScrollBarAlwaysOff</enum> - </property> - <property name="horizontalScrollBarPolicy"> - <enum>Qt::ScrollBarAlwaysOff</enum> - </property> - <property name="sizeAdjustPolicy"> - <enum>QAbstractScrollArea::AdjustIgnored</enum> - </property> - </widget> - </item> - <item row="0" column="0"> - <spacer name="horizontalSpacer_14"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="2"> - <spacer name="horizontalSpacer_15"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </widget> - </item> - <item row="1" column="0"> - <widget class="QGroupBox" name="groupBox"> - <property name="title"> - <string>Border</string> - </property> - <layout class="QGridLayout" name="gridLayout_16"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <property name="spacing"> - <number>0</number> - </property> - <item row="0" column="1"> - <widget class="QGraphicsView" name="graphicsView_BorderMetatile"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="maximumSize"> - <size> - <width>16777215</width> - <height>48</height> - </size> - </property> - <property name="toolTip"> - <string><html><head/><body><p>The border is a 2x2 metatile which is repeated outside of the map layout's boundary. Draw on this border area to modify it.</p></body></html></string> - </property> - <property name="frameShape"> - <enum>QFrame::StyledPanel</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Sunken</enum> - </property> - <property name="verticalScrollBarPolicy"> - <enum>Qt::ScrollBarAsNeeded</enum> - </property> - </widget> - </item> - <item row="0" column="0"> - <spacer name="horizontalSpacer_12"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="2"> - <spacer name="horizontalSpacer_13"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - <widget class="QWidget" name="tab_collision"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <attribute name="title"> - <string>Collision</string> - </attribute> - <layout class="QGridLayout" name="gridLayout_CollisionSelection"> - <property name="sizeConstraint"> - <enum>QLayout::SetDefaultConstraint</enum> - </property> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item row="0" column="1"> - <widget class="QGraphicsView" name="graphicsView_Collision"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>64</width> - <height>512</height> - </size> - </property> - </widget> - </item> - <item row="0" column="0"> - <spacer name="horizontalSpacer_18"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="2"> - <spacer name="horizontalSpacer_19"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="1"> - <spacer name="verticalSpacer_6"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </widget> - </item> - </layout> - </widget> - </widget> - </item> - </layout> - </widget> - <widget class="QWidget" name="tab_Objects"> - <property name="enabled"> - <bool>true</bool> - </property> - <attribute name="title"> - <string>Events</string> - </attribute> - <attribute name="toolTip"> - <string><html><head/><body><p>Edit the map's events.</p><p>View and modify objects, warps, signs, etc.</p></body></html></string> - </attribute> - <layout class="QGridLayout" name="gridLayout_10"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item row="0" column="0"> - <widget class="QSplitter" name="splitter_3"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <widget class="QScrollArea" name="scrollArea_3"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>1</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="widgetResizable"> - <bool>true</bool> - </property> - <widget class="QWidget" name="scrollAreaWidgetContents_4"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>381</width> - <height>657</height> - </rect> - </property> - <layout class="QGridLayout" name="gridLayout_7"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <property name="spacing"> - <number>0</number> - </property> - <item row="1" column="2"> - <spacer name="horizontalSpacer_Objects_Map_right"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>166</width> - <height>16</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="0"> - <spacer name="horizontalSpacer_Objects_Map_left"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>166</width> - <height>16</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="1"> - <spacer name="verticalSpacer_Objects_Map_top"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>16</width> - <height>166</height> - </size> - </property> - </spacer> - </item> - <item row="2" column="1"> - <spacer name="verticalSpacer_Objects_Map_bottom"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>16</width> - <height>166</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="1"> - <widget class="GraphicsView" name="graphicsView_Objects_Map"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - </widget> - </item> - </layout> - </widget> - </widget> - <widget class="QFrame" name="frame_Objects"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>444</width> - <height>0</height> - </size> - </property> - <layout class="QGridLayout" name="gridLayout_6"> - <property name="leftMargin"> - <number>3</number> - </property> - <property name="topMargin"> - <number>3</number> - </property> - <property name="rightMargin"> - <number>3</number> - </property> - <property name="bottomMargin"> - <number>3</number> - </property> - <item row="1" column="0"> - <widget class="QGroupBox" name="groupBox_selectedObjects"> - <property name="title"> - <string>Selected</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <property name="spacing"> - <number>6</number> - </property> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QFrame" name="frame_5"> - <property name="frameShape"> - <enum>QFrame::StyledPanel</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QScrollArea" name="scrollArea_4"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="sizeAdjustPolicy"> - <enum>QAbstractScrollArea::AdjustIgnored</enum> - </property> - <property name="widgetResizable"> - <bool>true</bool> - </property> - <property name="alignment"> - <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> - </property> - <widget class="QWidget" name="scrollAreaWidgetContents"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>432</width> - <height>596</height> - </rect> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - </widget> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - </item> - <item row="0" column="0"> - <widget class="QFrame" name="frame_4"> - <property name="maximumSize"> - <size> - <width>16777215</width> - <height>32</height> - </size> - </property> - <property name="frameShape"> - <enum>QFrame::StyledPanel</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QHBoxLayout" name="horizontalLayout"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="NewEventToolButton" name="newEventToolButton"> - <property name="minimumSize"> - <size> - <width>40</width> - <height>32</height> - </size> - </property> - <property name="toolTip"> - <string><html><head/><body><p>Add a new event to the map.</p></body></html></string> - </property> - <property name="text"> - <string>New Object</string> - </property> - <property name="icon"> - <iconset resource="resources/images.qrc"> - <normaloff>:/icons/add.ico</normaloff>:/icons/add.ico</iconset> - </property> - <property name="toolButtonStyle"> - <enum>Qt::ToolButtonTextBesideIcon</enum> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="toolButton_deleteObject"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>40</width> - <height>32</height> - </size> - </property> - <property name="toolTip"> - <string><html><head/><body><p>Delete the selected event from the map.</p></body></html></string> - </property> - <property name="text"> - <string>Delete</string> - </property> - <property name="icon"> - <iconset resource="resources/images.qrc"> - <normaloff>:/icons/delete.ico</normaloff>:/icons/delete.ico</iconset> - </property> - <property name="toolButtonStyle"> - <enum>Qt::ToolButtonTextBesideIcon</enum> - </property> - <property name="autoRaise"> - <bool>false</bool> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_3"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QToolButton" name="toolButton_Open_Scripts"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Open Map Scripts</string> - </property> - <property name="autoRaise"> - <bool>false</bool> - </property> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - </widget> - </item> - </layout> - </widget> - <widget class="QWidget" name="tab_Attributes"> - <attribute name="title"> - <string>Header</string> - </attribute> - <widget class="QFrame" name="frame_3"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="geometry"> - <rect> - <x>10</x> - <y>10</y> - <width>381</width> - <height>311</height> - </rect> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShape"> - <enum>QFrame::StyledPanel</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QFormLayout" name="formLayout_2"> - <property name="verticalSpacing"> - <number>12</number> - </property> - <item row="0" column="0"> - <widget class="QLabel" name="label_3"> - <property name="text"> - <string>Song</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QComboBox" name="comboBox_Song"> - <property name="toolTip"> - <string><html><head/><body><p>The default background music for this map.</p></body></html></string> - </property> - <property name="editable"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_4"> - <property name="text"> - <string>Location</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QComboBox" name="comboBox_Location"> - <property name="toolTip"> - <string><html><head/><body><p>The section of the region map which the map is grouped under. This also determines the name of the map that is display when the player enters it.</p></body></html></string> - </property> - <property name="editable"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_5"> - <property name="text"> - <string>Requires Flash</string> - </property> - </widget> - </item> - <item row="3" column="0"> - <widget class="QLabel" name="label_6"> - <property name="text"> - <string>Weather</string> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="QComboBox" name="comboBox_Weather"> - <property name="toolTip"> - <string><html><head/><body><p>The default weather for this map.</p></body></html></string> - </property> - <property name="editable"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="4" column="0"> - <widget class="QLabel" name="label_7"> - <property name="text"> - <string>Type</string> - </property> - </widget> - </item> - <item row="4" column="1"> - <widget class="QComboBox" name="comboBox_Type"> - <property name="toolTip"> - <string><html><head/><body><p>The map type is a general attribute, which is used for many different things. For example. it determines whether biking or running is allowed.</p></body></html></string> - </property> - <property name="editable"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="5" column="0"> - <widget class="QLabel" name="label_8"> - <property name="text"> - <string>Show Location Name</string> - </property> - </widget> - </item> - <item row="5" column="1"> - <widget class="QCheckBox" name="checkBox_ShowLocation"> - <property name="toolTip"> - <string><html><head/><body><p>Whether or not to display the location name when the player enters the map.</p></body></html></string> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item row="6" column="0"> - <widget class="QLabel" name="label_9"> - <property name="text"> - <string>Battle scene</string> - </property> - </widget> - </item> - <item row="6" column="1"> - <widget class="QComboBox" name="comboBox_BattleScene"> - <property name="toolTip"> - <string><html><head/><body><p>Determines the type of battle scene graphics to use.</p></body></html></string> - </property> - <property name="editable"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QCheckBox" name="checkBox_Visibility"> - <property name="toolTip"> - <string><html><head/><body><p>Whether or not the map is dark and requires Flash to illuminate.</p></body></html></string> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </widget> - </widget> - <widget class="QWidget" name="tab_Connections"> - <attribute name="title"> - <string>Connections</string> - </attribute> - <layout class="QGridLayout" name="gridLayout_12"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item row="3" column="0"> - <widget class="QFrame" name="gridFrame"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShape"> - <enum>QFrame::StyledPanel</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QGridLayout" name="gridLayout_11"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <property name="spacing"> - <number>0</number> - </property> - <item row="1" column="0"> - <widget class="QFrame" name="horizontalFrame"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>0</width> - <height>32</height> - </size> - </property> - <property name="frameShape"> - <enum>QFrame::StyledPanel</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QHBoxLayout" name="horizontalLayout_4"> - <property name="spacing"> - <number>4</number> - </property> - <property name="leftMargin"> - <number>4</number> - </property> - <property name="topMargin"> - <number>4</number> - </property> - <property name="rightMargin"> - <number>4</number> - </property> - <property name="bottomMargin"> - <number>4</number> - </property> - <item> - <widget class="QPushButton" name="pushButton_AddConnection"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string><html><head/><body><p>Add a new connection.</p></body></html></string> - </property> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset> - <activeon>:/icons/add.ico</activeon> - </iconset> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="pushButton_RemoveConnection"> - <property name="toolTip"> - <string><html><head/><body><p>Remove the currently-selected connection.</p></body></html></string> - </property> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset> - <activeon>:/icons/delete.ico</activeon> - </iconset> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="label_13"> - <property name="text"> - <string>Number of Connections:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="label_NumConnections"> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_11"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Expanding</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QCheckBox" name="checkBox_MirrorConnections"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string><html><head/><body><p>If enabled, connections will automatically be updated on the connected map.</p></body></html></string> - </property> - <property name="text"> - <string>Mirror to Connecting Maps</string> - </property> - <property name="checked"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item row="2" column="0"> - <widget class="QFrame" name="horizontalFrame"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>0</width> - <height>32</height> - </size> - </property> - <property name="frameShape"> - <enum>QFrame::StyledPanel</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,0,0,0,0,0"> - <property name="spacing"> - <number>6</number> - </property> - <property name="leftMargin"> - <number>4</number> - </property> - <property name="topMargin"> - <number>4</number> - </property> - <property name="rightMargin"> - <number>4</number> - </property> - <property name="bottomMargin"> - <number>4</number> - </property> - <item> - <widget class="QLabel" name="label_11"> - <property name="text"> - <string>Map</string> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="comboBox_ConnectedMap"> - <property name="toolTip"> - <string><html><head/><body><p>The destination map name of the connection.</p></body></html></string> - </property> - <property name="editable"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="label_12"> - <property name="text"> - <string>Offset</string> - </property> - </widget> - </item> - <item> - <widget class="QSpinBox" name="spinBox_ConnectionOffset"> - <property name="toolTip"> - <string><html><head/><body><p>The number of metatiles to offset the connection.</p></body></html></string> - </property> - <property name="minimum"> - <number>-999</number> - </property> - <property name="maximum"> - <number>999</number> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="comboBox_ConnectionDirection"> - <property name="toolTip"> - <string><html><head/><body><p>The direction of the connection.</p></body></html></string> - </property> - <item> - <property name="text"> - <string>up</string> - </property> - </item> - <item> - <property name="text"> - <string>right</string> - </property> - </item> - <item> - <property name="text"> - <string>down</string> - </property> - </item> - <item> - <property name="text"> - <string>left</string> - </property> - </item> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_6"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </item> - <item row="3" column="0"> - <widget class="QFrame" name="gridFrame"> - <property name="frameShape"> - <enum>QFrame::StyledPanel</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QGridLayout" name="gridLayout_13"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <property name="spacing"> - <number>0</number> - </property> - <item row="1" column="0"> - <widget class="QScrollArea" name="scrollArea_5"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>1</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="widgetResizable"> - <bool>true</bool> - </property> - <widget class="QWidget" name="scrollAreaWidgetContents_3"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>826</width> - <height>557</height> - </rect> - </property> - <layout class="QGridLayout" name="gridLayout_14"> - <item row="1" column="2"> - <spacer name="horizontalSpacer_8"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="2" column="1"> - <spacer name="verticalSpacer_2"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="1"> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="1"> - <widget class="QGraphicsView" name="graphicsView_Connections"> - <property name="backgroundBrush"> - <brush brushstyle="SolidPattern"> - <color alpha="255"> - <red>0</red> - <green>0</green> - <blue>0</blue> - </color> - </brush> - </property> - </widget> - </item> - <item row="1" column="0"> - <spacer name="horizontalSpacer_7"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </widget> - </item> - <item row="0" column="0"> - <widget class="QFrame" name="horizontalFrame"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShape"> - <enum>QFrame::StyledPanel</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QHBoxLayout" name="horizontalLayout_6"> - <property name="spacing"> - <number>4</number> - </property> - <property name="leftMargin"> - <number>4</number> - </property> - <property name="topMargin"> - <number>4</number> - </property> - <property name="rightMargin"> - <number>4</number> - </property> - <property name="bottomMargin"> - <number>4</number> - </property> - <item> - <widget class="QLabel" name="label_14"> - <property name="text"> - <string>Dive Map</string> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="comboBox_DiveMap"> - <property name="toolTip"> - <string><html><head/><body><p>Destination map name when using <span style=" font-weight:600;">Dive</span>. If empty, no such connection will exist.</p></body></html></string> - </property> - <property name="editable"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="label_15"> - <property name="text"> - <string>Emerge Map</string> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="comboBox_EmergeMap"> - <property name="toolTip"> - <string><html><head/><body><p>Destination map name when emerging using <span style=" font-weight:600;">Dive</span>. If empty, no such connection will exist.</p></body></html></string> - </property> - <property name="editable"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_10"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - </widget> - </widget> - </item> - </layout> - </widget> - <widget class="QMenuBar" name="menuBar"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>1117</width> - <height>21</height> - </rect> - </property> - <widget class="QMenu" name="menuFile"> - <property name="title"> - <string>File</string> - </property> - <addaction name="action_Open_Project"/> - <addaction name="action_Save"/> - <addaction name="action_Save_Project"/> - <addaction name="separator"/> - <addaction name="action_Export_Map_Image"/> - <addaction name="separator"/> - <addaction name="action_Exit"/> - </widget> - <widget class="QMenu" name="menuEdit"> - <property name="title"> - <string>Edit</string> - </property> - <addaction name="actionUndo"/> - <addaction name="actionRedo"/> - </widget> - <widget class="QMenu" name="menuView"> - <property name="title"> - <string>View</string> - </property> - <addaction name="actionZoom_In"/> - <addaction name="actionZoom_Out"/> - <addaction name="actionBetter_Cursors"/> - </widget> - <widget class="QMenu" name="menuTools"> - <property name="title"> - <string>Tools</string> - </property> - <addaction name="actionPencil"/> - <addaction name="actionPointer"/> - <addaction name="actionFlood_Fill"/> - <addaction name="actionEyedropper"/> - <addaction name="actionMove"/> - <addaction name="actionMap_Shift"/> - </widget> - <addaction name="menuFile"/> - <addaction name="menuEdit"/> - <addaction name="menuView"/> - <addaction name="menuTools"/> - </widget> - <widget class="QStatusBar" name="statusBar"/> - <action name="action_Save_Project"> - <property name="text"> - <string>Save All</string> - </property> - <property name="shortcut"> - <string>Ctrl+Shift+S</string> - </property> - </action> - <action name="action_Exit"> - <property name="text"> - <string>Exit</string> - </property> - <property name="shortcut"> - <string>Ctrl+Q</string> - </property> - </action> - <action name="action_Open_Project"> - <property name="text"> - <string>Open Project...</string> - </property> - <property name="shortcut"> - <string>Ctrl+O</string> - </property> - </action> - <action name="action_Save"> - <property name="text"> - <string>Save</string> - </property> - <property name="shortcut"> - <string>Ctrl+S</string> - </property> - </action> - <action name="actionUndo"> - <property name="text"> - <string>Undo</string> - </property> - <property name="shortcut"> - <string>Ctrl+Z</string> - </property> - </action> - <action name="actionRedo"> - <property name="text"> - <string>Redo</string> - </property> - <property name="font"> - <font/> - </property> - <property name="shortcut"> - <string>Ctrl+Y</string> - </property> - </action> - <action name="action_Export_Map_Image"> - <property name="text"> - <string>Export Map Image...</string> - </property> - </action> - <action name="actionZoom_In"> - <property name="text"> - <string>Zoom In</string> - </property> - <property name="shortcut"> - <string>+</string> - </property> - </action> - <action name="actionZoom_Out"> - <property name="text"> - <string>Zoom Out</string> - </property> - <property name="shortcut"> - <string>-</string> - </property> - </action> - <action name="actionBetter_Cursors"> - <property name="checkable"> - <bool>true</bool> - </property> - <property name="checked"> - <bool>true</bool> - </property> - <property name="text"> - <string>Cursor Icons</string> - </property> - <property name="toolTip"> - <string><html><head/><body><p>Use reticule-styled cursors with icon showing currently selected tool.</p></body></html></string> - </property> - </action> - <action name="actionPencil"> - <property name="text"> - <string>Pencil</string> - </property> - <property name="shortcut"> - <string>N</string> - </property> - </action> - <action name="actionFlood_Fill"> - <property name="text"> - <string>Bucket Fill</string> - </property> - <property name="shortcut"> - <string>B</string> - </property> - </action> - <action name="actionEyedropper"> - <property name="text"> - <string>Eyedropper</string> - </property> - <property name="shortcut"> - <string>E</string> - </property> - </action> - <action name="actionMove"> - <property name="text"> - <string>Move</string> - </property> - <property name="shortcut"> - <string>M</string> - </property> - </action> - <action name="actionMap_Shift"> - <property name="text"> - <string>Map Shift</string> - </property> - <property name="shortcut"> - <string>S</string> - </property> - </action> - <action name="actionPointer"> - <property name="text"> - <string>Pointer</string> - </property> - <property name="shortcut"> - <string>P</string> - </property> - </action> - </widget> - <layoutdefault spacing="6" margin="11"/> - <customwidgets> - <customwidget> - <class>GraphicsView</class> - <extends>QGraphicsView</extends> - <header>graphicsview.h</header> - </customwidget> - <customwidget> - <class>NewEventToolButton</class> - <extends>QToolButton</extends> - <header>neweventtoolbutton.h</header> - </customwidget> - <customwidget> - <class>NoScrollComboBox</class> - <extends>QComboBox</extends> - <header>noscrollcombobox.h</header> - </customwidget> - </customwidgets> - <resources> - <include location="resources/images.qrc"/> - </resources> - <connections/> -</ui> +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>1117</width> + <height>747</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="windowTitle"> + <string>porymap</string> + </property> + <widget class="QWidget" name="centralWidget"> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QSplitter" name="splitter"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <widget class="QTreeView" name="mapList"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="selectionMode"> + <enum>QAbstractItemView::SingleSelection</enum> + </property> + <property name="selectionBehavior"> + <enum>QAbstractItemView::SelectItems</enum> + </property> + <attribute name="headerVisible"> + <bool>false</bool> + </attribute> + </widget> + <widget class="QTabWidget" name="tabWidget"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="currentIndex"> + <number>0</number> + </property> + <property name="tabsClosable"> + <bool>false</bool> + </property> + <property name="movable"> + <bool>false</bool> + </property> + <widget class="QWidget" name="tab_Map"> + <property name="toolTip"> + <string/> + </property> + <attribute name="icon"> + <iconset resource="resources/images.qrc"> + <normaloff>:/icons/map.ico</normaloff>:/icons/map.ico</iconset> + </attribute> + <attribute name="title"> + <string>Map</string> + </attribute> + <attribute name="toolTip"> + <string><html><head/><body><p>Edit the map layout.</p><p>Select metatiles or collision attributes from the right panel, and paint them onto the map.</p></body></html></string> + </attribute> + <layout class="QGridLayout" name="gridLayout_9"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="verticalSpacing"> + <number>6</number> + </property> + <item row="0" column="0"> + <widget class="QSplitter" name="splitter_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <widget class="QFrame" name="frame_9"> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="lineWidth"> + <number>1</number> + </property> + <layout class="QGridLayout" name="gridLayout_4"> + <property name="leftMargin"> + <number>3</number> + </property> + <property name="topMargin"> + <number>3</number> + </property> + <property name="rightMargin"> + <number>3</number> + </property> + <property name="bottomMargin"> + <number>3</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <item row="0" column="0"> + <widget class="QFrame" name="frame_6"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>32</height> + </size> + </property> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="spacing"> + <number>4</number> + </property> + <property name="leftMargin"> + <number>4</number> + </property> + <property name="topMargin"> + <number>4</number> + </property> + <property name="rightMargin"> + <number>4</number> + </property> + <property name="bottomMargin"> + <number>4</number> + </property> + <item> + <widget class="QToolButton" name="toolButton_Paint"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Pencil</p><p><span style=" font-weight:600;">Click</span> and drag to draw on the map.</p><p><span style=" font-weight:600;">Right-click</span> and drag to select tiles.</p></body></html></string> + </property> + <property name="text"> + <string>Paint</string> + </property> + <property name="icon"> + <iconset resource="resources/images.qrc"> + <normaloff>:/icons/pencil.ico</normaloff>:/icons/pencil.ico</iconset> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="autoRaise"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="toolButton_Select"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Pointer</p><p>Does nothing</p></body></html></string> + </property> + <property name="text"> + <string>Select</string> + </property> + <property name="icon"> + <iconset resource="resources/images.qrc"> + <normaloff>:/icons/cursor.ico</normaloff>:/icons/cursor.ico</iconset> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="toolButton_Fill"> + <property name="toolTip"> + <string><html><head/><body><p>Bucket Fill</p><p>Fills all similar tiles in a region with the selected metatiles or collision attributes</p></body></html></string> + </property> + <property name="text"> + <string>Fill</string> + </property> + <property name="icon"> + <iconset resource="resources/images.qrc"> + <normaloff>:/icons/fill_color.ico</normaloff>:/icons/fill_color.ico</iconset> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="toolButton_Dropper"> + <property name="toolTip"> + <string><html><head/><body><p>Eyedropper</p><p><span style=" font-weight:600;">Click</span> to select a metatile or collision attribute.</p></body></html></string> + </property> + <property name="text"> + <string>Dropper</string> + </property> + <property name="icon"> + <iconset resource="resources/images.qrc"> + <normaloff>:/icons/pipette.ico</normaloff>:/icons/pipette.ico</iconset> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="toolButton_Move"> + <property name="toolTip"> + <string><html><head/><body><p>Move</p><p>Click to drag map around.</p></body></html></string> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="icon"> + <iconset resource="resources/images.qrc"> + <normaloff>:/icons/move.ico</normaloff>:/icons/move.ico</iconset> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="toolButton_Shift"> + <property name="toolTip"> + <string><html><head/><body><p>Map Shift</p><p><span style=" font-weight:600;">Click and drag</span> on the map to shift the positions all metatiles at once. This is useful after resizing a map.</p></body></html></string> + </property> + <property name="text"> + <string>Shift</string> + </property> + <property name="icon"> + <iconset resource="resources/images.qrc"> + <normaloff>:/icons/shift.ico</normaloff>:/icons/shift.ico</iconset> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="checkBox_smartPaths"> + <property name="toolTip"> + <string><html><head/><body><p>Smart-path mode allows easier drawing of paths. If a 3x3 metatile block is selcted in the right panel, then smart path mode will automatically form a pathway using those selected blocks.</p><p>When smart-path mode is <span style=" font-weight:600;">not</span> enabled, clicking and dragging a selection will tile it in a grid.</p><p>Hold down the <span style=" font-weight:600;">shift</span> key while editing to quickly enable smart-path mode.</p></body></html></string> + </property> + <property name="styleSheet"> + <string notr="true">margin-left: 10px</string> + </property> + <property name="text"> + <string>Smart Paths</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="checkBox_ToggleGrid"> + <property name="toolTip"> + <string><html><head/><body><p>Toggles a grid over the map's metatile boundaries.</p></body></html></string> + </property> + <property name="styleSheet"> + <string notr="true"/> + </property> + <property name="text"> + <string>Grid</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="checkBox_ToggleBorder"> + <property name="text"> + <string>Border</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="pushButton"> + <property name="toolTip"> + <string><html><head/><body><p>Change a map layout's width and height.</p></body></html></string> + </property> + <property name="text"> + <string>Change Dimensions</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="1" column="0"> + <widget class="QFrame" name="frame_7"> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QScrollArea" name="scrollArea"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents_5"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>469</width> + <height>608</height> + </rect> + </property> + <layout class="QGridLayout" name="gridLayout_8"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="1" column="1"> + <widget class="QGraphicsView" name="graphicsView_Map"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="mouseTracking"> + <bool>false</bool> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="sizeAdjustPolicy"> + <enum>QAbstractScrollArea::AdjustIgnored</enum> + </property> + <property name="dragMode"> + <enum>QGraphicsView::NoDrag</enum> + </property> + </widget> + </item> + <item row="1" column="0"> + <spacer name="horizontalSpacer_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>166</width> + <height>16</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="1"> + <spacer name="verticalSpacer_3"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>16</width> + <height>166</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="2"> + <spacer name="horizontalSpacer_5"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>166</width> + <height>16</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="1"> + <spacer name="verticalSpacer_4"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>16</width> + <height>166</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <widget class="QFrame" name="frame_8"> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QVBoxLayout" name="verticalLayout_6"> + <property name="leftMargin"> + <number>3</number> + </property> + <property name="topMargin"> + <number>3</number> + </property> + <property name="rightMargin"> + <number>3</number> + </property> + <property name="bottomMargin"> + <number>3</number> + </property> + <item> + <widget class="QTabWidget" name="tabWidget_2"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>156</width> + <height>0</height> + </size> + </property> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="tab_blocks"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <attribute name="title"> + <string>Metatiles</string> + </attribute> + <layout class="QGridLayout" name="gridLayout_3"> + <property name="leftMargin"> + <number>3</number> + </property> + <property name="topMargin"> + <number>3</number> + </property> + <property name="rightMargin"> + <number>3</number> + </property> + <property name="bottomMargin"> + <number>3</number> + </property> + <property name="spacing"> + <number>3</number> + </property> + <item row="0" column="0"> + <widget class="QFrame" name="frame_Tilesets"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label_PrimaryTileset"> + <property name="text"> + <string>Primary Tileset</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="NoScrollComboBox" name="comboBox_PrimaryTileset"> + <property name="focusPolicy"> + <enum>Qt::StrongFocus</enum> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Primary Tileset</p><p>Defines the first 0x200 metatiles available for the map.</p></body></html></string> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_SecondaryTileset"> + <property name="text"> + <string>Secondary Tileset</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="NoScrollComboBox" name="comboBox_SecondaryTileset"> + <property name="focusPolicy"> + <enum>Qt::StrongFocus</enum> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Secondary Tileset</p><p>Defines the second 0x200 metatiles available for the map.</p></body></html></string> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="2" column="0"> + <widget class="QFrame" name="frame_currentMetatileSelection"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>92</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>92</height> + </size> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_5"> + <property name="spacing"> + <number>0</number> + </property> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGroupBox" name="groupBox_2"> + <property name="title"> + <string>Selection</string> + </property> + <layout class="QGridLayout" name="gridLayout_17"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QScrollArea" name="scrollArea_6"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents_6"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>324</width> + <height>77</height> + </rect> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_7"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <spacer name="horizontalSpacer_16"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QGraphicsView" name="graphicsView_currentMetatileSelection"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>16777215</height> + </size> + </property> + <property name="verticalScrollBarPolicy"> + <enum>Qt::ScrollBarAlwaysOff</enum> + </property> + <property name="horizontalScrollBarPolicy"> + <enum>Qt::ScrollBarAlwaysOff</enum> + </property> + <property name="interactive"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_17"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + <item row="3" column="0"> + <widget class="QScrollArea" name="scrollArea_2"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="verticalScrollBarPolicy"> + <enum>Qt::ScrollBarAlwaysOn</enum> + </property> + <property name="horizontalScrollBarPolicy"> + <enum>Qt::ScrollBarAsNeeded</enum> + </property> + <property name="sizeAdjustPolicy"> + <enum>QAbstractScrollArea::AdjustIgnored</enum> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <property name="alignment"> + <set>Qt::AlignHCenter|Qt::AlignTop</set> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents_2"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>307</width> + <height>387</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QGridLayout" name="gridLayout_5"> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="1" column="1"> + <spacer name="verticalSpacer_5"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="1"> + <widget class="QGraphicsView" name="graphicsView_Metatiles"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="verticalScrollBarPolicy"> + <enum>Qt::ScrollBarAlwaysOff</enum> + </property> + <property name="horizontalScrollBarPolicy"> + <enum>Qt::ScrollBarAlwaysOff</enum> + </property> + <property name="sizeAdjustPolicy"> + <enum>QAbstractScrollArea::AdjustIgnored</enum> + </property> + </widget> + </item> + <item row="0" column="0"> + <spacer name="horizontalSpacer_14"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="2"> + <spacer name="horizontalSpacer_15"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </widget> + </item> + <item row="1" column="0"> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Border</string> + </property> + <layout class="QGridLayout" name="gridLayout_16"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="0" column="1"> + <widget class="QGraphicsView" name="graphicsView_BorderMetatile"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>48</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>The border is a 2x2 metatile which is repeated outside of the map layout's boundary. Draw on this border area to modify it.</p></body></html></string> + </property> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Sunken</enum> + </property> + <property name="verticalScrollBarPolicy"> + <enum>Qt::ScrollBarAsNeeded</enum> + </property> + </widget> + </item> + <item row="0" column="0"> + <spacer name="horizontalSpacer_12"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="2"> + <spacer name="horizontalSpacer_13"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_collision"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <attribute name="title"> + <string>Collision</string> + </attribute> + <layout class="QGridLayout" name="gridLayout_CollisionSelection"> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item row="0" column="1"> + <widget class="QGraphicsView" name="graphicsView_Collision"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>64</width> + <height>512</height> + </size> + </property> + </widget> + </item> + <item row="0" column="0"> + <spacer name="horizontalSpacer_18"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="2"> + <spacer name="horizontalSpacer_19"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="1"> + <spacer name="verticalSpacer_6"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_Objects"> + <property name="enabled"> + <bool>true</bool> + </property> + <attribute name="title"> + <string>Events</string> + </attribute> + <attribute name="toolTip"> + <string><html><head/><body><p>Edit the map's events.</p><p>View and modify objects, warps, signs, etc.</p></body></html></string> + </attribute> + <layout class="QGridLayout" name="gridLayout_10"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QSplitter" name="splitter_3"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <widget class="QScrollArea" name="scrollArea_3"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents_4"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>381</width> + <height>657</height> + </rect> + </property> + <layout class="QGridLayout" name="gridLayout_7"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="1" column="2"> + <spacer name="horizontalSpacer_Objects_Map_right"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>166</width> + <height>16</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="0"> + <spacer name="horizontalSpacer_Objects_Map_left"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>166</width> + <height>16</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="1"> + <spacer name="verticalSpacer_Objects_Map_top"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>16</width> + <height>166</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="1"> + <spacer name="verticalSpacer_Objects_Map_bottom"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>16</width> + <height>166</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="1"> + <widget class="GraphicsView" name="graphicsView_Objects_Map"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + <widget class="QFrame" name="frame_Objects"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>444</width> + <height>0</height> + </size> + </property> + <layout class="QGridLayout" name="gridLayout_6"> + <property name="leftMargin"> + <number>3</number> + </property> + <property name="topMargin"> + <number>3</number> + </property> + <property name="rightMargin"> + <number>3</number> + </property> + <property name="bottomMargin"> + <number>3</number> + </property> + <item row="1" column="0"> + <widget class="QGroupBox" name="groupBox_selectedObjects"> + <property name="title"> + <string>Selected</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="spacing"> + <number>6</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QFrame" name="frame_5"> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QScrollArea" name="scrollArea_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="sizeAdjustPolicy"> + <enum>QAbstractScrollArea::AdjustIgnored</enum> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>432</width> + <height>596</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + <item row="0" column="0"> + <widget class="QFrame" name="frame_4"> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>32</height> + </size> + </property> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="NewEventToolButton" name="newEventToolButton"> + <property name="minimumSize"> + <size> + <width>40</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Add a new event to the map.</p></body></html></string> + </property> + <property name="text"> + <string>New Object</string> + </property> + <property name="icon"> + <iconset resource="resources/images.qrc"> + <normaloff>:/icons/add.ico</normaloff>:/icons/add.ico</iconset> + </property> + <property name="toolButtonStyle"> + <enum>Qt::ToolButtonTextBesideIcon</enum> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="toolButton_deleteObject"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>40</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Delete the selected event from the map.</p></body></html></string> + </property> + <property name="text"> + <string>Delete</string> + </property> + <property name="icon"> + <iconset resource="resources/images.qrc"> + <normaloff>:/icons/delete.ico</normaloff>:/icons/delete.ico</iconset> + </property> + <property name="toolButtonStyle"> + <enum>Qt::ToolButtonTextBesideIcon</enum> + </property> + <property name="autoRaise"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QToolButton" name="toolButton_Open_Scripts"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Open Map Scripts</string> + </property> + <property name="autoRaise"> + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_Attributes"> + <attribute name="title"> + <string>Header</string> + </attribute> + <widget class="QFrame" name="frame_3"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="geometry"> + <rect> + <x>10</x> + <y>10</y> + <width>381</width> + <height>311</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QFormLayout" name="formLayout_2"> + <property name="verticalSpacing"> + <number>12</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Song</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="comboBox_Song"> + <property name="toolTip"> + <string><html><head/><body><p>The default background music for this map.</p></body></html></string> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Location</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="comboBox_Location"> + <property name="toolTip"> + <string><html><head/><body><p>The section of the region map which the map is grouped under. This also determines the name of the map that is display when the player enters it.</p></body></html></string> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>Requires Flash</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_6"> + <property name="text"> + <string>Weather</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QComboBox" name="comboBox_Weather"> + <property name="toolTip"> + <string><html><head/><body><p>The default weather for this map.</p></body></html></string> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="label_7"> + <property name="text"> + <string>Type</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QComboBox" name="comboBox_Type"> + <property name="toolTip"> + <string><html><head/><body><p>The map type is a general attribute, which is used for many different things. For example. it determines whether biking or running is allowed.</p></body></html></string> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QLabel" name="label_8"> + <property name="text"> + <string>Show Location Name</string> + </property> + </widget> + </item> + <item row="5" column="1"> + <widget class="QCheckBox" name="checkBox_ShowLocation"> + <property name="toolTip"> + <string><html><head/><body><p>Whether or not to display the location name when the player enters the map.</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="6" column="0"> + <widget class="QLabel" name="label_9"> + <property name="text"> + <string>Battle scene</string> + </property> + </widget> + </item> + <item row="6" column="1"> + <widget class="QComboBox" name="comboBox_BattleScene"> + <property name="toolTip"> + <string><html><head/><body><p>Determines the type of battle scene graphics to use.</p></body></html></string> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QCheckBox" name="checkBox_Visibility"> + <property name="toolTip"> + <string><html><head/><body><p>Whether or not the map is dark and requires Flash to illuminate.</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + <widget class="QWidget" name="tab_Connections"> + <attribute name="title"> + <string>Connections</string> + </attribute> + <layout class="QGridLayout" name="gridLayout_12"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item row="3" column="0"> + <widget class="QFrame" name="gridFrame"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QGridLayout" name="gridLayout_11"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="1" column="0"> + <widget class="QFrame" name="horizontalFrame"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>32</height> + </size> + </property> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <property name="spacing"> + <number>4</number> + </property> + <property name="leftMargin"> + <number>4</number> + </property> + <property name="topMargin"> + <number>4</number> + </property> + <property name="rightMargin"> + <number>4</number> + </property> + <property name="bottomMargin"> + <number>4</number> + </property> + <item> + <widget class="QPushButton" name="pushButton_AddConnection"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Add a new connection.</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <activeon>:/icons/add.ico</activeon> + </iconset> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButton_RemoveConnection"> + <property name="toolTip"> + <string><html><head/><body><p>Remove the currently-selected connection.</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <activeon>:/icons/delete.ico</activeon> + </iconset> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_13"> + <property name="text"> + <string>Number of Connections:</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_NumConnections"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_11"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QCheckBox" name="checkBox_MirrorConnections"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string><html><head/><body><p>If enabled, connections will automatically be updated on the connected map.</p></body></html></string> + </property> + <property name="text"> + <string>Mirror to Connecting Maps</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="2" column="0"> + <widget class="QFrame" name="horizontalFrame"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>32</height> + </size> + </property> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,0,0,0,0,0"> + <property name="spacing"> + <number>6</number> + </property> + <property name="leftMargin"> + <number>4</number> + </property> + <property name="topMargin"> + <number>4</number> + </property> + <property name="rightMargin"> + <number>4</number> + </property> + <property name="bottomMargin"> + <number>4</number> + </property> + <item> + <widget class="QLabel" name="label_11"> + <property name="text"> + <string>Map</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="comboBox_ConnectedMap"> + <property name="toolTip"> + <string><html><head/><body><p>The destination map name of the connection.</p></body></html></string> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_12"> + <property name="text"> + <string>Offset</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="spinBox_ConnectionOffset"> + <property name="toolTip"> + <string><html><head/><body><p>The number of metatiles to offset the connection.</p></body></html></string> + </property> + <property name="minimum"> + <number>-999</number> + </property> + <property name="maximum"> + <number>999</number> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="comboBox_ConnectionDirection"> + <property name="toolTip"> + <string><html><head/><body><p>The direction of the connection.</p></body></html></string> + </property> + <item> + <property name="text"> + <string>up</string> + </property> + </item> + <item> + <property name="text"> + <string>right</string> + </property> + </item> + <item> + <property name="text"> + <string>down</string> + </property> + </item> + <item> + <property name="text"> + <string>left</string> + </property> + </item> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_6"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + <item row="3" column="0"> + <widget class="QFrame" name="gridFrame"> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QGridLayout" name="gridLayout_13"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="1" column="0"> + <widget class="QScrollArea" name="scrollArea_5"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents_3"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>826</width> + <height>557</height> + </rect> + </property> + <layout class="QGridLayout" name="gridLayout_14"> + <item row="1" column="2"> + <spacer name="horizontalSpacer_8"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="1"> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="1"> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="1"> + <widget class="QGraphicsView" name="graphicsView_Connections"> + <property name="backgroundBrush"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> + <red>0</red> + <green>0</green> + <blue>0</blue> + </color> + </brush> + </property> + </widget> + </item> + <item row="1" column="0"> + <spacer name="horizontalSpacer_7"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </widget> + </item> + <item row="0" column="0"> + <widget class="QFrame" name="horizontalFrame"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_6"> + <property name="spacing"> + <number>4</number> + </property> + <property name="leftMargin"> + <number>4</number> + </property> + <property name="topMargin"> + <number>4</number> + </property> + <property name="rightMargin"> + <number>4</number> + </property> + <property name="bottomMargin"> + <number>4</number> + </property> + <item> + <widget class="QLabel" name="label_14"> + <property name="text"> + <string>Dive Map</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="comboBox_DiveMap"> + <property name="toolTip"> + <string><html><head/><body><p>Destination map name when using <span style=" font-weight:600;">Dive</span>. If empty, no such connection will exist.</p></body></html></string> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_15"> + <property name="text"> + <string>Emerge Map</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="comboBox_EmergeMap"> + <property name="toolTip"> + <string><html><head/><body><p>Destination map name when emerging using <span style=" font-weight:600;">Dive</span>. If empty, no such connection will exist.</p></body></html></string> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_10"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menuBar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>1117</width> + <height>21</height> + </rect> + </property> + <widget class="QMenu" name="menuFile"> + <property name="title"> + <string>File</string> + </property> + <addaction name="action_Open_Project"/> + <addaction name="action_Save"/> + <addaction name="action_Save_Project"/> + <addaction name="separator"/> + <addaction name="action_Export_Map_Image"/> + <addaction name="separator"/> + <addaction name="action_Exit"/> + </widget> + <widget class="QMenu" name="menuEdit"> + <property name="title"> + <string>Edit</string> + </property> + <addaction name="actionUndo"/> + <addaction name="actionRedo"/> + </widget> + <widget class="QMenu" name="menuView"> + <property name="title"> + <string>View</string> + </property> + <addaction name="actionZoom_In"/> + <addaction name="actionZoom_Out"/> + <addaction name="actionBetter_Cursors"/> + </widget> + <widget class="QMenu" name="menuTools"> + <property name="title"> + <string>Tools</string> + </property> + <addaction name="actionPencil"/> + <addaction name="actionPointer"/> + <addaction name="actionFlood_Fill"/> + <addaction name="actionEyedropper"/> + <addaction name="actionMove"/> + <addaction name="actionMap_Shift"/> + </widget> + <addaction name="menuFile"/> + <addaction name="menuEdit"/> + <addaction name="menuView"/> + <addaction name="menuTools"/> + </widget> + <widget class="QStatusBar" name="statusBar"/> + <action name="action_Save_Project"> + <property name="text"> + <string>Save All</string> + </property> + <property name="shortcut"> + <string>Ctrl+Shift+S</string> + </property> + </action> + <action name="action_Exit"> + <property name="text"> + <string>Exit</string> + </property> + <property name="shortcut"> + <string>Ctrl+Q</string> + </property> + </action> + <action name="action_Open_Project"> + <property name="text"> + <string>Open Project...</string> + </property> + <property name="shortcut"> + <string>Ctrl+O</string> + </property> + </action> + <action name="action_Save"> + <property name="text"> + <string>Save</string> + </property> + <property name="shortcut"> + <string>Ctrl+S</string> + </property> + </action> + <action name="actionUndo"> + <property name="text"> + <string>Undo</string> + </property> + <property name="shortcut"> + <string>Ctrl+Z</string> + </property> + </action> + <action name="actionRedo"> + <property name="text"> + <string>Redo</string> + </property> + <property name="font"> + <font/> + </property> + <property name="shortcut"> + <string>Ctrl+Y</string> + </property> + </action> + <action name="action_Export_Map_Image"> + <property name="text"> + <string>Export Map Image...</string> + </property> + </action> + <action name="actionZoom_In"> + <property name="text"> + <string>Zoom In</string> + </property> + <property name="shortcut"> + <string>+</string> + </property> + </action> + <action name="actionZoom_Out"> + <property name="text"> + <string>Zoom Out</string> + </property> + <property name="shortcut"> + <string>-</string> + </property> + </action> + <action name="actionBetter_Cursors"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="text"> + <string>Cursor Icons</string> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Use reticule-styled cursors with icon showing currently selected tool.</p></body></html></string> + </property> + </action> + <action name="actionPencil"> + <property name="text"> + <string>Pencil</string> + </property> + <property name="shortcut"> + <string>N</string> + </property> + </action> + <action name="actionFlood_Fill"> + <property name="text"> + <string>Bucket Fill</string> + </property> + <property name="shortcut"> + <string>B</string> + </property> + </action> + <action name="actionEyedropper"> + <property name="text"> + <string>Eyedropper</string> + </property> + <property name="shortcut"> + <string>E</string> + </property> + </action> + <action name="actionMove"> + <property name="text"> + <string>Move</string> + </property> + <property name="shortcut"> + <string>M</string> + </property> + </action> + <action name="actionMap_Shift"> + <property name="text"> + <string>Map Shift</string> + </property> + <property name="shortcut"> + <string>S</string> + </property> + </action> + <action name="actionPointer"> + <property name="text"> + <string>Pointer</string> + </property> + <property name="shortcut"> + <string>P</string> + </property> + </action> + </widget> + <layoutdefault spacing="6" margin="11"/> + <customwidgets> + <customwidget> + <class>GraphicsView</class> + <extends>QGraphicsView</extends> + <header>graphicsview.h</header> + </customwidget> + <customwidget> + <class>NewEventToolButton</class> + <extends>QToolButton</extends> + <header>neweventtoolbutton.h</header> + </customwidget> + <customwidget> + <class>NoScrollComboBox</class> + <extends>QComboBox</extends> + <header>noscrollcombobox.h</header> + </customwidget> + </customwidgets> + <resources> + <include location="resources/images.qrc"/> + </resources> + <connections/> +</ui> diff --git a/porymap.pro b/src/porymap.pro old mode 100755 new mode 100644 similarity index 100% rename from porymap.pro rename to src/porymap.pro diff --git a/project.cpp b/src/project.cpp old mode 100755 new mode 100644 similarity index 97% rename from project.cpp rename to src/project.cpp index f916f260..63899604 --- a/project.cpp +++ b/src/project.cpp @@ -1,1760 +1,1760 @@ -#include "project.h" -#include "history.h" -#include "historyitem.h" -#include "parseutil.h" -#include "tile.h" -#include "tileset.h" -#include "event.h" - -#include <QDebug> -#include <QDir> -#include <QFile> -#include <QTextStream> -#include <QStandardItem> -#include <QMessageBox> -#include <QRegularExpression> - -int Project::num_tiles_primary = 512; -int Project::num_tiles_total = 1024; -int Project::num_metatiles_primary = 512; -int Project::num_metatiles_total = 1024; -int Project::num_pals_primary = 6; -int Project::num_pals_total = 13; - -Project::Project() -{ - groupNames = new QStringList; - map_groups = new QMap<QString, int>; - mapNames = new QStringList; - regionMapSections = new QStringList; - itemNames = new QStringList; - flagNames = new QStringList; - varNames = new QStringList; - movementTypes = new QStringList; - mapTypes = new QStringList; - mapBattleScenes = new QStringList; - weatherNames = new QStringList; - coordEventWeatherNames = new QStringList; - secretBaseIds = new QStringList; - bgEventFacingDirections = new QStringList; - map_cache = new QMap<QString, Map*>; - mapConstantsToMapNames = new QMap<QString, QString>; - mapNamesToMapConstants = new QMap<QString, QString>; - tileset_cache = new QMap<QString, Tileset*>; -} - -QString Project::getProjectTitle() { - if (!root.isNull()) { - return root.section('/', -1); - } else { - return QString(); - } -} - -Map* Project::loadMap(QString map_name) { - Map *map; - if (map_cache->contains(map_name)) { - map = map_cache->value(map_name); - // TODO: uncomment when undo/redo history is fully implemented for all actions. - if (true/*map->hasUnsavedChanges()*/) { - return map; - } - } else { - map = new Map; - map->setName(map_name); - } - - readMapHeader(map); - readMapLayout(map); - readMapEvents(map); - loadMapConnections(map); - map->commit(); - map->metatileHistory.save(); - - map_cache->insert(map_name, map); - return map; -} - -void Project::loadMapConnections(Map *map) { - if (!map->isPersistedToFile) { - return; - } - - map->connections.clear(); - if (!map->connections_label.isNull()) { - QString path = root + QString("/data/maps/%1/connections.inc").arg(map->name); - QString text = readTextFile(path); - if (!text.isNull()) { - QList<QStringList> *commands = parseAsm(text); - QStringList *list = getLabelValues(commands, map->connections_label); - - //// Avoid using this value. It ought to be generated instead. - //int num_connections = list->value(0).toInt(nullptr, 0); - - QString connections_list_label = list->value(1); - QList<QStringList> *connections = getLabelMacros(commands, connections_list_label); - for (QStringList command : *connections) { - QString macro = command.value(0); - if (macro == "connection") { - MapConnection *connection = new MapConnection; - connection->direction = command.value(1); - connection->offset = command.value(2); - QString mapConstant = command.value(3); - if (mapConstantsToMapNames->contains(mapConstant)) { - connection->map_name = mapConstantsToMapNames->value(mapConstant); - map->connections.append(connection); - } else { - qDebug() << QString("Failed to find connected map for map constant '%1'").arg(mapConstant); - } - } - } - } - } -} - -void Project::setNewMapConnections(Map *map) { - map->connections.clear(); -} - -QList<QStringList>* Project::getLabelMacros(QList<QStringList> *list, QString label) { - bool in_label = false; - QList<QStringList> *new_list = new QList<QStringList>; - for (int i = 0; i < list->length(); i++) { - QStringList params = list->value(i); - QString macro = params.value(0); - if (macro == ".label") { - if (params.value(1) == label) { - in_label = true; - } else if (in_label) { - // If nothing has been read yet, assume the label - // we're looking for is in a stack of labels. - if (new_list->length() > 0) { - break; - } - } - } else if (in_label) { - new_list->append(params); - } - } - return new_list; -} - -// For if you don't care about filtering by macro, -// and just want all values associated with some label. -QStringList* Project::getLabelValues(QList<QStringList> *list, QString label) { - list = getLabelMacros(list, label); - QStringList *values = new QStringList; - for (int i = 0; i < list->length(); i++) { - QStringList params = list->value(i); - QString macro = params.value(0); - // Ignore .align - if (macro == ".align") - continue; - if (macro == ".ifdef") - continue; - if (macro == ".ifndef") - continue; - for (int j = 1; j < params.length(); j++) { - values->append(params.value(j)); - } - } - return values; -} - -void Project::readMapHeader(Map* map) { - if (!map->isPersistedToFile) { - return; - } - - QString label = map->name; - ParseUtil *parser = new ParseUtil; - - QString header_text = readTextFile(root + "/data/maps/" + label + "/header.inc"); - if (header_text.isNull()) { - return; - } - QStringList *header = getLabelValues(parser->parseAsm(header_text), label); - map->layout_label = header->value(0); - map->events_label = header->value(1); - map->scripts_label = header->value(2); - map->connections_label = header->value(3); - map->song = header->value(4); - map->layout_id = header->value(5); - map->location = header->value(6); - map->requiresFlash = header->value(7); - map->weather = header->value(8); - map->type = header->value(9); - map->unknown = header->value(10); - map->show_location = header->value(11); - map->battle_scene = header->value(12); -} - -void Project::setNewMapHeader(Map* map, int mapIndex) { - map->layout_label = QString("%1_Layout").arg(map->name); - map->events_label = QString("%1_MapEvents").arg(map->name);; - map->scripts_label = QString("%1_MapScripts").arg(map->name);; - map->connections_label = "0x0"; - map->song = "MUS_DAN02"; - map->layout_id = QString("%1").arg(mapIndex); - map->location = "MAPSEC_LITTLEROOT_TOWN"; - map->requiresFlash = "FALSE"; - map->weather = "WEATHER_SUNNY"; - map->type = "MAP_TYPE_TOWN"; - map->unknown = "0"; - map->show_location = "TRUE"; - map->battle_scene = "MAP_BATTLE_SCENE_NORMAL"; -} - -void Project::saveMapHeader(Map *map) { - QString label = map->name; - QString header_path = root + "/data/maps/" + label + "/header.inc"; - QString text = ""; - text += QString("%1::\n").arg(label); - text += QString("\t.4byte %1\n").arg(map->layout_label); - text += QString("\t.4byte %1\n").arg(map->events_label); - text += QString("\t.4byte %1\n").arg(map->scripts_label); - - if (map->connections.length() == 0) { - map->connections_label = "0x0"; - } else { - map->connections_label = QString("%1_MapConnections").arg(map->name); - } - text += QString("\t.4byte %1\n").arg(map->connections_label); - - text += QString("\t.2byte %1\n").arg(map->song); - text += QString("\t.2byte %1\n").arg(map->layout_id); - text += QString("\t.byte %1\n").arg(map->location); - text += QString("\t.byte %1\n").arg(map->requiresFlash); - text += QString("\t.byte %1\n").arg(map->weather); - text += QString("\t.byte %1\n").arg(map->type); - text += QString("\t.2byte %1\n").arg(map->unknown); - text += QString("\t.byte %1\n").arg(map->show_location); - text += QString("\t.byte %1\n").arg(map->battle_scene); - saveTextFile(header_path, text); -} - -void Project::saveMapConnections(Map *map) { - QString path = root + "/data/maps/" + map->name + "/connections.inc"; - if (map->connections.length() > 0) { - QString text = ""; - QString connectionsListLabel = QString("%1_MapConnectionsList").arg(map->name); - int numValidConnections = 0; - text += QString("%1::\n").arg(connectionsListLabel); - for (MapConnection* connection : map->connections) { - if (mapNamesToMapConstants->contains(connection->map_name)) { - text += QString("\tconnection %1, %2, %3\n") - .arg(connection->direction) - .arg(connection->offset) - .arg(mapNamesToMapConstants->value(connection->map_name)); - numValidConnections++; - } else { - qDebug() << QString("Failed to write map connection. %1 not a valid map name").arg(connection->map_name); - } - } - text += QString("\n"); - text += QString("%1::\n").arg(map->connections_label); - text += QString("\t.4byte %1\n").arg(numValidConnections); - text += QString("\t.4byte %1\n").arg(connectionsListLabel); - saveTextFile(path, text); - } else { - deleteFile(path); - } - - updateMapsWithConnections(map); -} - -void Project::updateMapsWithConnections(Map *map) { - if (map->connections.length() > 0) { - if (!mapsWithConnections.contains(map->name)) { - mapsWithConnections.append(map->name); - } - } else { - if (mapsWithConnections.contains(map->name)) { - mapsWithConnections.removeOne(map->name); - } - } -} - -void Project::readMapLayoutsTable() { - QString layoutsText = readTextFile(getMapLayoutsTableFilepath()); - QList<QStringList>* values = parseAsm(layoutsText); - bool inLayoutPointers = false; - for (int i = 0; i < values->length(); i++) { - QStringList params = values->value(i); - QString macro = params.value(0); - if (macro == ".label") { - if (inLayoutPointers) { - break; - } - if (params.value(1) == "gMapLayouts") { - inLayoutPointers = true; - } - } else if (macro == ".4byte" && inLayoutPointers) { - QString layoutName = params.value(1); - mapLayoutsTable.append(layoutName); - } - } - - // Deep copy - mapLayoutsTableMaster = mapLayoutsTable; - mapLayoutsTableMaster.detach(); -} - -void Project::saveMapLayoutsTable() { - QString text = ""; - text += QString("\t.align 2\n"); - text += QString("gMapLayouts::\n"); - for (QString layoutName : mapLayoutsTableMaster) { - text += QString("\t.4byte %1\n").arg(layoutName); - } - saveTextFile(getMapLayoutsTableFilepath(), text); -} - -QString Project::getMapLayoutsTableFilepath() { - return QString("%1/data/layouts_table.inc").arg(root); -} - -QStringList* Project::readLayoutValues(QString layoutLabel) { - ParseUtil *parser = new ParseUtil; - - QString layoutText = readTextFile(getMapLayoutFilepath(layoutLabel)); - if (layoutText.isNull()) { - return nullptr; - } - - QStringList *layoutValues = getLabelValues(parser->parseAsm(layoutText), layoutLabel); - QString borderLabel = layoutValues->value(2); - QString blockdataLabel = layoutValues->value(3); - QStringList *borderValues = getLabelValues(parser->parseAsm(layoutText), borderLabel); - QString borderPath = borderValues->value(0).replace("\"", ""); - layoutValues->append(borderPath); - QStringList *blockdataValues = getLabelValues(parser->parseAsm(layoutText), blockdataLabel); - QString blockdataPath = blockdataValues->value(0).replace("\"", ""); - layoutValues->append(blockdataPath); - - if (layoutValues->size() != 8) { - qDebug() << "Error: Unexpected number of properties in layout '" << layoutLabel << "'"; - return nullptr; - } - - return layoutValues; -} - -void Project::readMapLayout(Map* map) { - if (!map->isPersistedToFile) { - return; - } - - MapLayout *layout; - if (!mapLayouts.contains(map->layout_label)) { - QStringList *layoutValues = readLayoutValues(map->layout->label); - if (!layoutValues) { - return; - } - - layout = new MapLayout(); - mapLayouts.insert(map->layout_label, layout); - layout->name = MapLayout::getNameFromLabel(map->layout_label); - layout->label = map->layout_label; - layout->width = layoutValues->value(0); - layout->height = layoutValues->value(1); - layout->border_label = layoutValues->value(2); - layout->blockdata_label = layoutValues->value(3); - layout->tileset_primary_label = layoutValues->value(4); - layout->tileset_secondary_label = layoutValues->value(5); - layout->border_path = layoutValues->value(6); - layout->blockdata_path = layoutValues->value(7); - map->layout = layout; - } else { - map->layout = mapLayouts[map->layout_label]; - } - - loadMapTilesets(map); - loadBlockdata(map); - loadMapBorder(map); -} - -void Project::readAllMapLayouts() { - mapLayouts.clear(); - - for (int i = 0; i < mapLayoutsTable.size(); i++) { - QString layoutLabel = mapLayoutsTable[i]; - QStringList *layoutValues = readLayoutValues(layoutLabel); - if (!layoutValues) { - return; - } - - MapLayout *layout = new MapLayout(); - layout->name = MapLayout::getNameFromLabel(layoutLabel); - layout->label = layoutLabel; - layout->index = i; - layout->width = layoutValues->value(0); - layout->height = layoutValues->value(1); - layout->border_label = layoutValues->value(2); - layout->blockdata_label = layoutValues->value(3); - layout->tileset_primary_label = layoutValues->value(4); - layout->tileset_secondary_label = layoutValues->value(5); - layout->border_path = layoutValues->value(6); - layout->blockdata_path = layoutValues->value(7); - mapLayouts.insert(layoutLabel, layout); - } - - // Deep copy - mapLayoutsMaster = mapLayouts; - mapLayoutsMaster.detach(); -} - -void Project::saveAllMapLayouts() { - for (QString layoutName : mapLayoutsTableMaster) { - MapLayout *layout = mapLayouts.value(layoutName); - QString text = QString("%1::\n").arg(layout->border_label); - text += QString("\t.incbin \"%1\"\n").arg(layout->border_path); - text += QString("\n"); - text += QString("%1::\n").arg(layout->blockdata_label); - text += QString("\t.incbin \"%1\"\n").arg(layout->blockdata_path); - text += QString("\n"); - text += QString("\t.align 2\n"); - text += QString("%1::\n").arg(layoutName); - text += QString("\t.4byte %1\n").arg(layout->width); - text += QString("\t.4byte %1\n").arg(layout->height); - text += QString("\t.4byte %1\n").arg(layout->border_label); - text += QString("\t.4byte %1\n").arg(layout->blockdata_label); - text += QString("\t.4byte %1\n").arg(layout->tileset_primary_label); - text += QString("\t.4byte %1\n").arg(layout->tileset_secondary_label); - text += QString("\n"); - saveTextFile(getMapLayoutFilepath(layout->label), text); - } -} - -QString Project::getMapLayoutFilepath(QString layoutLabel) { - return QString("%1/data/layouts/%2/layout.inc").arg(root).arg(MapLayout::getNameFromLabel(layoutLabel)); -} - -void Project::setNewMapLayout(Map* map) { - MapLayout *layout = new MapLayout(); - layout->label = QString("%1_Layout").arg(map->name); - layout->name = MapLayout::getNameFromLabel(layout->label); - layout->width = "20"; - layout->height = "20"; - layout->border_label = QString("%1_MapBorder").arg(map->name); - layout->border_path = QString("data/layouts/%1/border.bin").arg(map->name); - layout->blockdata_label = QString("%1_MapBlockdata").arg(map->name); - layout->blockdata_path = QString("data/layouts/%1/map.bin").arg(map->name); - layout->tileset_primary_label = "gTileset_General"; - layout->tileset_secondary_label = "gTileset_Petalburg"; - map->layout = layout; - map->layout_label = layout->label; - - // Insert new entry into the global map layouts. - mapLayouts.insert(layout->label, layout); - mapLayoutsTable.append(layout->label); -} - -void Project::saveMapGroupsTable() { - QString text = ""; - int groupNum = 0; - for (QStringList mapNames : groupedMapNames) { - text += QString("\t.align 2\n"); - text += QString("gMapGroup%1::\n").arg(groupNum); - for (QString mapName : mapNames) { - text += QString("\t.4byte %1\n").arg(mapName); - } - text += QString("\n"); - groupNum++; - } - - text += QString("\t.align 2\n"); - text += QString("gMapGroups::\n"); - for (int i = 0; i < groupNum; i++) { - text += QString("\t.4byte gMapGroup%1\n").arg(i); - } - - saveTextFile(root + "/data/maps/groups.inc", text); -} - -void Project::saveMapConstantsHeader() { - QString text = QString("#ifndef GUARD_CONSTANTS_MAPS_H\n"); - text += QString("#define GUARD_CONSTANTS_MAPS_H\n"); - text += QString("\n"); - - int groupNum = 0; - for (QStringList mapNames : groupedMapNames) { - text += QString("// Map Group %1\n").arg(groupNum); - int maxLength = 0; - for (QString mapName : mapNames) { - QString mapConstantName = mapNamesToMapConstants->value(mapName); - if (mapConstantName.length() > maxLength) - maxLength = mapConstantName.length(); - } - int groupIndex = 0; - for (QString mapName : mapNames) { - QString mapConstantName = mapNamesToMapConstants->value(mapName); - text += QString("#define %1%2(%3 | (%4 << 8))\n") - .arg(mapConstantName) - .arg(QString(" ").repeated(maxLength - mapConstantName.length() + 1)) - .arg(groupIndex) - .arg(groupNum); - groupIndex++; - } - text += QString("\n"); - groupNum++; - } - - text += QString("\n"); - text += QString("#define MAP_NONE (0x7F | (0x7F << 8))\n"); - text += QString("#define MAP_UNDEFINED (0xFF | (0xFF << 8))\n\n\n"); - text += QString("#define MAP_GROUP(map) (MAP_##map >> 8)\n"); - text += QString("#define MAP_NUM(map) (MAP_##map & 0xFF)\n\n"); - text += QString("#endif // GUARD_CONSTANTS_MAPS_H\n"); - saveTextFile(root + "/include/constants/maps.h", text); -} - -// saves heal location coords in root + /src/data/heal_locations.h -// and indexes as defines in root + /include/constants/heal_locations.h -void Project::saveHealLocationStruct(Map *map) { - QString tab = QString(" "); - - QString data_text = QString("static const struct HealLocation sHealLocations[] =\n{\n"); - - QString constants_text = QString("#ifndef GUARD_CONSTANTS_HEAL_LOCATIONS_H\n"); - constants_text += QString("#define GUARD_CONSTANTS_HEAL_LOCATIONS_H\n\n"); - - QMap<QString, int> flyableMapsDupes; - QSet<QString> flyableMapsUnique; - - // set flyableMapsDupes and flyableMapsUnique - for (auto it = flyableMaps.begin(); it != flyableMaps.end(); it++) { - HealLocation loc = *it; - QString xname = loc.name; - if (flyableMapsUnique.contains(xname)) { - flyableMapsDupes[xname] = 1; - } - flyableMapsUnique.insert(xname); - } - - // set new location in flyableMapsList - if (map->events["heal_event_group"].length() > 0) { - for (Event *healEvent : map->events["heal_event_group"]) { - HealLocation hl = HealLocation::fromEvent(healEvent); - flyableMaps[hl.index - 1] = hl; - } - } - - int i = 1; - - for (auto map_in : flyableMaps) { - data_text += QString(" {MAP_GROUP(%1), MAP_NUM(%1), %2, %3},\n") - .arg(map_in.name) - .arg(map_in.x) - .arg(map_in.y); - - QString ending = QString(""); - - // must add _1 / _2 for maps that have duplicates - if (flyableMapsDupes.keys().contains(map_in.name)) { - // map contains multiple heal locations - ending += QString("_%1").arg(flyableMapsDupes[map_in.name]); - flyableMapsDupes[map_in.name]++; - } - if (map_in.index != 0) { - constants_text += QString("#define HEAL_LOCATION_%1 %2\n") - .arg(map_in.name + ending) - .arg(map_in.index); - } - else { - constants_text += QString("#define HEAL_LOCATION_%1 %2\n") - .arg(map_in.name + ending) - .arg(i); - } - i++; - } - - data_text += QString("};\n"); - constants_text += QString("\n#endif // GUARD_CONSTANTS_HEAL_LOCATIONS_H\n"); - - saveTextFile(root + "/src/data/heal_locations.h", data_text); - saveTextFile(root + "/include/constants/heal_locations.h", constants_text); -} - -void Project::loadMapTilesets(Map* map) { - if (map->layout->has_unsaved_changes) { - return; - } - - map->layout->tileset_primary = getTileset(map->layout->tileset_primary_label); - map->layout->tileset_secondary = getTileset(map->layout->tileset_secondary_label); -} - -Tileset* Project::loadTileset(QString label) { - ParseUtil *parser = new ParseUtil; - - QString headers_text = readTextFile(root + "/data/tilesets/headers.inc"); - QStringList *values = getLabelValues(parser->parseAsm(headers_text), label); - Tileset *tileset = new Tileset; - tileset->name = label; - tileset->is_compressed = values->value(0); - tileset->is_secondary = values->value(1); - tileset->padding = values->value(2); - tileset->tiles_label = values->value(3); - tileset->palettes_label = values->value(4); - tileset->metatiles_label = values->value(5); - tileset->metatile_attrs_label = values->value(6); - tileset->callback_label = values->value(7); - - loadTilesetAssets(tileset); - - tileset_cache->insert(label, tileset); - return tileset; -} - -void Project::loadBlockdata(Map* map) { - if (!map->isPersistedToFile || map->layout->has_unsaved_changes) { - return; - } - - QString path = QString("%1/%2").arg(root).arg(map->layout->blockdata_path); - map->layout->blockdata = readBlockdata(path); -} - -void Project::setNewMapBlockdata(Map* map) { - Blockdata *blockdata = new Blockdata; - for (int i = 0; i < map->getWidth() * map->getHeight(); i++) { - blockdata->addBlock(qint16(0x3001)); - } - map->layout->blockdata = blockdata; -} - -void Project::loadMapBorder(Map *map) { - if (!map->isPersistedToFile || map->layout->has_unsaved_changes) { - return; - } - - QString path = QString("%1/%2").arg(root).arg(map->layout->border_path); - map->layout->border = readBlockdata(path); -} - -void Project::setNewMapBorder(Map *map) { - Blockdata *blockdata = new Blockdata; - blockdata->addBlock(qint16(0x01D4)); - blockdata->addBlock(qint16(0x01D5)); - blockdata->addBlock(qint16(0x01DC)); - blockdata->addBlock(qint16(0x01DD)); - map->layout->border = blockdata; -} - -void Project::saveMapBorder(Map *map) { - QString path = QString("%1/%2").arg(root).arg(map->layout->border_path); - writeBlockdata(path, map->layout->border); -} - -void Project::saveBlockdata(Map* map) { - QString path = QString("%1/%2").arg(root).arg(map->layout->blockdata_path); - writeBlockdata(path, map->layout->blockdata); - map->metatileHistory.save(); -} - -void Project::writeBlockdata(QString path, Blockdata *blockdata) { - QFile file(path); - if (file.open(QIODevice::WriteOnly)) { - QByteArray data = blockdata->serialize(); - file.write(data); - } else { - qDebug() << "Failed to open blockdata file for writing: '" << path << "'"; - } -} - -void Project::saveAllMaps() { - QList<QString> keys = map_cache->keys(); - for (int i = 0; i < keys.length(); i++) { - QString key = keys.value(i); - Map* map = map_cache->value(key); - saveMap(map); - } -} - -void Project::saveMap(Map *map) { - // Create/Modify a few collateral files for brand new maps. - if (!map->isPersistedToFile) { - QString newMapDataDir = QString(root + "/data/maps/%1").arg(map->name); - if (!QDir::root().mkdir(newMapDataDir)) { - qDebug() << "Error: failed to create directory for new map. " << newMapDataDir; - } - - QString newLayoutDir = QString(root + "/data/layouts/%1").arg(map->name); - if (!QDir::root().mkdir(newLayoutDir)) { - qDebug() << "Error: failed to create directory for new layout. " << newLayoutDir; - } - - // TODO: In the future, these files needs more structure to allow for proper parsing/saving. - // Create file data/maps/<map_name>/scripts.inc - QString text = QString("%1_MapScripts::\n\t.byte 0\n").arg(map->name); - saveTextFile(root + "/data/maps/" + map->name + "/scripts.inc", text); - - // Create file data/maps/<map_name>/text.inc - saveTextFile(root + "/data/maps/" + map->name + "/text.inc", "\n"); - - // Simply append to data/event_scripts.s. - text = QString("\n\t.include \"data/maps/%1/scripts.inc\"\n").arg(map->name); - text += QString("\t.include \"data/maps/%1/text.inc\"\n").arg(map->name); - appendTextFile(root + "/data/event_scripts.s", text); - - // Simply append to data/map_events.s. - text = QString("\n\t.include \"data/maps/%1/events.inc\"\n").arg(map->name); - appendTextFile(root + "/data/map_events.s", text); - - // Simply append to data/maps/headers.inc. - text = QString("\t.include \"data/maps/%1/header.inc\"\n").arg(map->name); - appendTextFile(root + "/data/maps/headers.inc", text); - - // Simply append to data/layouts.inc. - text = QString("\t.include \"data/layouts/%1/layout.inc\"\n").arg(map->layout->name); - appendTextFile(root + "/data/layouts.inc", text); - } - - saveMapBorder(map); - saveMapHeader(map); - saveMapConnections(map); - saveBlockdata(map); - saveMapEvents(map); - - // Update global data structures with current map data. - updateMapLayout(map); - - map->isPersistedToFile = true; - map->layout->has_unsaved_changes = false; -} - -void Project::updateMapLayout(Map* map) { - if (!mapLayoutsTableMaster.contains(map->layout_label)) { - mapLayoutsTableMaster.append(map->layout_label); - } - - // Deep copy - MapLayout *layout = mapLayouts.value(map->layout_label); - MapLayout *newLayout = new MapLayout(); - *newLayout = *layout; - mapLayoutsMaster.insert(map->layout_label, newLayout); -} - -void Project::saveAllDataStructures() { - saveMapLayoutsTable(); - saveAllMapLayouts(); - saveMapGroupsTable(); - saveMapConstantsHeader(); - saveMapsWithConnections(); -} - -void Project::loadTilesetAssets(Tileset* tileset) { - ParseUtil* parser = new ParseUtil; - QString category = (tileset->is_secondary == "TRUE") ? "secondary" : "primary"; - if (tileset->name.isNull()) { - return; - } - QString dir_path = root + "/data/tilesets/" + category + "/" + tileset->name.replace("gTileset_", "").toLower(); - - QString graphics_text = readTextFile(root + "/data/tilesets/graphics.inc"); - QList<QStringList> *graphics = parser->parseAsm(graphics_text); - QStringList *tiles_values = getLabelValues(graphics, tileset->tiles_label); - QStringList *palettes_values = getLabelValues(graphics, tileset->palettes_label); - - QString tiles_path; - if (!tiles_values->isEmpty()) { - tiles_path = root + "/" + tiles_values->value(0).section('"', 1, 1); - } else { - tiles_path = dir_path + "/tiles.4bpp"; - if (tileset->is_compressed == "TRUE") { - tiles_path += ".lz"; - } - } - - QStringList *palette_paths = new QStringList; - if (!palettes_values->isEmpty()) { - for (int i = 0; i < palettes_values->length(); i++) { - QString value = palettes_values->value(i); - palette_paths->append(root + "/" + value.section('"', 1, 1)); - } - } else { - QString palettes_dir_path = dir_path + "/palettes"; - for (int i = 0; i < 16; i++) { - palette_paths->append(palettes_dir_path + "/" + QString("%1").arg(i, 2, 10, QLatin1Char('0')) + ".gbapal"); - } - } - - QString metatiles_path; - QString metatile_attrs_path; - QString metatiles_text = readTextFile(root + "/data/tilesets/metatiles.inc"); - QList<QStringList> *metatiles_macros = parser->parseAsm(metatiles_text); - QStringList *metatiles_values = getLabelValues(metatiles_macros, tileset->metatiles_label); - if (!metatiles_values->isEmpty()) { - metatiles_path = root + "/" + metatiles_values->value(0).section('"', 1, 1); - } else { - metatiles_path = dir_path + "/metatiles.bin"; - } - QStringList *metatile_attrs_values = getLabelValues(metatiles_macros, tileset->metatile_attrs_label); - if (!metatile_attrs_values->isEmpty()) { - metatile_attrs_path = root + "/" + metatile_attrs_values->value(0).section('"', 1, 1); - } else { - metatile_attrs_path = dir_path + "/metatile_attributes.bin"; - } - - // tiles - tiles_path = fixGraphicPath(tiles_path); - QImage *image = new QImage(tiles_path); - //image->setColor(0, qRgb(0xff, 0, 0)); // debug - - QList<QImage> *tiles = new QList<QImage>; - int w = 8; - int h = 8; - for (int y = 0; y < image->height(); y += h) - for (int x = 0; x < image->width(); x += w) { - QImage tile = image->copy(x, y, w, h); - tiles->append(tile); - } - tileset->tiles = tiles; - - // metatiles - QFile metatiles_file(metatiles_path); - if (metatiles_file.open(QIODevice::ReadOnly)) { - QByteArray data = metatiles_file.readAll(); - int num_metatiles = data.length() / 16; - int num_layers = 2; - QList<Metatile*> *metatiles = new QList<Metatile*>; - for (int i = 0; i < num_metatiles; i++) { - Metatile *metatile = new Metatile; - int index = i * (2 * 4 * num_layers); - for (int j = 0; j < 4 * num_layers; j++) { - uint16_t word = data[index++] & 0xff; - word += (data[index++] & 0xff) << 8; - Tile tile; - tile.tile = word & 0x3ff; - tile.xflip = (word >> 10) & 1; - tile.yflip = (word >> 11) & 1; - tile.palette = (word >> 12) & 0xf; - metatile->tiles->append(tile); - } - metatiles->append(metatile); - } - tileset->metatiles = metatiles; - } else { - tileset->metatiles = new QList<Metatile*>; - qDebug() << QString("Could not open '%1'").arg(metatiles_path); - } - - QFile attrs_file(metatile_attrs_path); - //qDebug() << metatile_attrs_path; - if (attrs_file.open(QIODevice::ReadOnly)) { - QByteArray data = attrs_file.readAll(); - int num_metatiles = tileset->metatiles->count(); - int num_metatileAttrs = data.length() / 2; - if (num_metatiles != num_metatileAttrs) { - qDebug() << QString("Metatile count %1 does not match metatile attribute count %2").arg(num_metatiles).arg(num_metatileAttrs); - if (num_metatiles > num_metatileAttrs) - num_metatiles = num_metatileAttrs; - } - } else { - qDebug() << QString("Could not open '%1'").arg(metatile_attrs_path); - } - - // palettes - QList<QList<QRgb>> *palettes = new QList<QList<QRgb>>; - for (int i = 0; i < palette_paths->length(); i++) { - QString path = palette_paths->value(i); - // the palettes are not compressed. this should never happen. it's only a precaution. - path = path.replace(QRegExp("\\.lz$"), ""); - // TODO default to .pal (JASC-PAL) - // just use .gbapal for now - QFile file(path); - QList<QRgb> palette; - if (file.open(QIODevice::ReadOnly)) { - QByteArray data = file.readAll(); - for (int j = 0; j < 16; j++) { - uint16_t word = data[j*2] & 0xff; - word += (data[j*2 + 1] & 0xff) << 8; - int red = word & 0x1f; - int green = (word >> 5) & 0x1f; - int blue = (word >> 10) & 0x1f; - QRgb color = qRgb(red * 8, green * 8, blue * 8); - palette.append(color); - } - } else { - for (int j = 0; j < 16; j++) { - palette.append(qRgb(j * 16, j * 16, j * 16)); - } - qDebug() << QString("Could not open palette path '%1'").arg(path); - } - - palettes->append(palette); - } - tileset->palettes = palettes; -} - -Blockdata* Project::readBlockdata(QString path) { - Blockdata *blockdata = new Blockdata; - QFile file(path); - if (file.open(QIODevice::ReadOnly)) { - QByteArray data = file.readAll(); - for (int i = 0; (i + 1) < data.length(); i += 2) { - uint16_t word = static_cast<uint16_t>((data[i] & 0xff) + ((data[i + 1] & 0xff) << 8)); - blockdata->addBlock(word); - } - } else { - qDebug() << "Failed to open blockdata path '" << path << "'"; - } - - return blockdata; -} - -Map* Project::getMap(QString map_name) { - if (map_cache->contains(map_name)) { - return map_cache->value(map_name); - } else { - Map *map = loadMap(map_name); - return map; - } -} - -Tileset* Project::getTileset(QString label) { - if (tileset_cache->contains(label)) { - return tileset_cache->value(label); - } else { - Tileset *tileset = loadTileset(label); - return tileset; - } -} - -QString Project::readTextFile(QString path) { - QFile file(path); - if (!file.open(QIODevice::ReadOnly)) { - //QMessageBox::information(0, "Error", QString("Could not open '%1': ").arg(path) + file.errorString()); - qDebug() << QString("Could not open '%1': ").arg(path) + file.errorString(); - return QString(); - } - QTextStream in(&file); - QString text = ""; - while (!in.atEnd()) { - text += in.readLine() + "\n"; - } - return text; -} - -void Project::saveTextFile(QString path, QString text) { - QFile file(path); - if (file.open(QIODevice::WriteOnly)) { - file.write(text.toUtf8()); - } else { - qDebug() << QString("Could not open '%1' for writing: ").arg(path) + file.errorString(); - } -} - -void Project::appendTextFile(QString path, QString text) { - QFile file(path); - if (file.open(QIODevice::Append)) { - file.write(text.toUtf8()); - } else { - qDebug() << QString("Could not open '%1' for appending: ").arg(path) + file.errorString(); - } -} - -void Project::deleteFile(QString path) { - QFile file(path); - if (file.exists() && !file.remove()) { - qDebug() << QString("Could not delete file '%1': ").arg(path) + file.errorString(); - } -} - -void Project::readMapGroups() { - QString text = readTextFile(root + "/data/maps/groups.inc"); - if (text.isNull()) { - return; - } - ParseUtil *parser = new ParseUtil; - QList<QStringList> *commands = parser->parseAsm(text); - - bool in_group_pointers = false; - QStringList *groups = new QStringList; - for (int i = 0; i < commands->length(); i++) { - QStringList params = commands->value(i); - QString macro = params.value(0); - if (macro == ".label") { - if (in_group_pointers) { - break; - } - if (params.value(1) == "gMapGroups") { - in_group_pointers = true; - } - } else if (macro == ".4byte") { - if (in_group_pointers) { - for (int j = 1; j < params.length(); j++) { - groups->append(params.value(j)); - } - } - } - } - - QList<QStringList> groupedMaps; - for (int i = 0; i < groups->length(); i++) { - groupedMaps.append(QStringList()); - } - - QStringList *maps = new QStringList; - int group = -1; - for (int i = 0; i < commands->length(); i++) { - QStringList params = commands->value(i); - QString macro = params.value(0); - if (macro == ".label") { - group = groups->indexOf(params.value(1)); - } else if (macro == ".4byte") { - if (group != -1) { - for (int j = 1; j < params.length(); j++) { - QString mapName = params.value(j); - groupedMaps[group].append(mapName); - maps->append(mapName); - map_groups->insert(mapName, group); - - // Build the mapping and reverse mapping between map constants and map names. - QString mapConstant = Map::mapConstantFromName(mapName); - mapConstantsToMapNames->insert(mapConstant, mapName); - mapNamesToMapConstants->insert(mapName, mapConstant); - } - } - } - } - - mapConstantsToMapNames->insert(NONE_MAP_CONSTANT, NONE_MAP_NAME); - mapNamesToMapConstants->insert(NONE_MAP_NAME, NONE_MAP_CONSTANT); - maps->append(NONE_MAP_NAME); - - groupNames = groups; - groupedMapNames = groupedMaps; - mapNames = maps; - - QString hltext = readTextFile(root + QString("/src/data/heal_locations.h")); - QList<HealLocation>* hl = parser->parseHealLocs(hltext); - flyableMaps = *hl; - delete hl; -} - -Map* Project::addNewMapToGroup(QString mapName, int groupNum) { - // Setup new map in memory, but don't write to file until map is actually saved later. - mapNames->append(mapName); - map_groups->insert(mapName, groupNum); - groupedMapNames[groupNum].append(mapName); - - Map *map = new Map; - map->isPersistedToFile = false; - map->setName(mapName); - mapConstantsToMapNames->insert(map->constantName, map->name); - mapNamesToMapConstants->insert(map->name, map->constantName); - setNewMapHeader(map, mapLayoutsTable.size() + 1); - setNewMapLayout(map); - loadMapTilesets(map); - setNewMapBlockdata(map); - setNewMapBorder(map); - setNewMapEvents(map); - setNewMapConnections(map); - map->commit(); - map->metatileHistory.save(); - map_cache->insert(mapName, map); - - return map; -} - -QString Project::getNewMapName() { - // Ensure default name doesn't already exist. - int i = 0; - QString newMapName; - do { - newMapName = QString("NewMap%1").arg(++i); - } while (mapNames->contains(newMapName)); - - return newMapName; -} - -QList<QStringList>* Project::parseAsm(QString text) { - ParseUtil *parser = new ParseUtil; - return parser->parseAsm(text); -} - -QStringList Project::getVisibilities() { - // TODO - QStringList names; - for (int i = 0; i < 16; i++) { - names.append(QString("%1").arg(i)); - } - return names; -} - -QMap<QString, QStringList> Project::getTilesets() { - QMap<QString, QStringList> allTilesets; - QStringList primaryTilesets; - QStringList secondaryTilesets; - allTilesets.insert("primary", primaryTilesets); - allTilesets.insert("secondary", secondaryTilesets); - QString headers_text = readTextFile(root + "/data/tilesets/headers.inc"); - QList<QStringList>* commands = parseAsm(headers_text); - int i = 0; - while (i < commands->length()) { - if (commands->at(i).length() != 2) - continue; - - if (commands->at(i).at(0) == ".label") { - QString tilesetLabel = commands->at(i).at(1); - // Advance to command specifying whether or not it is a secondary tileset - i += 2; - if (commands->at(i).at(0) != ".byte") { - qDebug() << "Unexpected command found for secondary tileset flag in tileset" << tilesetLabel << ". Expected '.byte', but found: " << commands->at(i).at(0); - continue; - } - - QString secondaryTilesetValue = commands->at(i).at(1); - if (secondaryTilesetValue != "TRUE" && secondaryTilesetValue != "FALSE" && secondaryTilesetValue != "0" && secondaryTilesetValue != "1") { - qDebug() << "Unexpected secondary tileset flag found. Expected \"TRUE\", \"FALSE\", \"0\", or \"1\", but found: " << secondaryTilesetValue; - continue; - } - - bool isSecondaryTileset = (secondaryTilesetValue == "TRUE" || secondaryTilesetValue == "1"); - if (isSecondaryTileset) - allTilesets["secondary"].append(tilesetLabel); - else - allTilesets["primary"].append(tilesetLabel); - } - - i++; - } - - return allTilesets; -} - -void Project::readTilesetProperties() { - QStringList defines; - QString text = readTextFile(root + "/include/fieldmap.h"); - if (!text.isNull()) { - bool error = false; - QStringList definePrefixes; - definePrefixes << "NUM_"; - QMap<QString, int> defines = readCDefines(text, definePrefixes); - auto it = defines.find("NUM_TILES_IN_PRIMARY"); - if (it != defines.end()) { - Project::num_tiles_primary = it.value(); - } - else { - error = true; - } - it = defines.find("NUM_TILES_TOTAL"); - if (it != defines.end()) { - Project::num_tiles_total = it.value(); - } - else { - error = true; - } - it = defines.find("NUM_METATILES_IN_PRIMARY"); - if (it != defines.end()) { - Project::num_metatiles_primary = it.value(); - } - else { - error = true; - } - it = defines.find("NUM_METATILES_TOTAL"); - if (it != defines.end()) { - Project::num_metatiles_total = it.value(); - } - else { - error = true; - } - it = defines.find("NUM_PALS_IN_PRIMARY"); - if (it != defines.end()) { - Project::num_pals_primary = it.value(); - } - else { - error = true; - } - it = defines.find("NUM_PALS_TOTAL"); - if (it != defines.end()) { - Project::num_pals_total = it.value(); - } - else { - error = true; - } - - if (error) - { - qDebug() << "Some global tileset values could not be loaded. Using default values"; - } - } -} - -void Project::readRegionMapSections() { - QString filepath = root + "/include/constants/region_map_sections.h"; - QStringList prefixes = (QStringList() << "MAPSEC_"); - readCDefinesSorted(filepath, prefixes, regionMapSections); -} - -void Project::readItemNames() { - QString filepath = root + "/include/constants/items.h"; - QStringList prefixes = (QStringList() << "ITEM_"); - readCDefinesSorted(filepath, prefixes, itemNames); -} - -void Project::readFlagNames() { - QString filepath = root + "/include/constants/flags.h"; - QStringList prefixes = (QStringList() << "FLAG_"); - readCDefinesSorted(filepath, prefixes, flagNames); -} - -void Project::readVarNames() { - QString filepath = root + "/include/constants/vars.h"; - QStringList prefixes = (QStringList() << "VAR_"); - readCDefinesSorted(filepath, prefixes, varNames); -} - -void Project::readMovementTypes() { - QString filepath = root + "/include/constants/event_object_movement_constants.h"; - QStringList prefixes = (QStringList() << "MOVEMENT_TYPE_"); - readCDefinesSorted(filepath, prefixes, movementTypes); -} - -void Project::readMapTypes() { - QString filepath = root + "/include/constants/map_types.h"; - QStringList prefixes = (QStringList() << "MAP_TYPE_"); - readCDefinesSorted(filepath, prefixes, mapTypes); -} - -void Project::readMapBattleScenes() { - QString filepath = root + "/include/constants/map_types.h"; - QStringList prefixes = (QStringList() << "MAP_BATTLE_SCENE_"); - readCDefinesSorted(filepath, prefixes, mapBattleScenes); -} - -void Project::readWeatherNames() { - QString filepath = root + "/include/constants/weather.h"; - QStringList prefixes = (QStringList() << "WEATHER_"); - readCDefinesSorted(filepath, prefixes, weatherNames); -} - -void Project::readCoordEventWeatherNames() { - QString filepath = root + "/include/constants/weather.h"; - QStringList prefixes = (QStringList() << "COORD_EVENT_WEATHER_"); - readCDefinesSorted(filepath, prefixes, coordEventWeatherNames); -} - -void Project::readSecretBaseIds() { - QString filepath = root + "/include/constants/secret_bases.h"; - QStringList prefixes = (QStringList() << "SECRET_BASE_"); - readCDefinesSorted(filepath, prefixes, secretBaseIds); -} - -void Project::readBgEventFacingDirections() { - QString filepath = root + "/include/constants/bg_event_constants.h"; - QStringList prefixes = (QStringList() << "BG_EVENT_PLAYER_FACING_"); - readCDefinesSorted(filepath, prefixes, bgEventFacingDirections); -} - -void Project::readCDefinesSorted(QString filepath, QStringList prefixes, QStringList* definesToSet) { - QString text = readTextFile(filepath); - if (!text.isNull()) { - QMap<QString, int> defines = readCDefines(text, prefixes); - - // The defines should to be sorted by their underlying value, not alphabetically. - // Reverse the map and read out the resulting keys in order. - QMultiMap<int, QString> definesInverse; - for (QString defineName : defines.keys()) { - definesInverse.insert(defines[defineName], defineName); - } - *definesToSet = definesInverse.values(); - } else { - qDebug() << "Failed to read C defines file: " << filepath; - } -} - -void Project::readMapsWithConnections() { - QString path = root + "/data/maps/connections.inc"; - QString text = readTextFile(path); - if (text.isNull()) { - return; - } - - mapsWithConnections.clear(); - QRegularExpression re("data\\/maps\\/(?<mapName>\\w+)\\/connections.inc"); - QList<QStringList>* includes = parseAsm(text); - for (QStringList values : *includes) { - if (values.length() != 2) - continue; - - QRegularExpressionMatch match = re.match(values.value(1)); - if (match.hasMatch()) { - QString mapName = match.captured("mapName"); - mapsWithConnections.append(mapName); - } - } -} - -void Project::saveMapsWithConnections() { - QString path = root + "/data/maps/connections.inc"; - QString text = ""; - for (QString mapName : mapsWithConnections) { - if (mapNamesToMapConstants->contains(mapName)) { - text += QString("\t.include \"data/maps/%1/connections.inc\"\n").arg(mapName); - } else { - qDebug() << QString("Failed to write connection include. %1 not a valid map name").arg(mapName); - } - } - saveTextFile(path, text); -} - -QStringList Project::getSongNames() { - QStringList names; - QString text = readTextFile(root + "/include/constants/songs.h"); - if (!text.isNull()) { - QStringList songDefinePrefixes; - songDefinePrefixes << "SE_" << "MUS_"; - QMap<QString, int> songDefines = readCDefines(text, songDefinePrefixes); - names = songDefines.keys(); - } - return names; -} - -QMap<QString, int> Project::getEventObjGfxConstants() { - QMap<QString, int> constants; - QString text = readTextFile(root + "/include/constants/event_objects.h"); - if (!text.isNull()) { - QStringList eventObjGfxPrefixes; - eventObjGfxPrefixes << "EVENT_OBJ_GFX_"; - constants = readCDefines(text, eventObjGfxPrefixes); - } - return constants; -} - -QString Project::fixGraphicPath(QString path) { - path = path.replace(QRegExp("\\.lz$"), ""); - path = path.replace(QRegExp("\\.[1248]bpp$"), ".png"); - return path; -} - -void Project::loadEventPixmaps(QList<Event*> objects) { - bool needs_update = false; - for (Event *object : objects) { - if (object->pixmap.isNull()) { - needs_update = true; - break; - } - } - if (!needs_update) { - return; - } - - QMap<QString, int> constants = getEventObjGfxConstants(); - - QString pointers_text = readTextFile(root + "/src/data/field_event_obj/event_object_graphics_info_pointers.h"); - QString info_text = readTextFile(root + "/src/data/field_event_obj/event_object_graphics_info.h"); - QString pic_text = readTextFile(root + "/src/data/field_event_obj/event_object_pic_tables.h"); - QString assets_text = readTextFile(root + "/src/data/field_event_obj/event_object_graphics.h"); - - QStringList pointers = readCArray(pointers_text, "gEventObjectGraphicsInfoPointers"); - - for (Event *object : objects) { - if (!object->pixmap.isNull()) { - continue; - } - - object->spriteWidth = 16; - object->spriteHeight = 16; - QString event_type = object->get("event_type"); - if (event_type == EventType::Object) { - object->pixmap = QPixmap(":/images/Entities_16x16.png").copy(0, 0, 16, 16); - } else if (event_type == EventType::Warp) { - object->pixmap = QPixmap(":/images/Entities_16x16.png").copy(16, 0, 16, 16); - } else if (event_type == EventType::CoordScript || event_type == EventType::CoordWeather) { - object->pixmap = QPixmap(":/images/Entities_16x16.png").copy(32, 0, 16, 16); - } else if (event_type == EventType::Sign || event_type == EventType::HiddenItem || event_type == EventType::SecretBase) { - object->pixmap = QPixmap(":/images/Entities_16x16.png").copy(48, 0, 16, 16); - } else if (event_type == EventType::HealLocation) { - object->pixmap = QPixmap(":/images/Entities_16x16.png").copy(64, 0, 16, 16); - } - - if (event_type == EventType::Object) { - int sprite_id = constants.value(object->get("sprite")); - - QString info_label = pointers.value(sprite_id).replace("&", ""); - QStringList gfx_info = readCArray(info_text, info_label); - QString pic_label = gfx_info.value(14); - QString dimensions_label = gfx_info.value(11); - QString subsprites_label = gfx_info.value(12); - QString gfx_label = readCArray(pic_text, pic_label).value(0); - gfx_label = gfx_label.section(QRegExp("[\\(\\)]"), 1, 1); - QString path = readCIncbin(assets_text, gfx_label); - - if (!path.isNull()) { - path = fixGraphicPath(path); - QImage spritesheet(root + "/" + path); - if (!spritesheet.isNull()) { - // Infer the sprite dimensions from the OAM labels. - int spriteWidth = spritesheet.width(); - int spriteHeight = spritesheet.height(); - QRegularExpression re("\\S+_(\\d+)x(\\d+)"); - QRegularExpressionMatch dimensionMatch = re.match(dimensions_label); - if (dimensionMatch.hasMatch()) { - QRegularExpressionMatch oamTablesMatch = re.match(subsprites_label); - if (oamTablesMatch.hasMatch()) { - spriteWidth = dimensionMatch.captured(1).toInt(); - spriteHeight = dimensionMatch.captured(2).toInt(); - } - } - object->setPixmapFromSpritesheet(spritesheet, spriteWidth, spriteHeight); - } - } - } - } -} - -void Project::saveMapEvents(Map *map) { - QString path = root + QString("/data/maps/%1/events.inc").arg(map->name); - QString text = ""; - QString objectEventsLabel = "0x0"; - QString warpEventsLabel = "0x0"; - QString coordEventsLabel = "0x0"; - QString bgEventsLabel = "0x0"; - - if (map->events["object_event_group"].length() > 0) { - objectEventsLabel = Map::objectEventsLabelFromName(map->name); - text += QString("%1::\n").arg(objectEventsLabel); - for (int i = 0; i < map->events["object_event_group"].length(); i++) { - Event *object_event = map->events["object_event_group"].value(i); - text += object_event->buildObjectEventMacro(i); - } - text += "\n"; - } - - if (map->events["warp_event_group"].length() > 0) { - warpEventsLabel = Map::warpEventsLabelFromName(map->name); - text += QString("%1::\n").arg(warpEventsLabel); - for (Event *warp : map->events["warp_event_group"]) { - text += warp->buildWarpEventMacro(mapNamesToMapConstants); - } - text += "\n"; - } - - if (map->events["coord_event_group"].length() > 0) { - coordEventsLabel = Map::coordEventsLabelFromName(map->name); - text += QString("%1::\n").arg(coordEventsLabel); - for (Event *event : map->events["coord_event_group"]) { - QString event_type = event->get("event_type"); - if (event_type == EventType::CoordScript) { - text += event->buildCoordScriptEventMacro(); - } else if (event_type == EventType::CoordWeather) { - text += event->buildCoordWeatherEventMacro(); - } - } - text += "\n"; - } - - if (map->events["bg_event_group"].length() > 0) - { - bgEventsLabel = Map::bgEventsLabelFromName(map->name); - text += QString("%1::\n").arg(bgEventsLabel); - for (Event *event : map->events["bg_event_group"]) { - QString event_type = event->get("event_type"); - if (event_type == EventType::Sign) { - text += event->buildSignEventMacro(); - } else if (event_type == EventType::HiddenItem) { - text += event->buildHiddenItemEventMacro(); - } else if (event_type == EventType::SecretBase) { - text += event->buildSecretBaseEventMacro(); - } - } - text += "\n"; - } - - text += QString("%1::\n").arg(map->events_label); - text += QString("\tmap_events %1, %2, %3, %4\n") - .arg(objectEventsLabel) - .arg(warpEventsLabel) - .arg(coordEventsLabel) - .arg(bgEventsLabel); - - saveTextFile(path, text); - - // save heal event changes - if (map->events["heal_event_group"].length() > 0) { - for (Event *healEvent : map->events["heal_event_group"]) { - HealLocation hl = HealLocation::fromEvent(healEvent); - flyableMaps[hl.index - 1] = hl; - } - } - saveHealLocationStruct(map); -} - -void Project::readMapEvents(Map *map) { - if (!map->isPersistedToFile) { - return; - } - - // lazy - QString path = root + QString("/data/maps/%1/events.inc").arg(map->name); - QString text = readTextFile(path); - if (text.isNull()) { - return; - } - - QStringList *labels = getLabelValues(parseAsm(text), map->events_label); - QString objectEventsLabel = labels->value(0); - QString warpEventsLabel = labels->value(1); - QString coordEventsLabel = labels->value(2); - QString bgEventsLabel = labels->value(3); - - QList<QStringList> *object_events = getLabelMacros(parseAsm(text), objectEventsLabel); - map->events["object_event_group"].clear(); - for (QStringList command : *object_events) { - if (command.value(0) == "object_event") { - Event *object = new Event; - object->put("map_name", map->name); - int i = 2; - object->put("sprite", command.value(i++)); - object->put("replacement", command.value(i++)); - object->put("x", command.value(i++).toInt(nullptr, 0)); - object->put("y", command.value(i++).toInt(nullptr, 0)); - object->put("elevation", command.value(i++)); - object->put("movement_type", command.value(i++)); - object->put("radius_x", command.value(i++).toInt(nullptr, 0)); - object->put("radius_y", command.value(i++).toInt(nullptr, 0)); - object->put("is_trainer", command.value(i++)); - object->put("sight_radius_tree_id", command.value(i++)); - object->put("script_label", command.value(i++)); - object->put("event_flag", command.value(i++)); - object->put("event_group_type", "object_event_group"); - object->put("event_type", EventType::Object); - map->events["object_event_group"].append(object); - } - } - - QList<QStringList> *warps = getLabelMacros(parseAsm(text), warpEventsLabel); - map->events["warp_event_group"].clear(); - for (QStringList command : *warps) { - if (command.value(0) == "warp_def") { - Event *warp = new Event; - warp->put("map_name", map->name); - int i = 1; - warp->put("x", command.value(i++)); - warp->put("y", command.value(i++)); - warp->put("elevation", command.value(i++)); - warp->put("destination_warp", command.value(i++)); - - // Ensure the warp destination map constant is valid before adding it to the warps. - QString mapConstant = command.value(i++); - if (mapConstantsToMapNames->contains(mapConstant)) { - warp->put("destination_map_name", mapConstantsToMapNames->value(mapConstant)); - warp->put("event_group_type", "warp_event_group"); - warp->put("event_type", EventType::Warp); - map->events["warp_event_group"].append(warp); - } else if (mapConstant == NONE_MAP_CONSTANT) { - warp->put("destination_map_name", NONE_MAP_NAME); - warp->put("event_group_type", "warp_event_group"); - warp->put("event_type", EventType::Warp); - map->events["warp_event_group"].append(warp); - } else { - qDebug() << QString("Destination map constant '%1' is invalid for warp").arg(mapConstant); - } - } - } - - map->events["heal_event_group"].clear(); - - for (auto it = flyableMaps.begin(); it != flyableMaps.end(); it++) { - - HealLocation loc = *it; - - //if TRUE map is flyable / has healing location - if (loc.name == QString(mapNamesToMapConstants->value(map->name)).remove(0,4)) { - Event *heal = new Event; - heal->put("map_name", map->name); - heal->put("x", loc.x); - heal->put("y", loc.y); - heal->put("loc_name", loc.name); - heal->put("index", loc.index); - heal->put("elevation", 3); // TODO: change this? - heal->put("destination_map_name", mapConstantsToMapNames->value(map->name)); - heal->put("event_group_type", "heal_event_group"); - heal->put("event_type", EventType::HealLocation); - map->events["heal_event_group"].append(heal); - } - - } - - QList<QStringList> *coords = getLabelMacros(parseAsm(text), coordEventsLabel); - map->events["coord_event_group"].clear(); - for (QStringList command : *coords) { - if (command.value(0) == "coord_event") { - Event *coord = new Event; - coord->put("map_name", map->name); - int i = 1; - coord->put("x", command.value(i++)); - coord->put("y", command.value(i++)); - coord->put("elevation", command.value(i++)); - coord->put("script_var", command.value(i++)); - coord->put("script_var_value", command.value(i++)); - coord->put("script_label", command.value(i++)); - coord->put("event_group_type", "coord_event_group"); - coord->put("event_type", EventType::CoordScript); - map->events["coord_event_group"].append(coord); - } else if (command.value(0) == "coord_weather_event") { - Event *coord = new Event; - coord->put("map_name", map->name); - int i = 1; - coord->put("x", command.value(i++)); - coord->put("y", command.value(i++)); - coord->put("elevation", command.value(i++)); - coord->put("weather", command.value(i++)); - coord->put("event_group_type", "coord_event_group"); - coord->put("event_type", EventType::CoordWeather); - map->events["coord_event_group"].append(coord); - } - } - - QList<QStringList> *bgs = getLabelMacros(parseAsm(text), bgEventsLabel); - map->events["bg_event_group"].clear(); - for (QStringList command : *bgs) { - if (command.value(0) == "bg_event") { - Event *bg = new Event; - bg->put("map_name", map->name); - int i = 1; - bg->put("x", command.value(i++)); - bg->put("y", command.value(i++)); - bg->put("elevation", command.value(i++)); - bg->put("player_facing_direction", command.value(i++)); - bg->put("script_label", command.value(i++)); - //sign_unknown7 - bg->put("event_group_type", "bg_event_group"); - bg->put("event_type", EventType::Sign); - map->events["bg_event_group"].append(bg); - } else if (command.value(0) == "bg_hidden_item_event") { - Event *bg = new Event; - bg->put("map_name", map->name); - int i = 1; - bg->put("x", command.value(i++)); - bg->put("y", command.value(i++)); - bg->put("elevation", command.value(i++)); - bg->put("item", command.value(i++)); - bg->put("flag", command.value(i++)); - bg->put("event_group_type", "bg_event_group"); - bg->put("event_type", EventType::HiddenItem); - map->events["bg_event_group"].append(bg); - } else if (command.value(0) == "bg_secret_base_event") { - Event *bg = new Event; - bg->put("map_name", map->name); - int i = 1; - bg->put("x", command.value(i++)); - bg->put("y", command.value(i++)); - bg->put("elevation", command.value(i++)); - bg->put("secret_base_id", command.value(i++)); - bg->put("event_group_type", "bg_event_group"); - bg->put("event_type", EventType::SecretBase); - map->events["bg_event_group"].append(bg); - } - } -} - -void Project::setNewMapEvents(Map *map) { - map->events["object_event_group"].clear(); - map->events["warp_event_group"].clear(); - map->events["heal_event_group"].clear(); - map->events["coord_event_group"].clear(); - map->events["bg_event_group"].clear(); -} - -QStringList Project::readCArray(QString text, QString label) { - QStringList list; - - if (label.isNull()) { - return list; - } - - QRegExp *re = new QRegExp(QString("\\b%1\\b\\s*\\[?\\s*\\]?\\s*=\\s*\\{([^\\}]*)\\}").arg(label)); - int pos = re->indexIn(text); - if (pos != -1) { - QString body = re->cap(1); - body = body.replace(QRegExp("\\s*"), ""); - list = body.split(','); - /* - QRegExp *inner = new QRegExp("&?\\b([A-Za-z0-9_\\(\\)]*)\\b,"); - int pos = 0; - while ((pos = inner->indexIn(body, pos)) != -1) { - list << inner->cap(1); - pos += inner->matchedLength(); - } - */ - } - - return list; -} - -QString Project::readCIncbin(QString text, QString label) { - QString path; - - if (label.isNull()) { - return path; - } - - QRegExp *re = new QRegExp(QString( - "\\b%1\\b" - "\\s*\\[?\\s*\\]?\\s*=\\s*" - "INCBIN_[US][0-9][0-9]?" - "\\(\"([^\"]*)\"\\)").arg(label)); - - int pos = re->indexIn(text); - if (pos != -1) { - path = re->cap(1); - } - - return path; -} - -QMap<QString, int> Project::readCDefines(QString text, QStringList prefixes) { - ParseUtil parser; - QMap<QString, int> allDefines; - QMap<QString, int> filteredDefines; - QRegularExpression re("#define\\s+(?<defineName>\\w+)[^\\S\\n]+(?<defineValue>.+)"); - QRegularExpressionMatchIterator iter = re.globalMatch(text); - while (iter.hasNext()) { - QRegularExpressionMatch match = iter.next(); - QString name = match.captured("defineName"); - QString expression = match.captured("defineValue"); - expression.replace(QRegularExpression("//.*"), ""); - int value = parser.evaluateDefine(expression, &allDefines); - allDefines.insert(name, value); - for (QString prefix : prefixes) { - if (name.startsWith(prefix)) { - filteredDefines.insert(name, value); - } - } - } - return filteredDefines; -} - -int Project::getNumTilesPrimary() -{ - return Project::num_tiles_primary; -} - -int Project::getNumTilesTotal() -{ - return Project::num_tiles_total; -} - -int Project::getNumMetatilesPrimary() -{ - return Project::num_metatiles_primary; -} - -int Project::getNumMetatilesTotal() -{ - return Project::num_metatiles_total; -} - -int Project::getNumPalettesPrimary() -{ - return Project::num_pals_primary; -} - -int Project::getNumPalettesTotal() -{ - return Project::num_pals_total; -} +#include "project.h" +#include "history.h" +#include "historyitem.h" +#include "parseutil.h" +#include "tile.h" +#include "tileset.h" +#include "event.h" + +#include <QDebug> +#include <QDir> +#include <QFile> +#include <QTextStream> +#include <QStandardItem> +#include <QMessageBox> +#include <QRegularExpression> + +int Project::num_tiles_primary = 512; +int Project::num_tiles_total = 1024; +int Project::num_metatiles_primary = 512; +int Project::num_metatiles_total = 1024; +int Project::num_pals_primary = 6; +int Project::num_pals_total = 13; + +Project::Project() +{ + groupNames = new QStringList; + map_groups = new QMap<QString, int>; + mapNames = new QStringList; + regionMapSections = new QStringList; + itemNames = new QStringList; + flagNames = new QStringList; + varNames = new QStringList; + movementTypes = new QStringList; + mapTypes = new QStringList; + mapBattleScenes = new QStringList; + weatherNames = new QStringList; + coordEventWeatherNames = new QStringList; + secretBaseIds = new QStringList; + bgEventFacingDirections = new QStringList; + map_cache = new QMap<QString, Map*>; + mapConstantsToMapNames = new QMap<QString, QString>; + mapNamesToMapConstants = new QMap<QString, QString>; + tileset_cache = new QMap<QString, Tileset*>; +} + +QString Project::getProjectTitle() { + if (!root.isNull()) { + return root.section('/', -1); + } else { + return QString(); + } +} + +Map* Project::loadMap(QString map_name) { + Map *map; + if (map_cache->contains(map_name)) { + map = map_cache->value(map_name); + // TODO: uncomment when undo/redo history is fully implemented for all actions. + if (true/*map->hasUnsavedChanges()*/) { + return map; + } + } else { + map = new Map; + map->setName(map_name); + } + + readMapHeader(map); + readMapLayout(map); + readMapEvents(map); + loadMapConnections(map); + map->commit(); + map->metatileHistory.save(); + + map_cache->insert(map_name, map); + return map; +} + +void Project::loadMapConnections(Map *map) { + if (!map->isPersistedToFile) { + return; + } + + map->connections.clear(); + if (!map->connections_label.isNull()) { + QString path = root + QString("/data/maps/%1/connections.inc").arg(map->name); + QString text = readTextFile(path); + if (!text.isNull()) { + QList<QStringList> *commands = parseAsm(text); + QStringList *list = getLabelValues(commands, map->connections_label); + + //// Avoid using this value. It ought to be generated instead. + //int num_connections = list->value(0).toInt(nullptr, 0); + + QString connections_list_label = list->value(1); + QList<QStringList> *connections = getLabelMacros(commands, connections_list_label); + for (QStringList command : *connections) { + QString macro = command.value(0); + if (macro == "connection") { + MapConnection *connection = new MapConnection; + connection->direction = command.value(1); + connection->offset = command.value(2); + QString mapConstant = command.value(3); + if (mapConstantsToMapNames->contains(mapConstant)) { + connection->map_name = mapConstantsToMapNames->value(mapConstant); + map->connections.append(connection); + } else { + qDebug() << QString("Failed to find connected map for map constant '%1'").arg(mapConstant); + } + } + } + } + } +} + +void Project::setNewMapConnections(Map *map) { + map->connections.clear(); +} + +QList<QStringList>* Project::getLabelMacros(QList<QStringList> *list, QString label) { + bool in_label = false; + QList<QStringList> *new_list = new QList<QStringList>; + for (int i = 0; i < list->length(); i++) { + QStringList params = list->value(i); + QString macro = params.value(0); + if (macro == ".label") { + if (params.value(1) == label) { + in_label = true; + } else if (in_label) { + // If nothing has been read yet, assume the label + // we're looking for is in a stack of labels. + if (new_list->length() > 0) { + break; + } + } + } else if (in_label) { + new_list->append(params); + } + } + return new_list; +} + +// For if you don't care about filtering by macro, +// and just want all values associated with some label. +QStringList* Project::getLabelValues(QList<QStringList> *list, QString label) { + list = getLabelMacros(list, label); + QStringList *values = new QStringList; + for (int i = 0; i < list->length(); i++) { + QStringList params = list->value(i); + QString macro = params.value(0); + // Ignore .align + if (macro == ".align") + continue; + if (macro == ".ifdef") + continue; + if (macro == ".ifndef") + continue; + for (int j = 1; j < params.length(); j++) { + values->append(params.value(j)); + } + } + return values; +} + +void Project::readMapHeader(Map* map) { + if (!map->isPersistedToFile) { + return; + } + + QString label = map->name; + ParseUtil *parser = new ParseUtil; + + QString header_text = readTextFile(root + "/data/maps/" + label + "/header.inc"); + if (header_text.isNull()) { + return; + } + QStringList *header = getLabelValues(parser->parseAsm(header_text), label); + map->layout_label = header->value(0); + map->events_label = header->value(1); + map->scripts_label = header->value(2); + map->connections_label = header->value(3); + map->song = header->value(4); + map->layout_id = header->value(5); + map->location = header->value(6); + map->requiresFlash = header->value(7); + map->weather = header->value(8); + map->type = header->value(9); + map->unknown = header->value(10); + map->show_location = header->value(11); + map->battle_scene = header->value(12); +} + +void Project::setNewMapHeader(Map* map, int mapIndex) { + map->layout_label = QString("%1_Layout").arg(map->name); + map->events_label = QString("%1_MapEvents").arg(map->name);; + map->scripts_label = QString("%1_MapScripts").arg(map->name);; + map->connections_label = "0x0"; + map->song = "MUS_DAN02"; + map->layout_id = QString("%1").arg(mapIndex); + map->location = "MAPSEC_LITTLEROOT_TOWN"; + map->requiresFlash = "FALSE"; + map->weather = "WEATHER_SUNNY"; + map->type = "MAP_TYPE_TOWN"; + map->unknown = "0"; + map->show_location = "TRUE"; + map->battle_scene = "MAP_BATTLE_SCENE_NORMAL"; +} + +void Project::saveMapHeader(Map *map) { + QString label = map->name; + QString header_path = root + "/data/maps/" + label + "/header.inc"; + QString text = ""; + text += QString("%1::\n").arg(label); + text += QString("\t.4byte %1\n").arg(map->layout_label); + text += QString("\t.4byte %1\n").arg(map->events_label); + text += QString("\t.4byte %1\n").arg(map->scripts_label); + + if (map->connections.length() == 0) { + map->connections_label = "0x0"; + } else { + map->connections_label = QString("%1_MapConnections").arg(map->name); + } + text += QString("\t.4byte %1\n").arg(map->connections_label); + + text += QString("\t.2byte %1\n").arg(map->song); + text += QString("\t.2byte %1\n").arg(map->layout_id); + text += QString("\t.byte %1\n").arg(map->location); + text += QString("\t.byte %1\n").arg(map->requiresFlash); + text += QString("\t.byte %1\n").arg(map->weather); + text += QString("\t.byte %1\n").arg(map->type); + text += QString("\t.2byte %1\n").arg(map->unknown); + text += QString("\t.byte %1\n").arg(map->show_location); + text += QString("\t.byte %1\n").arg(map->battle_scene); + saveTextFile(header_path, text); +} + +void Project::saveMapConnections(Map *map) { + QString path = root + "/data/maps/" + map->name + "/connections.inc"; + if (map->connections.length() > 0) { + QString text = ""; + QString connectionsListLabel = QString("%1_MapConnectionsList").arg(map->name); + int numValidConnections = 0; + text += QString("%1::\n").arg(connectionsListLabel); + for (MapConnection* connection : map->connections) { + if (mapNamesToMapConstants->contains(connection->map_name)) { + text += QString("\tconnection %1, %2, %3\n") + .arg(connection->direction) + .arg(connection->offset) + .arg(mapNamesToMapConstants->value(connection->map_name)); + numValidConnections++; + } else { + qDebug() << QString("Failed to write map connection. %1 not a valid map name").arg(connection->map_name); + } + } + text += QString("\n"); + text += QString("%1::\n").arg(map->connections_label); + text += QString("\t.4byte %1\n").arg(numValidConnections); + text += QString("\t.4byte %1\n").arg(connectionsListLabel); + saveTextFile(path, text); + } else { + deleteFile(path); + } + + updateMapsWithConnections(map); +} + +void Project::updateMapsWithConnections(Map *map) { + if (map->connections.length() > 0) { + if (!mapsWithConnections.contains(map->name)) { + mapsWithConnections.append(map->name); + } + } else { + if (mapsWithConnections.contains(map->name)) { + mapsWithConnections.removeOne(map->name); + } + } +} + +void Project::readMapLayoutsTable() { + QString layoutsText = readTextFile(getMapLayoutsTableFilepath()); + QList<QStringList>* values = parseAsm(layoutsText); + bool inLayoutPointers = false; + for (int i = 0; i < values->length(); i++) { + QStringList params = values->value(i); + QString macro = params.value(0); + if (macro == ".label") { + if (inLayoutPointers) { + break; + } + if (params.value(1) == "gMapLayouts") { + inLayoutPointers = true; + } + } else if (macro == ".4byte" && inLayoutPointers) { + QString layoutName = params.value(1); + mapLayoutsTable.append(layoutName); + } + } + + // Deep copy + mapLayoutsTableMaster = mapLayoutsTable; + mapLayoutsTableMaster.detach(); +} + +void Project::saveMapLayoutsTable() { + QString text = ""; + text += QString("\t.align 2\n"); + text += QString("gMapLayouts::\n"); + for (QString layoutName : mapLayoutsTableMaster) { + text += QString("\t.4byte %1\n").arg(layoutName); + } + saveTextFile(getMapLayoutsTableFilepath(), text); +} + +QString Project::getMapLayoutsTableFilepath() { + return QString("%1/data/layouts_table.inc").arg(root); +} + +QStringList* Project::readLayoutValues(QString layoutLabel) { + ParseUtil *parser = new ParseUtil; + + QString layoutText = readTextFile(getMapLayoutFilepath(layoutLabel)); + if (layoutText.isNull()) { + return nullptr; + } + + QStringList *layoutValues = getLabelValues(parser->parseAsm(layoutText), layoutLabel); + QString borderLabel = layoutValues->value(2); + QString blockdataLabel = layoutValues->value(3); + QStringList *borderValues = getLabelValues(parser->parseAsm(layoutText), borderLabel); + QString borderPath = borderValues->value(0).replace("\"", ""); + layoutValues->append(borderPath); + QStringList *blockdataValues = getLabelValues(parser->parseAsm(layoutText), blockdataLabel); + QString blockdataPath = blockdataValues->value(0).replace("\"", ""); + layoutValues->append(blockdataPath); + + if (layoutValues->size() != 8) { + qDebug() << "Error: Unexpected number of properties in layout '" << layoutLabel << "'"; + return nullptr; + } + + return layoutValues; +} + +void Project::readMapLayout(Map* map) { + if (!map->isPersistedToFile) { + return; + } + + MapLayout *layout; + if (!mapLayouts.contains(map->layout_label)) { + QStringList *layoutValues = readLayoutValues(map->layout->label); + if (!layoutValues) { + return; + } + + layout = new MapLayout(); + mapLayouts.insert(map->layout_label, layout); + layout->name = MapLayout::getNameFromLabel(map->layout_label); + layout->label = map->layout_label; + layout->width = layoutValues->value(0); + layout->height = layoutValues->value(1); + layout->border_label = layoutValues->value(2); + layout->blockdata_label = layoutValues->value(3); + layout->tileset_primary_label = layoutValues->value(4); + layout->tileset_secondary_label = layoutValues->value(5); + layout->border_path = layoutValues->value(6); + layout->blockdata_path = layoutValues->value(7); + map->layout = layout; + } else { + map->layout = mapLayouts[map->layout_label]; + } + + loadMapTilesets(map); + loadBlockdata(map); + loadMapBorder(map); +} + +void Project::readAllMapLayouts() { + mapLayouts.clear(); + + for (int i = 0; i < mapLayoutsTable.size(); i++) { + QString layoutLabel = mapLayoutsTable[i]; + QStringList *layoutValues = readLayoutValues(layoutLabel); + if (!layoutValues) { + return; + } + + MapLayout *layout = new MapLayout(); + layout->name = MapLayout::getNameFromLabel(layoutLabel); + layout->label = layoutLabel; + layout->index = i; + layout->width = layoutValues->value(0); + layout->height = layoutValues->value(1); + layout->border_label = layoutValues->value(2); + layout->blockdata_label = layoutValues->value(3); + layout->tileset_primary_label = layoutValues->value(4); + layout->tileset_secondary_label = layoutValues->value(5); + layout->border_path = layoutValues->value(6); + layout->blockdata_path = layoutValues->value(7); + mapLayouts.insert(layoutLabel, layout); + } + + // Deep copy + mapLayoutsMaster = mapLayouts; + mapLayoutsMaster.detach(); +} + +void Project::saveAllMapLayouts() { + for (QString layoutName : mapLayoutsTableMaster) { + MapLayout *layout = mapLayouts.value(layoutName); + QString text = QString("%1::\n").arg(layout->border_label); + text += QString("\t.incbin \"%1\"\n").arg(layout->border_path); + text += QString("\n"); + text += QString("%1::\n").arg(layout->blockdata_label); + text += QString("\t.incbin \"%1\"\n").arg(layout->blockdata_path); + text += QString("\n"); + text += QString("\t.align 2\n"); + text += QString("%1::\n").arg(layoutName); + text += QString("\t.4byte %1\n").arg(layout->width); + text += QString("\t.4byte %1\n").arg(layout->height); + text += QString("\t.4byte %1\n").arg(layout->border_label); + text += QString("\t.4byte %1\n").arg(layout->blockdata_label); + text += QString("\t.4byte %1\n").arg(layout->tileset_primary_label); + text += QString("\t.4byte %1\n").arg(layout->tileset_secondary_label); + text += QString("\n"); + saveTextFile(getMapLayoutFilepath(layout->label), text); + } +} + +QString Project::getMapLayoutFilepath(QString layoutLabel) { + return QString("%1/data/layouts/%2/layout.inc").arg(root).arg(MapLayout::getNameFromLabel(layoutLabel)); +} + +void Project::setNewMapLayout(Map* map) { + MapLayout *layout = new MapLayout(); + layout->label = QString("%1_Layout").arg(map->name); + layout->name = MapLayout::getNameFromLabel(layout->label); + layout->width = "20"; + layout->height = "20"; + layout->border_label = QString("%1_MapBorder").arg(map->name); + layout->border_path = QString("data/layouts/%1/border.bin").arg(map->name); + layout->blockdata_label = QString("%1_MapBlockdata").arg(map->name); + layout->blockdata_path = QString("data/layouts/%1/map.bin").arg(map->name); + layout->tileset_primary_label = "gTileset_General"; + layout->tileset_secondary_label = "gTileset_Petalburg"; + map->layout = layout; + map->layout_label = layout->label; + + // Insert new entry into the global map layouts. + mapLayouts.insert(layout->label, layout); + mapLayoutsTable.append(layout->label); +} + +void Project::saveMapGroupsTable() { + QString text = ""; + int groupNum = 0; + for (QStringList mapNames : groupedMapNames) { + text += QString("\t.align 2\n"); + text += QString("gMapGroup%1::\n").arg(groupNum); + for (QString mapName : mapNames) { + text += QString("\t.4byte %1\n").arg(mapName); + } + text += QString("\n"); + groupNum++; + } + + text += QString("\t.align 2\n"); + text += QString("gMapGroups::\n"); + for (int i = 0; i < groupNum; i++) { + text += QString("\t.4byte gMapGroup%1\n").arg(i); + } + + saveTextFile(root + "/data/maps/groups.inc", text); +} + +void Project::saveMapConstantsHeader() { + QString text = QString("#ifndef GUARD_CONSTANTS_MAPS_H\n"); + text += QString("#define GUARD_CONSTANTS_MAPS_H\n"); + text += QString("\n"); + + int groupNum = 0; + for (QStringList mapNames : groupedMapNames) { + text += QString("// Map Group %1\n").arg(groupNum); + int maxLength = 0; + for (QString mapName : mapNames) { + QString mapConstantName = mapNamesToMapConstants->value(mapName); + if (mapConstantName.length() > maxLength) + maxLength = mapConstantName.length(); + } + int groupIndex = 0; + for (QString mapName : mapNames) { + QString mapConstantName = mapNamesToMapConstants->value(mapName); + text += QString("#define %1%2(%3 | (%4 << 8))\n") + .arg(mapConstantName) + .arg(QString(" ").repeated(maxLength - mapConstantName.length() + 1)) + .arg(groupIndex) + .arg(groupNum); + groupIndex++; + } + text += QString("\n"); + groupNum++; + } + + text += QString("\n"); + text += QString("#define MAP_NONE (0x7F | (0x7F << 8))\n"); + text += QString("#define MAP_UNDEFINED (0xFF | (0xFF << 8))\n\n\n"); + text += QString("#define MAP_GROUP(map) (MAP_##map >> 8)\n"); + text += QString("#define MAP_NUM(map) (MAP_##map & 0xFF)\n\n"); + text += QString("#endif // GUARD_CONSTANTS_MAPS_H\n"); + saveTextFile(root + "/include/constants/maps.h", text); +} + +// saves heal location coords in root + /src/data/heal_locations.h +// and indexes as defines in root + /include/constants/heal_locations.h +void Project::saveHealLocationStruct(Map *map) { + QString tab = QString(" "); + + QString data_text = QString("static const struct HealLocation sHealLocations[] =\n{\n"); + + QString constants_text = QString("#ifndef GUARD_CONSTANTS_HEAL_LOCATIONS_H\n"); + constants_text += QString("#define GUARD_CONSTANTS_HEAL_LOCATIONS_H\n\n"); + + QMap<QString, int> flyableMapsDupes; + QSet<QString> flyableMapsUnique; + + // set flyableMapsDupes and flyableMapsUnique + for (auto it = flyableMaps.begin(); it != flyableMaps.end(); it++) { + HealLocation loc = *it; + QString xname = loc.name; + if (flyableMapsUnique.contains(xname)) { + flyableMapsDupes[xname] = 1; + } + flyableMapsUnique.insert(xname); + } + + // set new location in flyableMapsList + if (map->events["heal_event_group"].length() > 0) { + for (Event *healEvent : map->events["heal_event_group"]) { + HealLocation hl = HealLocation::fromEvent(healEvent); + flyableMaps[hl.index - 1] = hl; + } + } + + int i = 1; + + for (auto map_in : flyableMaps) { + data_text += QString(" {MAP_GROUP(%1), MAP_NUM(%1), %2, %3},\n") + .arg(map_in.name) + .arg(map_in.x) + .arg(map_in.y); + + QString ending = QString(""); + + // must add _1 / _2 for maps that have duplicates + if (flyableMapsDupes.keys().contains(map_in.name)) { + // map contains multiple heal locations + ending += QString("_%1").arg(flyableMapsDupes[map_in.name]); + flyableMapsDupes[map_in.name]++; + } + if (map_in.index != 0) { + constants_text += QString("#define HEAL_LOCATION_%1 %2\n") + .arg(map_in.name + ending) + .arg(map_in.index); + } + else { + constants_text += QString("#define HEAL_LOCATION_%1 %2\n") + .arg(map_in.name + ending) + .arg(i); + } + i++; + } + + data_text += QString("};\n"); + constants_text += QString("\n#endif // GUARD_CONSTANTS_HEAL_LOCATIONS_H\n"); + + saveTextFile(root + "/src/data/heal_locations.h", data_text); + saveTextFile(root + "/include/constants/heal_locations.h", constants_text); +} + +void Project::loadMapTilesets(Map* map) { + if (map->layout->has_unsaved_changes) { + return; + } + + map->layout->tileset_primary = getTileset(map->layout->tileset_primary_label); + map->layout->tileset_secondary = getTileset(map->layout->tileset_secondary_label); +} + +Tileset* Project::loadTileset(QString label) { + ParseUtil *parser = new ParseUtil; + + QString headers_text = readTextFile(root + "/data/tilesets/headers.inc"); + QStringList *values = getLabelValues(parser->parseAsm(headers_text), label); + Tileset *tileset = new Tileset; + tileset->name = label; + tileset->is_compressed = values->value(0); + tileset->is_secondary = values->value(1); + tileset->padding = values->value(2); + tileset->tiles_label = values->value(3); + tileset->palettes_label = values->value(4); + tileset->metatiles_label = values->value(5); + tileset->metatile_attrs_label = values->value(6); + tileset->callback_label = values->value(7); + + loadTilesetAssets(tileset); + + tileset_cache->insert(label, tileset); + return tileset; +} + +void Project::loadBlockdata(Map* map) { + if (!map->isPersistedToFile || map->layout->has_unsaved_changes) { + return; + } + + QString path = QString("%1/%2").arg(root).arg(map->layout->blockdata_path); + map->layout->blockdata = readBlockdata(path); +} + +void Project::setNewMapBlockdata(Map* map) { + Blockdata *blockdata = new Blockdata; + for (int i = 0; i < map->getWidth() * map->getHeight(); i++) { + blockdata->addBlock(qint16(0x3001)); + } + map->layout->blockdata = blockdata; +} + +void Project::loadMapBorder(Map *map) { + if (!map->isPersistedToFile || map->layout->has_unsaved_changes) { + return; + } + + QString path = QString("%1/%2").arg(root).arg(map->layout->border_path); + map->layout->border = readBlockdata(path); +} + +void Project::setNewMapBorder(Map *map) { + Blockdata *blockdata = new Blockdata; + blockdata->addBlock(qint16(0x01D4)); + blockdata->addBlock(qint16(0x01D5)); + blockdata->addBlock(qint16(0x01DC)); + blockdata->addBlock(qint16(0x01DD)); + map->layout->border = blockdata; +} + +void Project::saveMapBorder(Map *map) { + QString path = QString("%1/%2").arg(root).arg(map->layout->border_path); + writeBlockdata(path, map->layout->border); +} + +void Project::saveBlockdata(Map* map) { + QString path = QString("%1/%2").arg(root).arg(map->layout->blockdata_path); + writeBlockdata(path, map->layout->blockdata); + map->metatileHistory.save(); +} + +void Project::writeBlockdata(QString path, Blockdata *blockdata) { + QFile file(path); + if (file.open(QIODevice::WriteOnly)) { + QByteArray data = blockdata->serialize(); + file.write(data); + } else { + qDebug() << "Failed to open blockdata file for writing: '" << path << "'"; + } +} + +void Project::saveAllMaps() { + QList<QString> keys = map_cache->keys(); + for (int i = 0; i < keys.length(); i++) { + QString key = keys.value(i); + Map* map = map_cache->value(key); + saveMap(map); + } +} + +void Project::saveMap(Map *map) { + // Create/Modify a few collateral files for brand new maps. + if (!map->isPersistedToFile) { + QString newMapDataDir = QString(root + "/data/maps/%1").arg(map->name); + if (!QDir::root().mkdir(newMapDataDir)) { + qDebug() << "Error: failed to create directory for new map. " << newMapDataDir; + } + + QString newLayoutDir = QString(root + "/data/layouts/%1").arg(map->name); + if (!QDir::root().mkdir(newLayoutDir)) { + qDebug() << "Error: failed to create directory for new layout. " << newLayoutDir; + } + + // TODO: In the future, these files needs more structure to allow for proper parsing/saving. + // Create file data/maps/<map_name>/scripts.inc + QString text = QString("%1_MapScripts::\n\t.byte 0\n").arg(map->name); + saveTextFile(root + "/data/maps/" + map->name + "/scripts.inc", text); + + // Create file data/maps/<map_name>/text.inc + saveTextFile(root + "/data/maps/" + map->name + "/text.inc", "\n"); + + // Simply append to data/event_scripts.s. + text = QString("\n\t.include \"data/maps/%1/scripts.inc\"\n").arg(map->name); + text += QString("\t.include \"data/maps/%1/text.inc\"\n").arg(map->name); + appendTextFile(root + "/data/event_scripts.s", text); + + // Simply append to data/map_events.s. + text = QString("\n\t.include \"data/maps/%1/events.inc\"\n").arg(map->name); + appendTextFile(root + "/data/map_events.s", text); + + // Simply append to data/maps/headers.inc. + text = QString("\t.include \"data/maps/%1/header.inc\"\n").arg(map->name); + appendTextFile(root + "/data/maps/headers.inc", text); + + // Simply append to data/layouts.inc. + text = QString("\t.include \"data/layouts/%1/layout.inc\"\n").arg(map->layout->name); + appendTextFile(root + "/data/layouts.inc", text); + } + + saveMapBorder(map); + saveMapHeader(map); + saveMapConnections(map); + saveBlockdata(map); + saveMapEvents(map); + + // Update global data structures with current map data. + updateMapLayout(map); + + map->isPersistedToFile = true; + map->layout->has_unsaved_changes = false; +} + +void Project::updateMapLayout(Map* map) { + if (!mapLayoutsTableMaster.contains(map->layout_label)) { + mapLayoutsTableMaster.append(map->layout_label); + } + + // Deep copy + MapLayout *layout = mapLayouts.value(map->layout_label); + MapLayout *newLayout = new MapLayout(); + *newLayout = *layout; + mapLayoutsMaster.insert(map->layout_label, newLayout); +} + +void Project::saveAllDataStructures() { + saveMapLayoutsTable(); + saveAllMapLayouts(); + saveMapGroupsTable(); + saveMapConstantsHeader(); + saveMapsWithConnections(); +} + +void Project::loadTilesetAssets(Tileset* tileset) { + ParseUtil* parser = new ParseUtil; + QString category = (tileset->is_secondary == "TRUE") ? "secondary" : "primary"; + if (tileset->name.isNull()) { + return; + } + QString dir_path = root + "/data/tilesets/" + category + "/" + tileset->name.replace("gTileset_", "").toLower(); + + QString graphics_text = readTextFile(root + "/data/tilesets/graphics.inc"); + QList<QStringList> *graphics = parser->parseAsm(graphics_text); + QStringList *tiles_values = getLabelValues(graphics, tileset->tiles_label); + QStringList *palettes_values = getLabelValues(graphics, tileset->palettes_label); + + QString tiles_path; + if (!tiles_values->isEmpty()) { + tiles_path = root + "/" + tiles_values->value(0).section('"', 1, 1); + } else { + tiles_path = dir_path + "/tiles.4bpp"; + if (tileset->is_compressed == "TRUE") { + tiles_path += ".lz"; + } + } + + QStringList *palette_paths = new QStringList; + if (!palettes_values->isEmpty()) { + for (int i = 0; i < palettes_values->length(); i++) { + QString value = palettes_values->value(i); + palette_paths->append(root + "/" + value.section('"', 1, 1)); + } + } else { + QString palettes_dir_path = dir_path + "/palettes"; + for (int i = 0; i < 16; i++) { + palette_paths->append(palettes_dir_path + "/" + QString("%1").arg(i, 2, 10, QLatin1Char('0')) + ".gbapal"); + } + } + + QString metatiles_path; + QString metatile_attrs_path; + QString metatiles_text = readTextFile(root + "/data/tilesets/metatiles.inc"); + QList<QStringList> *metatiles_macros = parser->parseAsm(metatiles_text); + QStringList *metatiles_values = getLabelValues(metatiles_macros, tileset->metatiles_label); + if (!metatiles_values->isEmpty()) { + metatiles_path = root + "/" + metatiles_values->value(0).section('"', 1, 1); + } else { + metatiles_path = dir_path + "/metatiles.bin"; + } + QStringList *metatile_attrs_values = getLabelValues(metatiles_macros, tileset->metatile_attrs_label); + if (!metatile_attrs_values->isEmpty()) { + metatile_attrs_path = root + "/" + metatile_attrs_values->value(0).section('"', 1, 1); + } else { + metatile_attrs_path = dir_path + "/metatile_attributes.bin"; + } + + // tiles + tiles_path = fixGraphicPath(tiles_path); + QImage *image = new QImage(tiles_path); + //image->setColor(0, qRgb(0xff, 0, 0)); // debug + + QList<QImage> *tiles = new QList<QImage>; + int w = 8; + int h = 8; + for (int y = 0; y < image->height(); y += h) + for (int x = 0; x < image->width(); x += w) { + QImage tile = image->copy(x, y, w, h); + tiles->append(tile); + } + tileset->tiles = tiles; + + // metatiles + QFile metatiles_file(metatiles_path); + if (metatiles_file.open(QIODevice::ReadOnly)) { + QByteArray data = metatiles_file.readAll(); + int num_metatiles = data.length() / 16; + int num_layers = 2; + QList<Metatile*> *metatiles = new QList<Metatile*>; + for (int i = 0; i < num_metatiles; i++) { + Metatile *metatile = new Metatile; + int index = i * (2 * 4 * num_layers); + for (int j = 0; j < 4 * num_layers; j++) { + uint16_t word = data[index++] & 0xff; + word += (data[index++] & 0xff) << 8; + Tile tile; + tile.tile = word & 0x3ff; + tile.xflip = (word >> 10) & 1; + tile.yflip = (word >> 11) & 1; + tile.palette = (word >> 12) & 0xf; + metatile->tiles->append(tile); + } + metatiles->append(metatile); + } + tileset->metatiles = metatiles; + } else { + tileset->metatiles = new QList<Metatile*>; + qDebug() << QString("Could not open '%1'").arg(metatiles_path); + } + + QFile attrs_file(metatile_attrs_path); + //qDebug() << metatile_attrs_path; + if (attrs_file.open(QIODevice::ReadOnly)) { + QByteArray data = attrs_file.readAll(); + int num_metatiles = tileset->metatiles->count(); + int num_metatileAttrs = data.length() / 2; + if (num_metatiles != num_metatileAttrs) { + qDebug() << QString("Metatile count %1 does not match metatile attribute count %2").arg(num_metatiles).arg(num_metatileAttrs); + if (num_metatiles > num_metatileAttrs) + num_metatiles = num_metatileAttrs; + } + } else { + qDebug() << QString("Could not open '%1'").arg(metatile_attrs_path); + } + + // palettes + QList<QList<QRgb>> *palettes = new QList<QList<QRgb>>; + for (int i = 0; i < palette_paths->length(); i++) { + QString path = palette_paths->value(i); + // the palettes are not compressed. this should never happen. it's only a precaution. + path = path.replace(QRegExp("\\.lz$"), ""); + // TODO default to .pal (JASC-PAL) + // just use .gbapal for now + QFile file(path); + QList<QRgb> palette; + if (file.open(QIODevice::ReadOnly)) { + QByteArray data = file.readAll(); + for (int j = 0; j < 16; j++) { + uint16_t word = data[j*2] & 0xff; + word += (data[j*2 + 1] & 0xff) << 8; + int red = word & 0x1f; + int green = (word >> 5) & 0x1f; + int blue = (word >> 10) & 0x1f; + QRgb color = qRgb(red * 8, green * 8, blue * 8); + palette.append(color); + } + } else { + for (int j = 0; j < 16; j++) { + palette.append(qRgb(j * 16, j * 16, j * 16)); + } + qDebug() << QString("Could not open palette path '%1'").arg(path); + } + + palettes->append(palette); + } + tileset->palettes = palettes; +} + +Blockdata* Project::readBlockdata(QString path) { + Blockdata *blockdata = new Blockdata; + QFile file(path); + if (file.open(QIODevice::ReadOnly)) { + QByteArray data = file.readAll(); + for (int i = 0; (i + 1) < data.length(); i += 2) { + uint16_t word = static_cast<uint16_t>((data[i] & 0xff) + ((data[i + 1] & 0xff) << 8)); + blockdata->addBlock(word); + } + } else { + qDebug() << "Failed to open blockdata path '" << path << "'"; + } + + return blockdata; +} + +Map* Project::getMap(QString map_name) { + if (map_cache->contains(map_name)) { + return map_cache->value(map_name); + } else { + Map *map = loadMap(map_name); + return map; + } +} + +Tileset* Project::getTileset(QString label) { + if (tileset_cache->contains(label)) { + return tileset_cache->value(label); + } else { + Tileset *tileset = loadTileset(label); + return tileset; + } +} + +QString Project::readTextFile(QString path) { + QFile file(path); + if (!file.open(QIODevice::ReadOnly)) { + //QMessageBox::information(0, "Error", QString("Could not open '%1': ").arg(path) + file.errorString()); + qDebug() << QString("Could not open '%1': ").arg(path) + file.errorString(); + return QString(); + } + QTextStream in(&file); + QString text = ""; + while (!in.atEnd()) { + text += in.readLine() + "\n"; + } + return text; +} + +void Project::saveTextFile(QString path, QString text) { + QFile file(path); + if (file.open(QIODevice::WriteOnly)) { + file.write(text.toUtf8()); + } else { + qDebug() << QString("Could not open '%1' for writing: ").arg(path) + file.errorString(); + } +} + +void Project::appendTextFile(QString path, QString text) { + QFile file(path); + if (file.open(QIODevice::Append)) { + file.write(text.toUtf8()); + } else { + qDebug() << QString("Could not open '%1' for appending: ").arg(path) + file.errorString(); + } +} + +void Project::deleteFile(QString path) { + QFile file(path); + if (file.exists() && !file.remove()) { + qDebug() << QString("Could not delete file '%1': ").arg(path) + file.errorString(); + } +} + +void Project::readMapGroups() { + QString text = readTextFile(root + "/data/maps/groups.inc"); + if (text.isNull()) { + return; + } + ParseUtil *parser = new ParseUtil; + QList<QStringList> *commands = parser->parseAsm(text); + + bool in_group_pointers = false; + QStringList *groups = new QStringList; + for (int i = 0; i < commands->length(); i++) { + QStringList params = commands->value(i); + QString macro = params.value(0); + if (macro == ".label") { + if (in_group_pointers) { + break; + } + if (params.value(1) == "gMapGroups") { + in_group_pointers = true; + } + } else if (macro == ".4byte") { + if (in_group_pointers) { + for (int j = 1; j < params.length(); j++) { + groups->append(params.value(j)); + } + } + } + } + + QList<QStringList> groupedMaps; + for (int i = 0; i < groups->length(); i++) { + groupedMaps.append(QStringList()); + } + + QStringList *maps = new QStringList; + int group = -1; + for (int i = 0; i < commands->length(); i++) { + QStringList params = commands->value(i); + QString macro = params.value(0); + if (macro == ".label") { + group = groups->indexOf(params.value(1)); + } else if (macro == ".4byte") { + if (group != -1) { + for (int j = 1; j < params.length(); j++) { + QString mapName = params.value(j); + groupedMaps[group].append(mapName); + maps->append(mapName); + map_groups->insert(mapName, group); + + // Build the mapping and reverse mapping between map constants and map names. + QString mapConstant = Map::mapConstantFromName(mapName); + mapConstantsToMapNames->insert(mapConstant, mapName); + mapNamesToMapConstants->insert(mapName, mapConstant); + } + } + } + } + + mapConstantsToMapNames->insert(NONE_MAP_CONSTANT, NONE_MAP_NAME); + mapNamesToMapConstants->insert(NONE_MAP_NAME, NONE_MAP_CONSTANT); + maps->append(NONE_MAP_NAME); + + groupNames = groups; + groupedMapNames = groupedMaps; + mapNames = maps; + + QString hltext = readTextFile(root + QString("/src/data/heal_locations.h")); + QList<HealLocation>* hl = parser->parseHealLocs(hltext); + flyableMaps = *hl; + delete hl; +} + +Map* Project::addNewMapToGroup(QString mapName, int groupNum) { + // Setup new map in memory, but don't write to file until map is actually saved later. + mapNames->append(mapName); + map_groups->insert(mapName, groupNum); + groupedMapNames[groupNum].append(mapName); + + Map *map = new Map; + map->isPersistedToFile = false; + map->setName(mapName); + mapConstantsToMapNames->insert(map->constantName, map->name); + mapNamesToMapConstants->insert(map->name, map->constantName); + setNewMapHeader(map, mapLayoutsTable.size() + 1); + setNewMapLayout(map); + loadMapTilesets(map); + setNewMapBlockdata(map); + setNewMapBorder(map); + setNewMapEvents(map); + setNewMapConnections(map); + map->commit(); + map->metatileHistory.save(); + map_cache->insert(mapName, map); + + return map; +} + +QString Project::getNewMapName() { + // Ensure default name doesn't already exist. + int i = 0; + QString newMapName; + do { + newMapName = QString("NewMap%1").arg(++i); + } while (mapNames->contains(newMapName)); + + return newMapName; +} + +QList<QStringList>* Project::parseAsm(QString text) { + ParseUtil *parser = new ParseUtil; + return parser->parseAsm(text); +} + +QStringList Project::getVisibilities() { + // TODO + QStringList names; + for (int i = 0; i < 16; i++) { + names.append(QString("%1").arg(i)); + } + return names; +} + +QMap<QString, QStringList> Project::getTilesets() { + QMap<QString, QStringList> allTilesets; + QStringList primaryTilesets; + QStringList secondaryTilesets; + allTilesets.insert("primary", primaryTilesets); + allTilesets.insert("secondary", secondaryTilesets); + QString headers_text = readTextFile(root + "/data/tilesets/headers.inc"); + QList<QStringList>* commands = parseAsm(headers_text); + int i = 0; + while (i < commands->length()) { + if (commands->at(i).length() != 2) + continue; + + if (commands->at(i).at(0) == ".label") { + QString tilesetLabel = commands->at(i).at(1); + // Advance to command specifying whether or not it is a secondary tileset + i += 2; + if (commands->at(i).at(0) != ".byte") { + qDebug() << "Unexpected command found for secondary tileset flag in tileset" << tilesetLabel << ". Expected '.byte', but found: " << commands->at(i).at(0); + continue; + } + + QString secondaryTilesetValue = commands->at(i).at(1); + if (secondaryTilesetValue != "TRUE" && secondaryTilesetValue != "FALSE" && secondaryTilesetValue != "0" && secondaryTilesetValue != "1") { + qDebug() << "Unexpected secondary tileset flag found. Expected \"TRUE\", \"FALSE\", \"0\", or \"1\", but found: " << secondaryTilesetValue; + continue; + } + + bool isSecondaryTileset = (secondaryTilesetValue == "TRUE" || secondaryTilesetValue == "1"); + if (isSecondaryTileset) + allTilesets["secondary"].append(tilesetLabel); + else + allTilesets["primary"].append(tilesetLabel); + } + + i++; + } + + return allTilesets; +} + +void Project::readTilesetProperties() { + QStringList defines; + QString text = readTextFile(root + "/include/fieldmap.h"); + if (!text.isNull()) { + bool error = false; + QStringList definePrefixes; + definePrefixes << "NUM_"; + QMap<QString, int> defines = readCDefines(text, definePrefixes); + auto it = defines.find("NUM_TILES_IN_PRIMARY"); + if (it != defines.end()) { + Project::num_tiles_primary = it.value(); + } + else { + error = true; + } + it = defines.find("NUM_TILES_TOTAL"); + if (it != defines.end()) { + Project::num_tiles_total = it.value(); + } + else { + error = true; + } + it = defines.find("NUM_METATILES_IN_PRIMARY"); + if (it != defines.end()) { + Project::num_metatiles_primary = it.value(); + } + else { + error = true; + } + it = defines.find("NUM_METATILES_TOTAL"); + if (it != defines.end()) { + Project::num_metatiles_total = it.value(); + } + else { + error = true; + } + it = defines.find("NUM_PALS_IN_PRIMARY"); + if (it != defines.end()) { + Project::num_pals_primary = it.value(); + } + else { + error = true; + } + it = defines.find("NUM_PALS_TOTAL"); + if (it != defines.end()) { + Project::num_pals_total = it.value(); + } + else { + error = true; + } + + if (error) + { + qDebug() << "Some global tileset values could not be loaded. Using default values"; + } + } +} + +void Project::readRegionMapSections() { + QString filepath = root + "/include/constants/region_map_sections.h"; + QStringList prefixes = (QStringList() << "MAPSEC_"); + readCDefinesSorted(filepath, prefixes, regionMapSections); +} + +void Project::readItemNames() { + QString filepath = root + "/include/constants/items.h"; + QStringList prefixes = (QStringList() << "ITEM_"); + readCDefinesSorted(filepath, prefixes, itemNames); +} + +void Project::readFlagNames() { + QString filepath = root + "/include/constants/flags.h"; + QStringList prefixes = (QStringList() << "FLAG_"); + readCDefinesSorted(filepath, prefixes, flagNames); +} + +void Project::readVarNames() { + QString filepath = root + "/include/constants/vars.h"; + QStringList prefixes = (QStringList() << "VAR_"); + readCDefinesSorted(filepath, prefixes, varNames); +} + +void Project::readMovementTypes() { + QString filepath = root + "/include/constants/event_object_movement_constants.h"; + QStringList prefixes = (QStringList() << "MOVEMENT_TYPE_"); + readCDefinesSorted(filepath, prefixes, movementTypes); +} + +void Project::readMapTypes() { + QString filepath = root + "/include/constants/map_types.h"; + QStringList prefixes = (QStringList() << "MAP_TYPE_"); + readCDefinesSorted(filepath, prefixes, mapTypes); +} + +void Project::readMapBattleScenes() { + QString filepath = root + "/include/constants/map_types.h"; + QStringList prefixes = (QStringList() << "MAP_BATTLE_SCENE_"); + readCDefinesSorted(filepath, prefixes, mapBattleScenes); +} + +void Project::readWeatherNames() { + QString filepath = root + "/include/constants/weather.h"; + QStringList prefixes = (QStringList() << "WEATHER_"); + readCDefinesSorted(filepath, prefixes, weatherNames); +} + +void Project::readCoordEventWeatherNames() { + QString filepath = root + "/include/constants/weather.h"; + QStringList prefixes = (QStringList() << "COORD_EVENT_WEATHER_"); + readCDefinesSorted(filepath, prefixes, coordEventWeatherNames); +} + +void Project::readSecretBaseIds() { + QString filepath = root + "/include/constants/secret_bases.h"; + QStringList prefixes = (QStringList() << "SECRET_BASE_"); + readCDefinesSorted(filepath, prefixes, secretBaseIds); +} + +void Project::readBgEventFacingDirections() { + QString filepath = root + "/include/constants/bg_event_constants.h"; + QStringList prefixes = (QStringList() << "BG_EVENT_PLAYER_FACING_"); + readCDefinesSorted(filepath, prefixes, bgEventFacingDirections); +} + +void Project::readCDefinesSorted(QString filepath, QStringList prefixes, QStringList* definesToSet) { + QString text = readTextFile(filepath); + if (!text.isNull()) { + QMap<QString, int> defines = readCDefines(text, prefixes); + + // The defines should to be sorted by their underlying value, not alphabetically. + // Reverse the map and read out the resulting keys in order. + QMultiMap<int, QString> definesInverse; + for (QString defineName : defines.keys()) { + definesInverse.insert(defines[defineName], defineName); + } + *definesToSet = definesInverse.values(); + } else { + qDebug() << "Failed to read C defines file: " << filepath; + } +} + +void Project::readMapsWithConnections() { + QString path = root + "/data/maps/connections.inc"; + QString text = readTextFile(path); + if (text.isNull()) { + return; + } + + mapsWithConnections.clear(); + QRegularExpression re("data\\/maps\\/(?<mapName>\\w+)\\/connections.inc"); + QList<QStringList>* includes = parseAsm(text); + for (QStringList values : *includes) { + if (values.length() != 2) + continue; + + QRegularExpressionMatch match = re.match(values.value(1)); + if (match.hasMatch()) { + QString mapName = match.captured("mapName"); + mapsWithConnections.append(mapName); + } + } +} + +void Project::saveMapsWithConnections() { + QString path = root + "/data/maps/connections.inc"; + QString text = ""; + for (QString mapName : mapsWithConnections) { + if (mapNamesToMapConstants->contains(mapName)) { + text += QString("\t.include \"data/maps/%1/connections.inc\"\n").arg(mapName); + } else { + qDebug() << QString("Failed to write connection include. %1 not a valid map name").arg(mapName); + } + } + saveTextFile(path, text); +} + +QStringList Project::getSongNames() { + QStringList names; + QString text = readTextFile(root + "/include/constants/songs.h"); + if (!text.isNull()) { + QStringList songDefinePrefixes; + songDefinePrefixes << "SE_" << "MUS_"; + QMap<QString, int> songDefines = readCDefines(text, songDefinePrefixes); + names = songDefines.keys(); + } + return names; +} + +QMap<QString, int> Project::getEventObjGfxConstants() { + QMap<QString, int> constants; + QString text = readTextFile(root + "/include/constants/event_objects.h"); + if (!text.isNull()) { + QStringList eventObjGfxPrefixes; + eventObjGfxPrefixes << "EVENT_OBJ_GFX_"; + constants = readCDefines(text, eventObjGfxPrefixes); + } + return constants; +} + +QString Project::fixGraphicPath(QString path) { + path = path.replace(QRegExp("\\.lz$"), ""); + path = path.replace(QRegExp("\\.[1248]bpp$"), ".png"); + return path; +} + +void Project::loadEventPixmaps(QList<Event*> objects) { + bool needs_update = false; + for (Event *object : objects) { + if (object->pixmap.isNull()) { + needs_update = true; + break; + } + } + if (!needs_update) { + return; + } + + QMap<QString, int> constants = getEventObjGfxConstants(); + + QString pointers_text = readTextFile(root + "/src/data/field_event_obj/event_object_graphics_info_pointers.h"); + QString info_text = readTextFile(root + "/src/data/field_event_obj/event_object_graphics_info.h"); + QString pic_text = readTextFile(root + "/src/data/field_event_obj/event_object_pic_tables.h"); + QString assets_text = readTextFile(root + "/src/data/field_event_obj/event_object_graphics.h"); + + QStringList pointers = readCArray(pointers_text, "gEventObjectGraphicsInfoPointers"); + + for (Event *object : objects) { + if (!object->pixmap.isNull()) { + continue; + } + + object->spriteWidth = 16; + object->spriteHeight = 16; + QString event_type = object->get("event_type"); + if (event_type == EventType::Object) { + object->pixmap = QPixmap(":/images/Entities_16x16.png").copy(0, 0, 16, 16); + } else if (event_type == EventType::Warp) { + object->pixmap = QPixmap(":/images/Entities_16x16.png").copy(16, 0, 16, 16); + } else if (event_type == EventType::CoordScript || event_type == EventType::CoordWeather) { + object->pixmap = QPixmap(":/images/Entities_16x16.png").copy(32, 0, 16, 16); + } else if (event_type == EventType::Sign || event_type == EventType::HiddenItem || event_type == EventType::SecretBase) { + object->pixmap = QPixmap(":/images/Entities_16x16.png").copy(48, 0, 16, 16); + } else if (event_type == EventType::HealLocation) { + object->pixmap = QPixmap(":/images/Entities_16x16.png").copy(64, 0, 16, 16); + } + + if (event_type == EventType::Object) { + int sprite_id = constants.value(object->get("sprite")); + + QString info_label = pointers.value(sprite_id).replace("&", ""); + QStringList gfx_info = readCArray(info_text, info_label); + QString pic_label = gfx_info.value(14); + QString dimensions_label = gfx_info.value(11); + QString subsprites_label = gfx_info.value(12); + QString gfx_label = readCArray(pic_text, pic_label).value(0); + gfx_label = gfx_label.section(QRegExp("[\\(\\)]"), 1, 1); + QString path = readCIncbin(assets_text, gfx_label); + + if (!path.isNull()) { + path = fixGraphicPath(path); + QImage spritesheet(root + "/" + path); + if (!spritesheet.isNull()) { + // Infer the sprite dimensions from the OAM labels. + int spriteWidth = spritesheet.width(); + int spriteHeight = spritesheet.height(); + QRegularExpression re("\\S+_(\\d+)x(\\d+)"); + QRegularExpressionMatch dimensionMatch = re.match(dimensions_label); + if (dimensionMatch.hasMatch()) { + QRegularExpressionMatch oamTablesMatch = re.match(subsprites_label); + if (oamTablesMatch.hasMatch()) { + spriteWidth = dimensionMatch.captured(1).toInt(); + spriteHeight = dimensionMatch.captured(2).toInt(); + } + } + object->setPixmapFromSpritesheet(spritesheet, spriteWidth, spriteHeight); + } + } + } + } +} + +void Project::saveMapEvents(Map *map) { + QString path = root + QString("/data/maps/%1/events.inc").arg(map->name); + QString text = ""; + QString objectEventsLabel = "0x0"; + QString warpEventsLabel = "0x0"; + QString coordEventsLabel = "0x0"; + QString bgEventsLabel = "0x0"; + + if (map->events["object_event_group"].length() > 0) { + objectEventsLabel = Map::objectEventsLabelFromName(map->name); + text += QString("%1::\n").arg(objectEventsLabel); + for (int i = 0; i < map->events["object_event_group"].length(); i++) { + Event *object_event = map->events["object_event_group"].value(i); + text += object_event->buildObjectEventMacro(i); + } + text += "\n"; + } + + if (map->events["warp_event_group"].length() > 0) { + warpEventsLabel = Map::warpEventsLabelFromName(map->name); + text += QString("%1::\n").arg(warpEventsLabel); + for (Event *warp : map->events["warp_event_group"]) { + text += warp->buildWarpEventMacro(mapNamesToMapConstants); + } + text += "\n"; + } + + if (map->events["coord_event_group"].length() > 0) { + coordEventsLabel = Map::coordEventsLabelFromName(map->name); + text += QString("%1::\n").arg(coordEventsLabel); + for (Event *event : map->events["coord_event_group"]) { + QString event_type = event->get("event_type"); + if (event_type == EventType::CoordScript) { + text += event->buildCoordScriptEventMacro(); + } else if (event_type == EventType::CoordWeather) { + text += event->buildCoordWeatherEventMacro(); + } + } + text += "\n"; + } + + if (map->events["bg_event_group"].length() > 0) + { + bgEventsLabel = Map::bgEventsLabelFromName(map->name); + text += QString("%1::\n").arg(bgEventsLabel); + for (Event *event : map->events["bg_event_group"]) { + QString event_type = event->get("event_type"); + if (event_type == EventType::Sign) { + text += event->buildSignEventMacro(); + } else if (event_type == EventType::HiddenItem) { + text += event->buildHiddenItemEventMacro(); + } else if (event_type == EventType::SecretBase) { + text += event->buildSecretBaseEventMacro(); + } + } + text += "\n"; + } + + text += QString("%1::\n").arg(map->events_label); + text += QString("\tmap_events %1, %2, %3, %4\n") + .arg(objectEventsLabel) + .arg(warpEventsLabel) + .arg(coordEventsLabel) + .arg(bgEventsLabel); + + saveTextFile(path, text); + + // save heal event changes + if (map->events["heal_event_group"].length() > 0) { + for (Event *healEvent : map->events["heal_event_group"]) { + HealLocation hl = HealLocation::fromEvent(healEvent); + flyableMaps[hl.index - 1] = hl; + } + } + saveHealLocationStruct(map); +} + +void Project::readMapEvents(Map *map) { + if (!map->isPersistedToFile) { + return; + } + + // lazy + QString path = root + QString("/data/maps/%1/events.inc").arg(map->name); + QString text = readTextFile(path); + if (text.isNull()) { + return; + } + + QStringList *labels = getLabelValues(parseAsm(text), map->events_label); + QString objectEventsLabel = labels->value(0); + QString warpEventsLabel = labels->value(1); + QString coordEventsLabel = labels->value(2); + QString bgEventsLabel = labels->value(3); + + QList<QStringList> *object_events = getLabelMacros(parseAsm(text), objectEventsLabel); + map->events["object_event_group"].clear(); + for (QStringList command : *object_events) { + if (command.value(0) == "object_event") { + Event *object = new Event; + object->put("map_name", map->name); + int i = 2; + object->put("sprite", command.value(i++)); + object->put("replacement", command.value(i++)); + object->put("x", command.value(i++).toInt(nullptr, 0)); + object->put("y", command.value(i++).toInt(nullptr, 0)); + object->put("elevation", command.value(i++)); + object->put("movement_type", command.value(i++)); + object->put("radius_x", command.value(i++).toInt(nullptr, 0)); + object->put("radius_y", command.value(i++).toInt(nullptr, 0)); + object->put("is_trainer", command.value(i++)); + object->put("sight_radius_tree_id", command.value(i++)); + object->put("script_label", command.value(i++)); + object->put("event_flag", command.value(i++)); + object->put("event_group_type", "object_event_group"); + object->put("event_type", EventType::Object); + map->events["object_event_group"].append(object); + } + } + + QList<QStringList> *warps = getLabelMacros(parseAsm(text), warpEventsLabel); + map->events["warp_event_group"].clear(); + for (QStringList command : *warps) { + if (command.value(0) == "warp_def") { + Event *warp = new Event; + warp->put("map_name", map->name); + int i = 1; + warp->put("x", command.value(i++)); + warp->put("y", command.value(i++)); + warp->put("elevation", command.value(i++)); + warp->put("destination_warp", command.value(i++)); + + // Ensure the warp destination map constant is valid before adding it to the warps. + QString mapConstant = command.value(i++); + if (mapConstantsToMapNames->contains(mapConstant)) { + warp->put("destination_map_name", mapConstantsToMapNames->value(mapConstant)); + warp->put("event_group_type", "warp_event_group"); + warp->put("event_type", EventType::Warp); + map->events["warp_event_group"].append(warp); + } else if (mapConstant == NONE_MAP_CONSTANT) { + warp->put("destination_map_name", NONE_MAP_NAME); + warp->put("event_group_type", "warp_event_group"); + warp->put("event_type", EventType::Warp); + map->events["warp_event_group"].append(warp); + } else { + qDebug() << QString("Destination map constant '%1' is invalid for warp").arg(mapConstant); + } + } + } + + map->events["heal_event_group"].clear(); + + for (auto it = flyableMaps.begin(); it != flyableMaps.end(); it++) { + + HealLocation loc = *it; + + //if TRUE map is flyable / has healing location + if (loc.name == QString(mapNamesToMapConstants->value(map->name)).remove(0,4)) { + Event *heal = new Event; + heal->put("map_name", map->name); + heal->put("x", loc.x); + heal->put("y", loc.y); + heal->put("loc_name", loc.name); + heal->put("index", loc.index); + heal->put("elevation", 3); // TODO: change this? + heal->put("destination_map_name", mapConstantsToMapNames->value(map->name)); + heal->put("event_group_type", "heal_event_group"); + heal->put("event_type", EventType::HealLocation); + map->events["heal_event_group"].append(heal); + } + + } + + QList<QStringList> *coords = getLabelMacros(parseAsm(text), coordEventsLabel); + map->events["coord_event_group"].clear(); + for (QStringList command : *coords) { + if (command.value(0) == "coord_event") { + Event *coord = new Event; + coord->put("map_name", map->name); + int i = 1; + coord->put("x", command.value(i++)); + coord->put("y", command.value(i++)); + coord->put("elevation", command.value(i++)); + coord->put("script_var", command.value(i++)); + coord->put("script_var_value", command.value(i++)); + coord->put("script_label", command.value(i++)); + coord->put("event_group_type", "coord_event_group"); + coord->put("event_type", EventType::CoordScript); + map->events["coord_event_group"].append(coord); + } else if (command.value(0) == "coord_weather_event") { + Event *coord = new Event; + coord->put("map_name", map->name); + int i = 1; + coord->put("x", command.value(i++)); + coord->put("y", command.value(i++)); + coord->put("elevation", command.value(i++)); + coord->put("weather", command.value(i++)); + coord->put("event_group_type", "coord_event_group"); + coord->put("event_type", EventType::CoordWeather); + map->events["coord_event_group"].append(coord); + } + } + + QList<QStringList> *bgs = getLabelMacros(parseAsm(text), bgEventsLabel); + map->events["bg_event_group"].clear(); + for (QStringList command : *bgs) { + if (command.value(0) == "bg_event") { + Event *bg = new Event; + bg->put("map_name", map->name); + int i = 1; + bg->put("x", command.value(i++)); + bg->put("y", command.value(i++)); + bg->put("elevation", command.value(i++)); + bg->put("player_facing_direction", command.value(i++)); + bg->put("script_label", command.value(i++)); + //sign_unknown7 + bg->put("event_group_type", "bg_event_group"); + bg->put("event_type", EventType::Sign); + map->events["bg_event_group"].append(bg); + } else if (command.value(0) == "bg_hidden_item_event") { + Event *bg = new Event; + bg->put("map_name", map->name); + int i = 1; + bg->put("x", command.value(i++)); + bg->put("y", command.value(i++)); + bg->put("elevation", command.value(i++)); + bg->put("item", command.value(i++)); + bg->put("flag", command.value(i++)); + bg->put("event_group_type", "bg_event_group"); + bg->put("event_type", EventType::HiddenItem); + map->events["bg_event_group"].append(bg); + } else if (command.value(0) == "bg_secret_base_event") { + Event *bg = new Event; + bg->put("map_name", map->name); + int i = 1; + bg->put("x", command.value(i++)); + bg->put("y", command.value(i++)); + bg->put("elevation", command.value(i++)); + bg->put("secret_base_id", command.value(i++)); + bg->put("event_group_type", "bg_event_group"); + bg->put("event_type", EventType::SecretBase); + map->events["bg_event_group"].append(bg); + } + } +} + +void Project::setNewMapEvents(Map *map) { + map->events["object_event_group"].clear(); + map->events["warp_event_group"].clear(); + map->events["heal_event_group"].clear(); + map->events["coord_event_group"].clear(); + map->events["bg_event_group"].clear(); +} + +QStringList Project::readCArray(QString text, QString label) { + QStringList list; + + if (label.isNull()) { + return list; + } + + QRegExp *re = new QRegExp(QString("\\b%1\\b\\s*\\[?\\s*\\]?\\s*=\\s*\\{([^\\}]*)\\}").arg(label)); + int pos = re->indexIn(text); + if (pos != -1) { + QString body = re->cap(1); + body = body.replace(QRegExp("\\s*"), ""); + list = body.split(','); + /* + QRegExp *inner = new QRegExp("&?\\b([A-Za-z0-9_\\(\\)]*)\\b,"); + int pos = 0; + while ((pos = inner->indexIn(body, pos)) != -1) { + list << inner->cap(1); + pos += inner->matchedLength(); + } + */ + } + + return list; +} + +QString Project::readCIncbin(QString text, QString label) { + QString path; + + if (label.isNull()) { + return path; + } + + QRegExp *re = new QRegExp(QString( + "\\b%1\\b" + "\\s*\\[?\\s*\\]?\\s*=\\s*" + "INCBIN_[US][0-9][0-9]?" + "\\(\"([^\"]*)\"\\)").arg(label)); + + int pos = re->indexIn(text); + if (pos != -1) { + path = re->cap(1); + } + + return path; +} + +QMap<QString, int> Project::readCDefines(QString text, QStringList prefixes) { + ParseUtil parser; + QMap<QString, int> allDefines; + QMap<QString, int> filteredDefines; + QRegularExpression re("#define\\s+(?<defineName>\\w+)[^\\S\\n]+(?<defineValue>.+)"); + QRegularExpressionMatchIterator iter = re.globalMatch(text); + while (iter.hasNext()) { + QRegularExpressionMatch match = iter.next(); + QString name = match.captured("defineName"); + QString expression = match.captured("defineValue"); + expression.replace(QRegularExpression("//.*"), ""); + int value = parser.evaluateDefine(expression, &allDefines); + allDefines.insert(name, value); + for (QString prefix : prefixes) { + if (name.startsWith(prefix)) { + filteredDefines.insert(name, value); + } + } + } + return filteredDefines; +} + +int Project::getNumTilesPrimary() +{ + return Project::num_tiles_primary; +} + +int Project::getNumTilesTotal() +{ + return Project::num_tiles_total; +} + +int Project::getNumMetatilesPrimary() +{ + return Project::num_metatiles_primary; +} + +int Project::getNumMetatilesTotal() +{ + return Project::num_metatiles_total; +} + +int Project::getNumPalettesPrimary() +{ + return Project::num_pals_primary; +} + +int Project::getNumPalettesTotal() +{ + return Project::num_pals_total; +} diff --git a/project.h b/src/project.h old mode 100755 new mode 100644 similarity index 96% rename from project.h rename to src/project.h index cb1a10ee..4efe58a6 --- a/project.h +++ b/src/project.h @@ -1,152 +1,152 @@ -#ifndef PROJECT_H -#define PROJECT_H - -#include "map.h" -#include "blockdata.h" -#include "heallocation.h" - -#include <QStringList> -#include <QList> -#include <QStandardItem> - -static QString NONE_MAP_CONSTANT = "MAP_NONE"; -static QString NONE_MAP_NAME = "None"; - -class Project -{ -public: - Project(); - QString root; - QStringList *groupNames = nullptr; - QMap<QString, int> *map_groups; - QList<QStringList> groupedMapNames; - QStringList *mapNames = nullptr; - QList<HealLocation> flyableMaps; - QMap<QString, QString>* mapConstantsToMapNames; - QMap<QString, QString>* mapNamesToMapConstants; - QList<QString> mapLayoutsTable; - QList<QString> mapLayoutsTableMaster; - QMap<QString, MapLayout*> mapLayouts; - QMap<QString, MapLayout*> mapLayoutsMaster; - QStringList *regionMapSections = nullptr; - QStringList *itemNames = nullptr; - QStringList *flagNames = nullptr; - QStringList *varNames = nullptr; - QStringList *movementTypes = nullptr; - QStringList *mapTypes = nullptr; - QStringList *mapBattleScenes = nullptr; - QStringList *weatherNames = nullptr; - QStringList *coordEventWeatherNames = nullptr; - QStringList *secretBaseIds = nullptr; - QStringList *bgEventFacingDirections = nullptr; - QStringList mapsWithConnections; - - QMap<QString, Map*> *map_cache; - Map* loadMap(QString); - Map* getMap(QString); - - QMap<QString, Tileset*> *tileset_cache = nullptr; - Tileset* loadTileset(QString); - Tileset* getTileset(QString); - - Blockdata* readBlockdata(QString); - void loadBlockdata(Map*); - - QString readTextFile(QString path); - void saveTextFile(QString path, QString text); - void appendTextFile(QString path, QString text); - void deleteFile(QString path); - - void readMapGroups(); - Map* addNewMapToGroup(QString mapName, int groupNum); - QString getNewMapName(); - QString getProjectTitle(); - - QList<QStringList>* getLabelMacros(QList<QStringList>*, QString); - QStringList* getLabelValues(QList<QStringList>*, QString); - void readMapHeader(Map*); - void readMapLayoutsTable(); - void readAllMapLayouts(); - QStringList* readLayoutValues(QString layoutName); - void readMapLayout(Map*); - void readMapsWithConnections(); - void loadMapTilesets(Map*); - void loadTilesetAssets(Tileset*); - - void saveBlockdata(Map*); - void saveMapBorder(Map*); - void writeBlockdata(QString, Blockdata*); - void saveAllMaps(); - void saveMap(Map*); - void saveAllDataStructures(); - void saveAllMapLayouts(); - void saveMapGroupsTable(); - void saveMapConstantsHeader(); - void saveHealLocationStruct(Map*); - - QList<QStringList>* parseAsm(QString text); - QStringList getSongNames(); - QStringList getVisibilities(); - QMap<QString, QStringList> getTilesets(); - void readTilesetProperties(); - void readRegionMapSections(); - void readItemNames(); - void readFlagNames(); - void readVarNames(); - void readMovementTypes(); - void readMapTypes(); - void readMapBattleScenes(); - void readWeatherNames(); - void readCoordEventWeatherNames(); - void readSecretBaseIds(); - void readBgEventFacingDirections(); - - void loadEventPixmaps(QList<Event*> objects); - QMap<QString, int> getEventObjGfxConstants(); - QString fixGraphicPath(QString path); - - void readMapEvents(Map *map); - void loadMapConnections(Map *map); - - void loadMapBorder(Map *map); - - void saveMapEvents(Map *map); - - QStringList readCArray(QString text, QString label); - QString readCIncbin(QString text, QString label); - QMap<QString, int> readCDefines(QString text, QStringList prefixes); - - static int getNumTilesPrimary(); - static int getNumTilesTotal(); - static int getNumMetatilesPrimary(); - static int getNumMetatilesTotal(); - static int getNumPalettesPrimary(); - static int getNumPalettesTotal(); -private: - QString getMapLayoutsTableFilepath(); - QString getMapLayoutFilepath(QString); - void saveMapHeader(Map*); - void saveMapConnections(Map*); - void updateMapsWithConnections(Map*); - void saveMapsWithConnections(); - void saveMapLayoutsTable(); - void updateMapLayout(Map*); - void readCDefinesSorted(QString, QStringList, QStringList*); - void readCDefinesSorted(QString, QStringList, QStringList*, QString, int); - - void setNewMapHeader(Map* map, int mapIndex); - void setNewMapLayout(Map* map); - void setNewMapBlockdata(Map* map); - void setNewMapBorder(Map *map); - void setNewMapEvents(Map *map); - void setNewMapConnections(Map *map); - - static int num_tiles_primary; - static int num_tiles_total; - static int num_metatiles_primary; - static int num_metatiles_total; - static int num_pals_primary; - static int num_pals_total; -}; - -#endif // PROJECT_H +#ifndef PROJECT_H +#define PROJECT_H + +#include "map.h" +#include "blockdata.h" +#include "heallocation.h" + +#include <QStringList> +#include <QList> +#include <QStandardItem> + +static QString NONE_MAP_CONSTANT = "MAP_NONE"; +static QString NONE_MAP_NAME = "None"; + +class Project +{ +public: + Project(); + QString root; + QStringList *groupNames = nullptr; + QMap<QString, int> *map_groups; + QList<QStringList> groupedMapNames; + QStringList *mapNames = nullptr; + QList<HealLocation> flyableMaps; + QMap<QString, QString>* mapConstantsToMapNames; + QMap<QString, QString>* mapNamesToMapConstants; + QList<QString> mapLayoutsTable; + QList<QString> mapLayoutsTableMaster; + QMap<QString, MapLayout*> mapLayouts; + QMap<QString, MapLayout*> mapLayoutsMaster; + QStringList *regionMapSections = nullptr; + QStringList *itemNames = nullptr; + QStringList *flagNames = nullptr; + QStringList *varNames = nullptr; + QStringList *movementTypes = nullptr; + QStringList *mapTypes = nullptr; + QStringList *mapBattleScenes = nullptr; + QStringList *weatherNames = nullptr; + QStringList *coordEventWeatherNames = nullptr; + QStringList *secretBaseIds = nullptr; + QStringList *bgEventFacingDirections = nullptr; + QStringList mapsWithConnections; + + QMap<QString, Map*> *map_cache; + Map* loadMap(QString); + Map* getMap(QString); + + QMap<QString, Tileset*> *tileset_cache = nullptr; + Tileset* loadTileset(QString); + Tileset* getTileset(QString); + + Blockdata* readBlockdata(QString); + void loadBlockdata(Map*); + + QString readTextFile(QString path); + void saveTextFile(QString path, QString text); + void appendTextFile(QString path, QString text); + void deleteFile(QString path); + + void readMapGroups(); + Map* addNewMapToGroup(QString mapName, int groupNum); + QString getNewMapName(); + QString getProjectTitle(); + + QList<QStringList>* getLabelMacros(QList<QStringList>*, QString); + QStringList* getLabelValues(QList<QStringList>*, QString); + void readMapHeader(Map*); + void readMapLayoutsTable(); + void readAllMapLayouts(); + QStringList* readLayoutValues(QString layoutName); + void readMapLayout(Map*); + void readMapsWithConnections(); + void loadMapTilesets(Map*); + void loadTilesetAssets(Tileset*); + + void saveBlockdata(Map*); + void saveMapBorder(Map*); + void writeBlockdata(QString, Blockdata*); + void saveAllMaps(); + void saveMap(Map*); + void saveAllDataStructures(); + void saveAllMapLayouts(); + void saveMapGroupsTable(); + void saveMapConstantsHeader(); + void saveHealLocationStruct(Map*); + + QList<QStringList>* parseAsm(QString text); + QStringList getSongNames(); + QStringList getVisibilities(); + QMap<QString, QStringList> getTilesets(); + void readTilesetProperties(); + void readRegionMapSections(); + void readItemNames(); + void readFlagNames(); + void readVarNames(); + void readMovementTypes(); + void readMapTypes(); + void readMapBattleScenes(); + void readWeatherNames(); + void readCoordEventWeatherNames(); + void readSecretBaseIds(); + void readBgEventFacingDirections(); + + void loadEventPixmaps(QList<Event*> objects); + QMap<QString, int> getEventObjGfxConstants(); + QString fixGraphicPath(QString path); + + void readMapEvents(Map *map); + void loadMapConnections(Map *map); + + void loadMapBorder(Map *map); + + void saveMapEvents(Map *map); + + QStringList readCArray(QString text, QString label); + QString readCIncbin(QString text, QString label); + QMap<QString, int> readCDefines(QString text, QStringList prefixes); + + static int getNumTilesPrimary(); + static int getNumTilesTotal(); + static int getNumMetatilesPrimary(); + static int getNumMetatilesTotal(); + static int getNumPalettesPrimary(); + static int getNumPalettesTotal(); +private: + QString getMapLayoutsTableFilepath(); + QString getMapLayoutFilepath(QString); + void saveMapHeader(Map*); + void saveMapConnections(Map*); + void updateMapsWithConnections(Map*); + void saveMapsWithConnections(); + void saveMapLayoutsTable(); + void updateMapLayout(Map*); + void readCDefinesSorted(QString, QStringList, QStringList*); + void readCDefinesSorted(QString, QStringList, QStringList*, QString, int); + + void setNewMapHeader(Map* map, int mapIndex); + void setNewMapLayout(Map* map); + void setNewMapBlockdata(Map* map); + void setNewMapBorder(Map *map); + void setNewMapEvents(Map *map); + void setNewMapConnections(Map *map); + + static int num_tiles_primary; + static int num_tiles_total; + static int num_metatiles_primary; + static int num_metatiles_total; + static int num_pals_primary; + static int num_pals_total; +}; + +#endif // PROJECT_H diff --git a/resources/icons/add.ico b/src/resources/icons/add.ico old mode 100755 new mode 100644 similarity index 100% rename from resources/icons/add.ico rename to src/resources/icons/add.ico diff --git a/resources/icons/cursor.ico b/src/resources/icons/cursor.ico old mode 100755 new mode 100644 similarity index 100% rename from resources/icons/cursor.ico rename to src/resources/icons/cursor.ico diff --git a/resources/icons/delete.ico b/src/resources/icons/delete.ico old mode 100755 new mode 100644 similarity index 100% rename from resources/icons/delete.ico rename to src/resources/icons/delete.ico diff --git a/resources/icons/fill_color.ico b/src/resources/icons/fill_color.ico old mode 100755 new mode 100644 similarity index 100% rename from resources/icons/fill_color.ico rename to src/resources/icons/fill_color.ico diff --git a/resources/icons/fill_color_cursor.ico b/src/resources/icons/fill_color_cursor.ico similarity index 100% rename from resources/icons/fill_color_cursor.ico rename to src/resources/icons/fill_color_cursor.ico diff --git a/resources/icons/folder.ico b/src/resources/icons/folder.ico old mode 100755 new mode 100644 similarity index 100% rename from resources/icons/folder.ico rename to src/resources/icons/folder.ico diff --git a/resources/icons/folder_closed.ico b/src/resources/icons/folder_closed.ico old mode 100755 new mode 100644 similarity index 100% rename from resources/icons/folder_closed.ico rename to src/resources/icons/folder_closed.ico diff --git a/resources/icons/folder_closed_map.ico b/src/resources/icons/folder_closed_map.ico old mode 100755 new mode 100644 similarity index 100% rename from resources/icons/folder_closed_map.ico rename to src/resources/icons/folder_closed_map.ico diff --git a/resources/icons/folder_image.ico b/src/resources/icons/folder_image.ico old mode 100755 new mode 100644 similarity index 100% rename from resources/icons/folder_image.ico rename to src/resources/icons/folder_image.ico diff --git a/resources/icons/folder_map.ico b/src/resources/icons/folder_map.ico old mode 100755 new mode 100644 similarity index 100% rename from resources/icons/folder_map.ico rename to src/resources/icons/folder_map.ico diff --git a/resources/icons/image.ico b/src/resources/icons/image.ico old mode 100755 new mode 100644 similarity index 100% rename from resources/icons/image.ico rename to src/resources/icons/image.ico diff --git a/resources/icons/map.ico b/src/resources/icons/map.ico old mode 100755 new mode 100644 similarity index 100% rename from resources/icons/map.ico rename to src/resources/icons/map.ico diff --git a/resources/icons/move.ico b/src/resources/icons/move.ico similarity index 100% rename from resources/icons/move.ico rename to src/resources/icons/move.ico diff --git a/resources/icons/pencil.ico b/src/resources/icons/pencil.ico old mode 100755 new mode 100644 similarity index 100% rename from resources/icons/pencil.ico rename to src/resources/icons/pencil.ico diff --git a/resources/icons/pencil_cursor.ico b/src/resources/icons/pencil_cursor.ico similarity index 100% rename from resources/icons/pencil_cursor.ico rename to src/resources/icons/pencil_cursor.ico diff --git a/resources/icons/pipette.ico b/src/resources/icons/pipette.ico old mode 100755 new mode 100644 similarity index 100% rename from resources/icons/pipette.ico rename to src/resources/icons/pipette.ico diff --git a/resources/icons/pipette_cursor.ico b/src/resources/icons/pipette_cursor.ico similarity index 100% rename from resources/icons/pipette_cursor.ico rename to src/resources/icons/pipette_cursor.ico diff --git a/resources/icons/porymap-icon-1.ico b/src/resources/icons/porymap-icon-1.ico similarity index 100% rename from resources/icons/porymap-icon-1.ico rename to src/resources/icons/porymap-icon-1.ico diff --git a/resources/icons/shift.ico b/src/resources/icons/shift.ico similarity index 100% rename from resources/icons/shift.ico rename to src/resources/icons/shift.ico diff --git a/resources/icons/shift_cursor.ico b/src/resources/icons/shift_cursor.ico similarity index 100% rename from resources/icons/shift_cursor.ico rename to src/resources/icons/shift_cursor.ico diff --git a/resources/icons/viewsprites.ico b/src/resources/icons/viewsprites.ico old mode 100755 new mode 100644 similarity index 100% rename from resources/icons/viewsprites.ico rename to src/resources/icons/viewsprites.ico diff --git a/resources/images.qrc b/src/resources/images.qrc old mode 100755 new mode 100644 similarity index 97% rename from resources/images.qrc rename to src/resources/images.qrc index 78fbe6a1..ac1ff8cb --- a/resources/images.qrc +++ b/src/resources/images.qrc @@ -1,27 +1,27 @@ -<RCC> - <qresource prefix="/"> - <file>icons/folder.ico</file> - <file>icons/folder_closed.ico</file> - <file>icons/folder_closed_map.ico</file> - <file>icons/folder_image.ico</file> - <file>icons/folder_map.ico</file> - <file>icons/image.ico</file> - <file>icons/map.ico</file> - <file>icons/cursor.ico</file> - <file>icons/fill_color.ico</file> - <file>icons/move.ico</file> - <file>icons/pencil.ico</file> - <file>icons/pipette.ico</file> - <file>images/Entities_16x16.png</file> - <file>icons/add.ico</file> - <file>icons/delete.ico</file> - <file>icons/viewsprites.ico</file> - <file>images/collisions.png</file> - <file>icons/fill_color_cursor.ico</file> - <file>icons/pencil_cursor.ico</file> - <file>icons/pipette_cursor.ico</file> - <file>icons/shift.ico</file> - <file>icons/shift_cursor.ico</file> - <file>icons/porymap-icon-1.ico</file> - </qresource> -</RCC> +<RCC> + <qresource prefix="/"> + <file>icons/folder.ico</file> + <file>icons/folder_closed.ico</file> + <file>icons/folder_closed_map.ico</file> + <file>icons/folder_image.ico</file> + <file>icons/folder_map.ico</file> + <file>icons/image.ico</file> + <file>icons/map.ico</file> + <file>icons/cursor.ico</file> + <file>icons/fill_color.ico</file> + <file>icons/move.ico</file> + <file>icons/pencil.ico</file> + <file>icons/pipette.ico</file> + <file>images/Entities_16x16.png</file> + <file>icons/add.ico</file> + <file>icons/delete.ico</file> + <file>icons/viewsprites.ico</file> + <file>images/collisions.png</file> + <file>icons/fill_color_cursor.ico</file> + <file>icons/pencil_cursor.ico</file> + <file>icons/pipette_cursor.ico</file> + <file>icons/shift.ico</file> + <file>icons/shift_cursor.ico</file> + <file>icons/porymap-icon-1.ico</file> + </qresource> +</RCC> diff --git a/resources/images/Entities_16x16.png b/src/resources/images/Entities_16x16.png old mode 100755 new mode 100644 similarity index 100% rename from resources/images/Entities_16x16.png rename to src/resources/images/Entities_16x16.png diff --git a/resources/images/collisions.png b/src/resources/images/collisions.png similarity index 100% rename from resources/images/collisions.png rename to src/resources/images/collisions.png diff --git a/settings.cpp b/src/settings.cpp similarity index 100% rename from settings.cpp rename to src/settings.cpp diff --git a/settings.h b/src/settings.h similarity index 100% rename from settings.h rename to src/settings.h diff --git a/ui/bordermetatilespixmapitem.cpp b/src/ui/bordermetatilespixmapitem.cpp similarity index 100% rename from ui/bordermetatilespixmapitem.cpp rename to src/ui/bordermetatilespixmapitem.cpp diff --git a/ui/bordermetatilespixmapitem.h b/src/ui/bordermetatilespixmapitem.h similarity index 100% rename from ui/bordermetatilespixmapitem.h rename to src/ui/bordermetatilespixmapitem.h diff --git a/ui/collisionpixmapitem.cpp b/src/ui/collisionpixmapitem.cpp similarity index 100% rename from ui/collisionpixmapitem.cpp rename to src/ui/collisionpixmapitem.cpp diff --git a/ui/collisionpixmapitem.h b/src/ui/collisionpixmapitem.h similarity index 100% rename from ui/collisionpixmapitem.h rename to src/ui/collisionpixmapitem.h diff --git a/ui/connectionpixmapitem.cpp b/src/ui/connectionpixmapitem.cpp similarity index 100% rename from ui/connectionpixmapitem.cpp rename to src/ui/connectionpixmapitem.cpp diff --git a/ui/connectionpixmapitem.h b/src/ui/connectionpixmapitem.h similarity index 100% rename from ui/connectionpixmapitem.h rename to src/ui/connectionpixmapitem.h diff --git a/ui/currentselectedmetatilespixmapitem.cpp b/src/ui/currentselectedmetatilespixmapitem.cpp similarity index 100% rename from ui/currentselectedmetatilespixmapitem.cpp rename to src/ui/currentselectedmetatilespixmapitem.cpp diff --git a/ui/currentselectedmetatilespixmapitem.h b/src/ui/currentselectedmetatilespixmapitem.h similarity index 100% rename from ui/currentselectedmetatilespixmapitem.h rename to src/ui/currentselectedmetatilespixmapitem.h diff --git a/ui/eventpropertiesframe.cpp b/src/ui/eventpropertiesframe.cpp similarity index 100% rename from ui/eventpropertiesframe.cpp rename to src/ui/eventpropertiesframe.cpp diff --git a/ui/eventpropertiesframe.h b/src/ui/eventpropertiesframe.h similarity index 100% rename from ui/eventpropertiesframe.h rename to src/ui/eventpropertiesframe.h diff --git a/ui/graphicsview.cpp b/src/ui/graphicsview.cpp similarity index 100% rename from ui/graphicsview.cpp rename to src/ui/graphicsview.cpp diff --git a/ui/graphicsview.h b/src/ui/graphicsview.h similarity index 100% rename from ui/graphicsview.h rename to src/ui/graphicsview.h diff --git a/ui/imageproviders.cpp b/src/ui/imageproviders.cpp similarity index 100% rename from ui/imageproviders.cpp rename to src/ui/imageproviders.cpp diff --git a/ui/imageproviders.h b/src/ui/imageproviders.h similarity index 100% rename from ui/imageproviders.h rename to src/ui/imageproviders.h diff --git a/ui/mappixmapitem.cpp b/src/ui/mappixmapitem.cpp similarity index 100% rename from ui/mappixmapitem.cpp rename to src/ui/mappixmapitem.cpp diff --git a/ui/mappixmapitem.h b/src/ui/mappixmapitem.h similarity index 100% rename from ui/mappixmapitem.h rename to src/ui/mappixmapitem.h diff --git a/ui/metatileselector.cpp b/src/ui/metatileselector.cpp similarity index 100% rename from ui/metatileselector.cpp rename to src/ui/metatileselector.cpp diff --git a/ui/metatileselector.h b/src/ui/metatileselector.h similarity index 100% rename from ui/metatileselector.h rename to src/ui/metatileselector.h diff --git a/ui/movementpermissionsselector.cpp b/src/ui/movementpermissionsselector.cpp similarity index 100% rename from ui/movementpermissionsselector.cpp rename to src/ui/movementpermissionsselector.cpp diff --git a/ui/movementpermissionsselector.h b/src/ui/movementpermissionsselector.h similarity index 100% rename from ui/movementpermissionsselector.h rename to src/ui/movementpermissionsselector.h diff --git a/ui/neweventtoolbutton.cpp b/src/ui/neweventtoolbutton.cpp similarity index 100% rename from ui/neweventtoolbutton.cpp rename to src/ui/neweventtoolbutton.cpp diff --git a/ui/neweventtoolbutton.h b/src/ui/neweventtoolbutton.h similarity index 100% rename from ui/neweventtoolbutton.h rename to src/ui/neweventtoolbutton.h diff --git a/ui/noscrollcombobox.cpp b/src/ui/noscrollcombobox.cpp similarity index 100% rename from ui/noscrollcombobox.cpp rename to src/ui/noscrollcombobox.cpp diff --git a/ui/noscrollcombobox.h b/src/ui/noscrollcombobox.h similarity index 100% rename from ui/noscrollcombobox.h rename to src/ui/noscrollcombobox.h diff --git a/ui/noscrollspinbox.cpp b/src/ui/noscrollspinbox.cpp similarity index 100% rename from ui/noscrollspinbox.cpp rename to src/ui/noscrollspinbox.cpp diff --git a/ui/noscrollspinbox.h b/src/ui/noscrollspinbox.h similarity index 100% rename from ui/noscrollspinbox.h rename to src/ui/noscrollspinbox.h diff --git a/ui/selectablepixmapitem.cpp b/src/ui/selectablepixmapitem.cpp similarity index 100% rename from ui/selectablepixmapitem.cpp rename to src/ui/selectablepixmapitem.cpp diff --git a/ui/selectablepixmapitem.h b/src/ui/selectablepixmapitem.h similarity index 100% rename from ui/selectablepixmapitem.h rename to src/ui/selectablepixmapitem.h