diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui
index cdb4dcb8..c2f0647c 100644
--- a/forms/mainwindow.ui
+++ b/forms/mainwindow.ui
@@ -1715,7 +1715,7 @@
0
0
100
- 16
+ 30
@@ -1809,7 +1809,7 @@
0
0
100
- 16
+ 30
@@ -1903,7 +1903,7 @@
0
0
100
- 16
+ 30
@@ -2003,7 +2003,7 @@
0
0
100
- 16
+ 30
@@ -2097,7 +2097,7 @@
0
0
100
- 16
+ 30
@@ -2596,6 +2596,9 @@
true
+
+ true
+
-
@@ -2667,6 +2670,9 @@
true
+
+ true
+
-
@@ -2757,8 +2763,8 @@
0
0
- 365
- 658
+ 100
+ 30
diff --git a/include/core/map.h b/include/core/map.h
index a6f6fa1c..83f9a9d1 100644
--- a/include/core/map.h
+++ b/include/core/map.h
@@ -98,7 +98,7 @@ public:
QStringList getScriptLabels(Event::Group group = Event::Group::None);
void removeEvent(Event *);
void addEvent(Event *);
- QPixmap renderConnection(MapConnection, MapLayout *);
+ QPixmap renderConnection(const MapConnection&, MapLayout *);
QPixmap renderBorder(bool ignoreCache = false);
void setDimensions(int newWidth, int newHeight, bool setNewBlockdata = true, bool enableScriptCallback = false);
void setBorderDimensions(int newWidth, int newHeight, bool setNewBlockdata = true, bool enableScriptCallback = false);
diff --git a/include/core/mapconnection.h b/include/core/mapconnection.h
index 474be5b1..a7077813 100644
--- a/include/core/mapconnection.h
+++ b/include/core/mapconnection.h
@@ -12,6 +12,12 @@ public:
QString direction;
int offset;
QString map_name;
+
+ static const QStringList cardinalDirections;
+ static bool isCardinal(const QString &direction);
+ static bool isHorizontal(const QString &direction);
+ static bool isVertical(const QString &direction);
+ static MapConnection mirror(const MapConnection &source, const QString &mapName);
};
struct MapConnectionMirror {
diff --git a/include/editor.h b/include/editor.h
index f0b54b69..7c878023 100644
--- a/include/editor.h
+++ b/include/editor.h
@@ -168,14 +168,13 @@ private:
QPixmap collisionSheetPixmap;
void updateBorderVisibility();
- QPoint calculateConnectionPosition(const MapConnection *connection, const QPixmap &pixmap);
+ QPoint calculateConnectionPosition(const MapConnection &connection, const QPixmap &pixmap);
+ QPixmap getConnectionPixmap(const MapConnection &connection);
void updateConnectionItem(ConnectionPixmapItem* connectionItem);
void updateConnectionItemPos(ConnectionPixmapItem* connectionItem);
void createConnectionItem(MapConnection* connection);
- void populateConnectionsList();
void addConnectionToList(ConnectionPixmapItem* connection);
void updateDiveEmergeMap(QString mapName, QString direction);
- bool shouldMirrorConnection(const MapConnection &source);
MapConnectionMirror getMirroredConnection(const MapConnection&);
void addMirroredConnection(const MapConnection&);
void removeMirroredConnection(const MapConnection&);
@@ -197,7 +196,7 @@ private slots:
void setConnectionOffset(MapConnection *connection, int offset);
void setConnectionMap(MapConnection *connection, const QString &mapName);
void setConnectionDirection(MapConnection *connection, const QString &direction);
- void onConnectionItemSelected(ConnectionPixmapItem* connectionItem);
+ void setSelectedConnection(ConnectionPixmapItem* connectionItem);
void onHoveredMovementPermissionChanged(uint16_t, uint16_t);
void onHoveredMovementPermissionCleared();
void onHoveredMetatileSelectionChanged(uint16_t);
diff --git a/include/ui/connectionpixmapitem.h b/include/ui/connectionpixmapitem.h
index f0e00ae1..4f18b649 100644
--- a/include/ui/connectionpixmapitem.h
+++ b/include/ui/connectionpixmapitem.h
@@ -28,13 +28,14 @@ public:
int initialOffset;
int baseMapWidth;
int baseMapHeight;
- void render(qreal opacity = 1);
+
void setEditable(bool editable);
bool getEditable();
- void updateHighlight(bool selected);
+ void setSelected(bool selected);
+ void render();
private:
- bool highlighted = false;
+ bool selected = false;
protected:
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
@@ -42,10 +43,9 @@ protected:
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent*);
signals:
- void connectionItemSelected(ConnectionPixmapItem* connectionItem);
void connectionItemDoubleClicked(ConnectionPixmapItem* connectionItem);
void connectionMoved(MapConnection *, int newOffset);
- void highlightChanged(bool highlighted);
+ void selectionChanged(bool selected);
};
#endif // CONNECTIONPIXMAPITEM_H
diff --git a/include/ui/noscrollcombobox.h b/include/ui/noscrollcombobox.h
index 59c680a3..43db9deb 100644
--- a/include/ui/noscrollcombobox.h
+++ b/include/ui/noscrollcombobox.h
@@ -13,6 +13,7 @@ public:
void setTextItem(const QString &text);
void setNumberItem(int value);
void setHexItem(uint32_t value);
+ void setClearButtonEnabled(bool enabled);
private:
void setItem(int index, const QString &text);
diff --git a/porymap.pro b/porymap.pro
index 5c898302..8afc99a5 100644
--- a/porymap.pro
+++ b/porymap.pro
@@ -24,6 +24,7 @@ SOURCES += src/core/block.cpp \
src/core/heallocation.cpp \
src/core/imageexport.cpp \
src/core/map.cpp \
+ src/core/mapconnection.cpp \
src/core/maplayout.cpp \
src/core/mapparser.cpp \
src/core/metatile.cpp \
diff --git a/src/core/map.cpp b/src/core/map.cpp
index 463b9341..fad4683a 100644
--- a/src/core/map.cpp
+++ b/src/core/map.cpp
@@ -217,34 +217,21 @@ QPixmap Map::renderBorder(bool ignoreCache) {
return layout->border_pixmap;
}
-QPixmap Map::renderConnection(MapConnection connection, MapLayout * fromLayout) {
- int x, y, w, h;
+QPixmap Map::renderConnection(const MapConnection &connection, MapLayout * fromLayout) {
+ if (!MapConnection::isCardinal(connection.direction))
+ return QPixmap();
+
+ int x = 0, y = 0, w = getWidth(), h = getHeight();
if (connection.direction == "up") {
- x = 0;
y = getHeight() - BORDER_DISTANCE;
- w = getWidth();
h = BORDER_DISTANCE;
} else if (connection.direction == "down") {
- x = 0;
- y = 0;
- w = getWidth();
h = BORDER_DISTANCE;
} else if (connection.direction == "left") {
x = getWidth() - BORDER_DISTANCE;
- y = 0;
w = BORDER_DISTANCE;
- h = getHeight();
} else if (connection.direction == "right") {
- x = 0;
- y = 0;
w = BORDER_DISTANCE;
- h = getHeight();
- } else {
- // this should not happen
- x = 0;
- y = 0;
- w = getWidth();
- h = getHeight();
}
render(true, fromLayout, QRect(x, y, w, h));
diff --git a/src/core/mapconnection.cpp b/src/core/mapconnection.cpp
index ebf48592..82a0b71e 100644
--- a/src/core/mapconnection.cpp
+++ b/src/core/mapconnection.cpp
@@ -1,43 +1,35 @@
#include "mapconnection.h"
#include "map.h"
-void MapConnection::setDirection(const QString & direction) {
- if (direction == m_direction)
- return;
- auto before = m_direction;
- m_direction = direction;
- emit directionChanged(before, m_direction);
-}
+const QStringList MapConnection::cardinalDirections = {
+ "up", "down", "left", "right"
+};
-void MapConnection::setOffset(int offset) {
- if (offset == m_offset)
- return;
- auto before = m_offset;
- m_offset = offset;
- emit offsetChanged(before, m_offset);
-}
-
-void MapConnection::setMapName(const QString &mapName) {
- if (mapName == m_mapName)
- return;
- auto before = m_mapName;
- m_mapName = mapName;
- emit mapNameChanged(before, m_mapName);
-}
-/*
-static QString MapConnection::oppositeDirection(const QString &direction) {
+MapConnection MapConnection::mirror(const MapConnection &source, const QString &mapName) {
static const QMap oppositeDirections = {
{"up", "down"}, {"down", "up"},
{"right", "left"}, {"left", "right"},
{"dive", "emerge"}, {"emerge", "dive"}
};
- return oppositeDirections.value(direction);
+
+ // TODO: Allowing editing unknown directions is a can of worms.
+ // Specifically a self-connection with an empty direction and an offset of 0 can be identified as its own mirror
+ MapConnection mirror;
+ mirror.direction = oppositeDirections.value(source.direction/*, source.direction*/);
+ mirror.map_name = mapName;
+ mirror.offset = -source.offset;
+
+ return mirror;
}
-static MapConnection* MapConnection::getMirror(const MapConnection*, const Map*) {
-
+bool MapConnection::isHorizontal(const QString &direction) {
+ return direction == "left" || direction == "right";
}
-static MapConnection* MapConnection::newMirror(const MapConnection*) {
+bool MapConnection::isVertical(const QString &direction) {
+ return direction == "up" || direction == "down";
+}
-}*/
+bool MapConnection::isCardinal(const QString &direction) {
+ return cardinalDirections.contains(direction);
+}
diff --git a/src/editor.cpp b/src/editor.cpp
index b88ac4cf..0f23f331 100644
--- a/src/editor.cpp
+++ b/src/editor.cpp
@@ -89,7 +89,6 @@ void Editor::setEditingMap() {
current_view = map_item;
if (map_item) {
map_item->paintingMode = MapPixmapItem::PaintMode::Metatiles;
- displayMapConnections();
map_item->draw();
map_item->setVisible(true);
}
@@ -109,7 +108,6 @@ void Editor::setEditingMap() {
void Editor::setEditingCollision() {
current_view = collision_item;
if (collision_item) {
- displayMapConnections();
collision_item->draw();
collision_item->setVisible(true);
}
@@ -135,7 +133,6 @@ void Editor::setEditingObjects() {
}
if (map_item) {
map_item->paintingMode = MapPixmapItem::PaintMode::EventObjects;
- displayMapConnections();
map_item->draw();
map_item->setVisible(true);
}
@@ -172,8 +169,6 @@ void Editor::setEditingConnections() {
map_item->paintingMode = MapPixmapItem::PaintMode::Disabled;
map_item->draw();
map_item->setVisible(true);
- populateConnectionsList();
- maskNonVisibleConnectionTiles();
}
if (collision_item) {
collision_item->setVisible(false);
@@ -722,58 +717,15 @@ void Editor::updateEncounterFields(EncounterFields newFields) {
project->wildMonFields = newFields;
}
-void Editor::populateConnectionsList() {
- const QSignalBlocker blocker1(ui->comboBox_DiveMap);
- const QSignalBlocker blocker2(ui->comboBox_EmergeMap);
-
- // TODO: We should probably just be doing this once, and updating the items when new maps are created.
- ui->comboBox_DiveMap->clear();
- ui->comboBox_EmergeMap->clear();
- ui->comboBox_DiveMap->addItems(project->mapNames);
- ui->comboBox_EmergeMap->addItems(project->mapNames);
- ui->comboBox_DiveMap->setCurrentText("");
- ui->comboBox_EmergeMap->setCurrentText("");
- ui->comboBox_DiveMap->lineEdit()->setClearButtonEnabled(true);
- ui->comboBox_EmergeMap->lineEdit()->setClearButtonEnabled(true);
-
- 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);
- }
- }
-
- // Clear any existing connections in list
- for (auto listItem : ui->scrollAreaContents_ConnectionsList->findChildren())
- listItem->deleteLater();
-
- for (auto item :connection_items)
- addConnectionToList(item);
-}
-
-// TODO: When connecting a map to itself the new mirror is shaded incorrectly
-// TODO: Set default focus to the selected connection, right now it defaults to the dive combo box
-
void Editor::addConnectionToList(ConnectionPixmapItem * connectionItem) {
ConnectionsListItem *listItem = new ConnectionsListItem(ui->scrollAreaContents_ConnectionsList, connectionItem->connection, project->mapNames);
ui->layout_ConnectionsList->insertWidget(ui->layout_ConnectionsList->count() - 1, listItem); // Insert above the vertical spacer
// Sync the selection highlight between the list UI and the graphical map connection
- connect(connectionItem, &ConnectionPixmapItem::highlightChanged, listItem, &ConnectionsListItem::setSelected);
+ connect(connectionItem, &ConnectionPixmapItem::selectionChanged, listItem, &ConnectionsListItem::setSelected);
connect(listItem, &ConnectionsListItem::selected, [this, connectionItem] {
- // When the list item is selected, select the pixmap too
- if (connectionItem == selected_connection_item) {
- // Already selected, no change
- return;
- }
- // Deselect old connection and select new connection
- if (selected_connection_item) selected_connection_item->updateHighlight(false);
- selected_connection_item = connectionItem;
- selected_connection_item->updateHighlight(true);
+ setSelectedConnection(connectionItem);
});
- if (connectionItem == selected_connection_item)
- listItem->setSelected(true);
// Sync edits to 'offset' between the list UI and the graphical map connection
connect(connectionItem, &ConnectionPixmapItem::connectionMoved, [this, listItem](MapConnection* connection, int offset) {
@@ -787,9 +739,10 @@ void Editor::addConnectionToList(ConnectionPixmapItem * connectionItem) {
// Sync edits to 'direction' or 'map' between the list UI and the graphical map connection.
// These are 1-way because the direction and map cannot be edited graphically, only via the list UI.
- connect(listItem, &ConnectionsListItem::editedDirection, [this, connectionItem](MapConnection* connection, QString direction) {
+ connect(listItem, &ConnectionsListItem::editedDirection, [this, connectionItem, listItem](MapConnection* connection, QString direction) {
setConnectionDirection(connection, direction);
- updateConnectionItem(connectionItem); // TODO: Simplify?
+ updateConnectionItem(connectionItem); // TODO: Simplify
+ listItem->updateUI(); // Changing direction may have changed our offset too
});
connect(listItem, &ConnectionsListItem::editedMapName, [this, connectionItem](MapConnection* connection, QString mapName) {
setConnectionMap(connection, mapName);
@@ -813,13 +766,13 @@ void Editor::addConnectionToList(ConnectionPixmapItem * connectionItem) {
void Editor::addNewConnection() {
// Find direction with least number of connections.
- QMap directionCounts = QMap({{"up", 0}, {"right", 0}, {"down", 0}, {"left", 0}});
+ QMap directionCounts;
for (MapConnection* connection : map->connections) {
directionCounts[connection->direction]++;
}
QString minDirection = "up";
int minCount = INT_MAX;
- for (QString direction : directionCounts.keys()) {
+ for (QString direction : MapConnection::cardinalDirections) {
if (directionCounts[direction] < minCount) {
minDirection = direction;
minCount = directionCounts[direction];
@@ -827,7 +780,6 @@ void Editor::addNewConnection() {
}
// Prefer not to connect the map to itself (we have to if it's the only map).
- // TODO: Is this more or less sensible than a connection with no map name
QString defaultMapName = project->mapNames.first();
if (defaultMapName == map->name && project->mapNames.length() > 1) {
defaultMapName = project->mapNames.at(1);
@@ -838,11 +790,14 @@ void Editor::addNewConnection() {
newConnection->offset = 0;
newConnection->map_name = defaultMapName;
addConnection(map, newConnection);
- onConnectionItemSelected(connection_items.last());
+ setSelectedConnection(connection_items.last());
addMirroredConnection(*newConnection);
}
void Editor::addConnection(Map* map, MapConnection * connection) {
+ if (!map || !connection)
+ return;
+
map->connections.append(connection);
if (map == this->map) {
// Adding a connection to the current map, we need to display it visually.
@@ -857,7 +812,6 @@ void Editor::addConnection(Map* map, MapConnection * connection) {
ui->comboBox_EmergeMap->setCurrentText(connection->map_name);
} else {
createConnectionItem(connection);
- addConnectionToList(connection_items.last());
}
}
emit editedMapData(map);
@@ -885,7 +839,7 @@ void Editor::removeConnectionItem(ConnectionPixmapItem* connectionItem, bool rem
if (connectionItem == selected_connection_item) {
selected_connection_item = nullptr;
if (!connection_items.isEmpty())
- onConnectionItemSelected(connection_items.first());
+ setSelectedConnection(connection_items.first());
}
delete connectionItem;
}
@@ -902,22 +856,9 @@ void Editor::removeSelectedConnection() {
removeConnectionItem(selected_connection_item);
}
-static const QMap oppositeDirections = {
- {"up", "down"}, {"down", "up"},
- {"right", "left"}, {"left", "right"},
- {"dive", "emerge"}, {"emerge", "dive"}
-};
-
-bool Editor::shouldMirrorConnection(const MapConnection &source) {
- // The current map's connections are not mirrored if the user has disabled this setting,
- // unless it's a connection to itself (which is mirrored by definition).
- // TODO: Confirm in-game representation of the above fact is accurate.
- return ui->checkBox_MirrorConnections->isChecked() || (map && map->name == source.map_name);
-}
-
MapConnectionMirror Editor::getMirroredConnection(const MapConnection &source) {
MapConnectionMirror mirror;
- if (!map || !shouldMirrorConnection(source))
+ if (!map || !ui->checkBox_MirrorConnections->isChecked())
return mirror;
// Note: It's possible (and ok) for mirror.map == this->map
@@ -925,12 +866,10 @@ MapConnectionMirror Editor::getMirroredConnection(const MapConnection &source) {
if (!mirror.map)
return mirror;
- MapConnection target;
- target.direction = oppositeDirections.value(source.direction);
- target.map_name = map->name;
- target.offset = -source.offset;
-
// Find the matching connection in the connected map.
+ // Note: There is no strict source -> mirror pairing, i.e. we are not guaranteed
+ // to always get the same MapConnection if there are multiple identical copies.
+ MapConnection target = MapConnection::mirror(source, map->name);
for (auto connection : mirror.map->connections) {
if (*connection == target) {
mirror.connection = connection;
@@ -946,10 +885,7 @@ void Editor::addMirroredConnection(const MapConnection &source) {
return;
mirror.connection = new MapConnection;
- mirror.connection->direction = oppositeDirections.value(source.direction);
- mirror.connection->map_name = map->name;
- mirror.connection->offset = -source.offset;
-
+ *mirror.connection = MapConnection::mirror(source, map->name);
addConnection(mirror.map, mirror.connection);
}
@@ -993,7 +929,7 @@ void Editor::updateDiveEmergeMap(QString mapName, QString direction) {
return;
}
- // TODO: How does the game handle having multiple Dive/Emerge maps. Should we support this?
+ // Only the first Dive/Emerge map (if present) is considered, as in-game.
MapConnection* connection = nullptr;
for (MapConnection* conn : map->connections) {
if (conn->direction == direction) {
@@ -1002,14 +938,18 @@ void Editor::updateDiveEmergeMap(QString mapName, QString direction) {
}
}
- // We (lazily) always update the connection by deleting the old one and creating a new one.
- // Unlike the displayed connections which can be updated rapidly by click+drag, this isn't
- // really an issue for Dive/Emerge maps.
+ // Dive/Emerge maps aren't represented visually (aside from their combo boxes),
+ // so we have less to do here than a normal connection.
if (connection) {
- removeMirroredConnection(*connection);
- removeConnection(map, connection);
- }
- if (!mapName.isEmpty() && mapName != DYNAMIC_MAP_NAME) {
+ // Update existing connection
+ if (mapName.isEmpty()) {
+ removeMirroredConnection(*connection);
+ removeConnection(map, connection);
+ } else {
+ setConnectionMap(connection, mapName);
+ }
+ } else if (!mapName.isEmpty()) {
+ // Create new connection
connection = new MapConnection;
connection->direction = direction;
connection->offset = 0;
@@ -1019,25 +959,36 @@ void Editor::updateDiveEmergeMap(QString mapName, QString direction) {
}
}
-QPoint Editor::calculateConnectionPosition(const MapConnection *connection, const QPixmap &pixmap) {
+QPoint Editor::calculateConnectionPosition(const MapConnection &connection, const QPixmap &pixmap) {
int x = 0, y = 0;
const int mWidth = 16, mHeight = 16;
- if (connection->direction == "up") {
- x = connection->offset * mWidth;
+ if (connection.direction == "up") {
+ x = connection.offset * mWidth;
y = -pixmap.height();
- } else if (connection->direction == "down") {
- x = connection->offset * mWidth;
+ } else if (connection.direction == "down") {
+ x = connection.offset * mWidth;
y = map->getHeight() * mHeight;
- } else if (connection->direction == "left") {
+ } else if (connection.direction == "left") {
x = -pixmap.width();
- y = connection->offset * mHeight;
- } else if (connection->direction == "right") {
+ y = connection.offset * mHeight;
+ } else if (connection.direction == "right") {
x = map->getWidth() * mWidth;
- y = connection->offset * mHeight;
+ y = connection.offset * mHeight;
}
return QPoint(x, y);
}
+QPixmap Editor::getConnectionPixmap(const MapConnection &connection) {
+ Map *connectedMap = project->getMap(connection.map_name);
+
+ // connectedMap will be null for MAP_DYNAMIC and any map that fails to load.
+ // The connection will be editable from the list, but no image will be displayed on the map.
+ if (!connectedMap)
+ return QPixmap();
+
+ return connectedMap->renderConnection(connection, map->layout);
+}
+
void Editor::updateConnectionItem(ConnectionPixmapItem* connectionItem) {
if (!connectionItem || !connectionItem->connection)
return;
@@ -1046,29 +997,22 @@ void Editor::updateConnectionItem(ConnectionPixmapItem* connectionItem) {
if (mapName.isEmpty())
return;
- // TODO: What happens if a connection is saved with an empty name
- if (mapName == DYNAMIC_MAP_NAME || !project->mapNames.contains(mapName)) {
+ if (!project->mapNames.contains(mapName)) {
logError(QString("Invalid map name '%1' specified for connection.").arg(mapName));
return;
}
- Map *connectedMap = project->getMap(mapName);
- if (!connectedMap)
- return;
-
- QPixmap pixmap = connectedMap->renderConnection(*connectionItem->connection, map->layout);
connectionItem->initialOffset = connectionItem->connection->offset;
- connectionItem->basePixmap = pixmap;
- QPoint pos = calculateConnectionPosition(connectionItem->connection, pixmap);
+ connectionItem->basePixmap = getConnectionPixmap(*connectionItem->connection);
+ QPoint pos = calculateConnectionPosition(*connectionItem->connection, connectionItem->basePixmap);
connectionItem->blockSignals(true);
- connectionItem->setPixmap(pixmap);
- connectionItem->updateHighlight(connectionItem == selected_connection_item);
+ connectionItem->setPixmap(connectionItem->basePixmap);
connectionItem->initialX = pos.x();
connectionItem->initialY = pos.y();
connectionItem->setX(pos.x());
connectionItem->setY(pos.y());
- connectionItem->setZValue(-1);
+ connectionItem->render();
connectionItem->blockSignals(false);
maskNonVisibleConnectionTiles();
@@ -1080,9 +1024,9 @@ void Editor::updateConnectionItemPos(ConnectionPixmapItem* connectionItem) {
MapConnection *connection = connectionItem->connection;
connectionItem->blockSignals(true);
- if (connection->direction == "up" || connection->direction == "down") {
+ if (MapConnection::isVertical(connection->direction)) {
connectionItem->setX(connectionItem->initialX + (connection->offset - connectionItem->initialOffset) * 16);
- } else if (connection->direction == "left" || connection->direction == "right") {
+ } else if (MapConnection::isHorizontal(connection->direction)) {
connectionItem->setY(connectionItem->initialY + (connection->offset - connectionItem->initialOffset) * 16);
}
connectionItem->blockSignals(false);
@@ -1115,7 +1059,6 @@ void Editor::setConnectionOffset(MapConnection *connection, int offset) {
}
}
}
- // TODO: If there's no mirror but there should be we're not creating one
connection->offset = offset;
emit editedMapData(map);
@@ -1141,19 +1084,26 @@ void Editor::setConnectionDirection(MapConnection *connection, const QString &di
// TODO: Lazy
removeMirroredConnection(*connection);
+
+ if (MapConnection::isHorizontal(connection->direction) != MapConnection::isHorizontal(direction)
+ || MapConnection::isVertical(connection->direction) != MapConnection::isVertical(direction)) {
+ // If the direction has changed between vertical/horizontal then the old offset may not make sense, so we reset it
+ setConnectionOffset(connection, 0);
+ }
connection->direction = direction;
+
addMirroredConnection(*connection);
emit editedMapData(map);
}
-void Editor::onConnectionItemSelected(ConnectionPixmapItem* connectionItem) {
- if (!connectionItem)
+void Editor::setSelectedConnection(ConnectionPixmapItem* connectionItem) {
+ if (!connectionItem || connectionItem == selected_connection_item)
return;
+ if (selected_connection_item) selected_connection_item->setSelected(false);
selected_connection_item = connectionItem;
- for (ConnectionPixmapItem* item : connection_items)
- item->updateHighlight(item == selected_connection_item);
+ selected_connection_item->setSelected(true);
}
// TODO: Inaccurate if there are multiple connections from the same map
@@ -1161,7 +1111,7 @@ void Editor::setSelectedConnectionFromMap(QString mapName) {
// Search for the first connection that connects to the given map map.
for (ConnectionPixmapItem* item : connection_items) {
if (item->connection->map_name == mapName) {
- onConnectionItemSelected(item);
+ setSelectedConnection(item);
break;
}
}
@@ -1606,6 +1556,7 @@ bool Editor::displayMap() {
displayMapBorder();
displayMapGrid();
displayWildMonTables();
+ maskNonVisibleConnectionTiles();
this->map_ruler->setZValue(1000);
scene->addItem(this->map_ruler);
@@ -1795,41 +1746,56 @@ void Editor::displayMapConnections() {
selected_connection_item = nullptr;
connection_items.clear();
+ const QSignalBlocker blocker1(ui->comboBox_DiveMap);
+ const QSignalBlocker blocker2(ui->comboBox_EmergeMap);
+ ui->comboBox_DiveMap->clear();
+ ui->comboBox_EmergeMap->clear();
+ ui->comboBox_DiveMap->addItems(project->mapNames);
+ ui->comboBox_EmergeMap->addItems(project->mapNames);
+ ui->comboBox_DiveMap->setCurrentText("");
+ ui->comboBox_EmergeMap->setCurrentText("");
+
+ // Note: We only support editing 1 Dive and Emerge connection per map.
+ // In a vanilla game only the first Dive/Emerge connection is considered, so allowing
+ // users to have multiple is likely to lead to confusion. In case users have changed
+ // this we won't delete extra diving connections, but we'll only display the first one.
for (MapConnection *connection : map->connections) {
- if (connection->direction == "dive" || connection->direction == "emerge") {
- continue;
+ if (connection->direction == "dive") {
+ if (ui->comboBox_DiveMap->currentText().isEmpty())
+ ui->comboBox_DiveMap->setCurrentText(connection->map_name);
+ } else if (connection->direction == "emerge") {
+ if (ui->comboBox_EmergeMap->currentText().isEmpty())
+ ui->comboBox_EmergeMap->setCurrentText(connection->map_name);
+ } else {
+ // We allow any unknown direction names here. They'll be editable from the list menu.
+ createConnectionItem(connection);
}
- createConnectionItem(connection);
}
- if (!connection_items.empty()) {
- onConnectionItemSelected(connection_items.first());
- }
-
- maskNonVisibleConnectionTiles();
+ if (!connection_items.empty())
+ setSelectedConnection(connection_items.first());
}
void Editor::createConnectionItem(MapConnection* connection) {
- Map *connected_map = project->getMap(connection->map_name);
- if (!connected_map) {
+ if (!connection)
return;
- }
-
- QPixmap pixmap = connected_map->renderConnection(*connection, map->layout);
- QPoint pos = calculateConnectionPosition(connection, pixmap);
-
+ QPixmap pixmap = getConnectionPixmap(*connection);
+ QPoint pos = calculateConnectionPosition(*connection, pixmap);
ConnectionPixmapItem *item = new ConnectionPixmapItem(pixmap, connection, pos.x(), pos.y(), map->getWidth(), map->getHeight());
item->setX(pos.x());
item->setY(pos.y());
- item->setZValue(-1);
+ item->render();
scene->addItem(item);
- connect(item, &ConnectionPixmapItem::connectionItemSelected, this, &Editor::onConnectionItemSelected);
+ connect(item, &ConnectionPixmapItem::selectionChanged, [this, item](bool selected) {
+ if (selected) setSelectedConnection(item);
+ });
connect(item, &ConnectionPixmapItem::connectionItemDoubleClicked, [this, item] {
emit this->connectionItemDoubleClicked(item->connection->map_name, map->name);
});
connection_items.append(item);
+ addConnectionToList(item);
}
// Hides connected map tiles that cannot be seen from the current map (beyond BORDER_DISTANCE).
@@ -1891,14 +1857,12 @@ void Editor::updateMapBorder() {
}
void Editor::updateMapConnections() {
- for (int i = 0; i < connection_items.size(); i++) {
- Map *connected_map = project->getMap(connection_items[i]->connection->map_name);
- if (!connected_map)
+ for (auto item : connection_items) {
+ if (!item->connection)
continue;
-
- QPixmap pixmap = connected_map->renderConnection(*(connection_items[i]->connection), map->layout);
- connection_items[i]->basePixmap = pixmap;
- connection_items[i]->setPixmap(pixmap);
+ QPixmap pixmap = getConnectionPixmap(*item->connection);
+ item->basePixmap = pixmap;
+ item->setPixmap(pixmap);
}
maskNonVisibleConnectionTiles();
@@ -1992,7 +1956,7 @@ void Editor::updateBorderVisibility() {
item->setVisible(visible);
item->setEditable(editingConnections);
item->setEnabled(visible);
- item->updateHighlight(item == selected_connection_item);
+ item->render();
}
}
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 38af29d2..19377a49 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -736,6 +736,13 @@ void MainWindow::on_action_Reload_Project_triggered() {
// setMap, but with a visible error message in case of failure.
// Use when the user is specifically requesting a map to open.
bool MainWindow::userSetMap(QString map_name, bool scrollTreeView) {
+ if (map_name == DYNAMIC_MAP_NAME) {
+ QMessageBox msgBox(this);
+ QString errorMsg = QString("The map '%1' can't be opened, it's a placeholder to indicate the specified map will be set programmatically.").arg(map_name);
+ msgBox.critical(nullptr, "Error Opening Map", errorMsg);
+ return false;
+ }
+
if (!setMap(map_name, scrollTreeView)) {
QMessageBox msgBox(this);
QString errorMsg = QString("There was an error opening map %1. Please see %2 for full error details.\n\n%3")
@@ -750,7 +757,7 @@ bool MainWindow::userSetMap(QString map_name, bool scrollTreeView) {
bool MainWindow::setMap(QString map_name, bool scrollTreeView) {
logInfo(QString("Setting map to '%1'").arg(map_name));
- if (map_name.isEmpty()) {
+ if (map_name.isEmpty() || map_name == DYNAMIC_MAP_NAME) {
return false;
}
@@ -828,10 +835,6 @@ void MainWindow::refreshMapScene()
}
void MainWindow::openWarpMap(QString map_name, int event_id, Event::Group event_group) {
- // Can't warp to dynamic maps
- if (map_name == DYNAMIC_MAP_NAME)
- return;
-
// Ensure valid destination map name.
if (!editor->project->mapNames.contains(map_name)) {
logError(QString("Invalid map name '%1'").arg(map_name));
@@ -1846,6 +1849,8 @@ void MainWindow::on_mainTabBar_tabBarClicked(int index)
clickToolButtonFromEditMode(editor->obj_edit_mode);
} else if (index == MainTab::Connections) {
editor->setEditingConnections();
+ // Stop the Dive/Emerge combo boxes from getting the initial focus
+ ui->graphicsView_Map->setFocus();
}
if (index != MainTab::WildPokemon) {
if (editor->project && editor->project->wildEncountersLoaded)
@@ -2577,13 +2582,13 @@ void MainWindow::on_pushButton_ConfigureEncountersJSON_clicked() {
void MainWindow::on_button_OpenDiveMap_clicked() {
const QString mapName = ui->comboBox_DiveMap->currentText();
- if (mapName != DYNAMIC_MAP_NAME && editor->project->mapNames.contains(mapName))
+ if (editor->project->mapNames.contains(mapName))
userSetMap(mapName, true);
}
void MainWindow::on_button_OpenEmergeMap_clicked() {
const QString mapName = ui->comboBox_EmergeMap->currentText();
- if (mapName != DYNAMIC_MAP_NAME && editor->project->mapNames.contains(mapName))
+ if (editor->project->mapNames.contains(mapName))
userSetMap(mapName, true);
}
diff --git a/src/project.cpp b/src/project.cpp
index c6550c6a..06382168 100644
--- a/src/project.cpp
+++ b/src/project.cpp
@@ -117,6 +117,9 @@ void Project::clearTilesetCache() {
}
Map* Project::loadMap(QString map_name) {
+ if (map_name == DYNAMIC_MAP_NAME)
+ return nullptr;
+
Map *map;
if (mapCache.contains(map_name)) {
map = mapCache.value(map_name);
diff --git a/src/ui/connectionpixmapitem.cpp b/src/ui/connectionpixmapitem.cpp
index 060f084f..1b7743f9 100644
--- a/src/ui/connectionpixmapitem.cpp
+++ b/src/ui/connectionpixmapitem.cpp
@@ -2,15 +2,28 @@
#include
-void ConnectionPixmapItem::render(qreal opacity) {
- QPixmap newPixmap = this->basePixmap.copy(0, 0, this->basePixmap.width(), this->basePixmap.height());
- if (opacity < 1) {
- QPainter painter(&newPixmap);
- int alpha = static_cast(255 * (1 - opacity));
- painter.fillRect(0, 0, newPixmap.width(), newPixmap.height(), QColor(0, 0, 0, alpha));
- painter.end();
+void ConnectionPixmapItem::render() {
+ QPixmap pixmap = this->basePixmap.copy(0, 0, this->basePixmap.width(), this->basePixmap.height());
+ this->setZValue(-1);
+
+ // When editing is inactive the current selection is ignored, all connections should appear normal.
+ if (this->getEditable()) {
+ if (this->selected) {
+ // Draw highlight
+ QPainter painter(&pixmap);
+ painter.setPen(QColor(255, 0, 255));
+ painter.drawRect(0, 0, pixmap.width() - 1, pixmap.height() - 1);
+ painter.end();
+ } else {
+ // Darken the image
+ this->setZValue(-2);
+ QPainter painter(&pixmap);
+ int alpha = static_cast(255 * 0.25);
+ painter.fillRect(0, 0, pixmap.width(), pixmap.height(), QColor(0, 0, 0, alpha));
+ painter.end();
+ }
}
- this->setPixmap(newPixmap);
+ this->setPixmap(pixmap);
}
QVariant ConnectionPixmapItem::itemChange(GraphicsItemChange change, const QVariant &value)
@@ -20,7 +33,7 @@ QVariant ConnectionPixmapItem::itemChange(GraphicsItemChange change, const QVari
qreal x, y;
int newOffset = this->initialOffset;
- if (this->connection->direction == "up" || this->connection->direction == "down") {
+ if (MapConnection::isVertical(this->connection->direction)) {
x = round(newPos.x() / 16) * 16;
newOffset += (x - initialX) / 16;
x = newOffset * 16;
@@ -29,7 +42,7 @@ QVariant ConnectionPixmapItem::itemChange(GraphicsItemChange change, const QVari
x = this->initialX;
}
- if (this->connection->direction == "right" || this->connection->direction == "left") {
+ if (MapConnection::isHorizontal(this->connection->direction)) {
y = round(newPos.y() / 16) * 16;
newOffset += (y - this->initialY) / 16;
y = newOffset * 16;
@@ -56,41 +69,18 @@ bool ConnectionPixmapItem::getEditable() {
return (this->flags() & ItemIsMovable) != 0;
}
-// TODO: Consider whether it still makes sense to highlight the "current" connection (given you can edit them at any point now)
-void ConnectionPixmapItem::updateHighlight(bool selected) {
- const int normalZ = -1;
- const qreal normalOpacity = 1.0;
-
- // When editing is inactive the current selection is ignored, all connections should appear normal.
- if (!this->getEditable()) {
- this->setZValue(normalZ);
- this->render(normalOpacity);
+void ConnectionPixmapItem::setSelected(bool selected) {
+ if (this->selected == selected)
return;
- }
-
- this->setZValue(selected ? normalZ : -2);
- this->render(selected ? normalOpacity : 0.75);
-
- if (selected) {
- // Draw highlight
- QPixmap pixmap = this->pixmap();
- QPainter painter(&pixmap);
- painter.setPen(QColor(255, 0, 255));
- painter.drawRect(0, 0, pixmap.width() - 1, pixmap.height() - 1);
- painter.end();
- this->setPixmap(pixmap);
- }
-
- // Let the list UI know if the selection highlight changes so it can update accordingly
- if (this->highlighted != selected)
- emit highlightChanged(selected);
- this->highlighted = selected;
+ this->selected = selected;
+ this->render();
+ emit selectionChanged(selected);
}
void ConnectionPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *) {
if (!this->getEditable())
return;
- emit connectionItemSelected(this);
+ this->setSelected(true);
}
void ConnectionPixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) {
diff --git a/src/ui/connectionslistitem.cpp b/src/ui/connectionslistitem.cpp
index f40ae57f..cf6e3020 100644
--- a/src/ui/connectionslistitem.cpp
+++ b/src/ui/connectionslistitem.cpp
@@ -1,8 +1,6 @@
#include "connectionslistitem.h"
#include "ui_connectionslistitem.h"
-static const QStringList directions = {"up", "down", "left", "right"};
-
ConnectionsListItem::ConnectionsListItem(QWidget *parent, MapConnection * connection, const QStringList &mapNames) :
QFrame(parent),
ui(new Ui::ConnectionsListItem)
@@ -15,7 +13,7 @@ ConnectionsListItem::ConnectionsListItem(QWidget *parent, MapConnection * connec
ui->comboBox_Direction->setEditable(false);
ui->comboBox_Direction->setMinimumContentsLength(0);
- ui->comboBox_Direction->addItems(directions);
+ ui->comboBox_Direction->addItems(MapConnection::cardinalDirections);
ui->comboBox_Map->setMinimumContentsLength(6);
ui->comboBox_Map->addItems(mapNames);
diff --git a/src/ui/noscrollcombobox.cpp b/src/ui/noscrollcombobox.cpp
index ee778df5..fcb662c7 100644
--- a/src/ui/noscrollcombobox.cpp
+++ b/src/ui/noscrollcombobox.cpp
@@ -1,6 +1,7 @@
#include "noscrollcombobox.h"
#include
+#include
NoScrollComboBox::NoScrollComboBox(QWidget *parent)
: QComboBox(parent)
@@ -61,3 +62,8 @@ void NoScrollComboBox::setHexItem(uint32_t value)
{
this->setItem(this->findData(value), "0x" + QString::number(value, 16).toUpper());
}
+
+void NoScrollComboBox::setClearButtonEnabled(bool enabled) {
+ if (this->lineEdit())
+ this->lineEdit()->setClearButtonEnabled(enabled);
+}