Performance & bug clean up

This commit is contained in:
GriffinR 2024-07-12 14:05:37 -04:00
parent 1e09d08c9c
commit 96b5fb1617
15 changed files with 214 additions and 256 deletions

View file

@ -1715,7 +1715,7 @@
<x>0</x>
<y>0</y>
<width>100</width>
<height>16</height>
<height>30</height>
</rect>
</property>
<property name="sizePolicy">
@ -1809,7 +1809,7 @@
<x>0</x>
<y>0</y>
<width>100</width>
<height>16</height>
<height>30</height>
</rect>
</property>
<property name="sizePolicy">
@ -1903,7 +1903,7 @@
<x>0</x>
<y>0</y>
<width>100</width>
<height>16</height>
<height>30</height>
</rect>
</property>
<property name="sizePolicy">
@ -2003,7 +2003,7 @@
<x>0</x>
<y>0</y>
<width>100</width>
<height>16</height>
<height>30</height>
</rect>
</property>
<property name="sizePolicy">
@ -2097,7 +2097,7 @@
<x>0</x>
<y>0</y>
<width>100</width>
<height>16</height>
<height>30</height>
</rect>
</property>
<property name="sizePolicy">
@ -2596,6 +2596,9 @@
<property name="editable">
<bool>true</bool>
</property>
<property name="clearButtonEnabled" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="4">
@ -2667,6 +2670,9 @@
<property name="editable">
<bool>true</bool>
</property>
<property name="clearButtonEnabled" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
@ -2757,8 +2763,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>365</width>
<height>658</height>
<width>100</width>
<height>30</height>
</rect>
</property>
<layout class="QVBoxLayout" name="layout_ConnectionsList">

View file

@ -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);

View file

@ -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 {

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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 \

View file

@ -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));

View file

@ -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<QString, QString> 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);
}

View file

@ -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<ConnectionsListItem*>())
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<QString, int> directionCounts = QMap<QString, int>({{"up", 0}, {"right", 0}, {"down", 0}, {"left", 0}});
QMap<QString, int> 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<QString, QString> 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();
}
}

View file

@ -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);
}

View file

@ -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);

View file

@ -2,15 +2,28 @@
#include <math.h>
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<int>(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<int>(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 *) {

View file

@ -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);

View file

@ -1,6 +1,7 @@
#include "noscrollcombobox.h"
#include <QCompleter>
#include <QLineEdit>
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);
}