Reimplement connection mirroring
This commit is contained in:
parent
f1cfc3c78e
commit
1e09d08c9c
12 changed files with 405 additions and 251 deletions
|
@ -128,7 +128,6 @@ private:
|
|||
void setNewBorderDimensionsBlockdata(int newWidth, int newHeight);
|
||||
|
||||
signals:
|
||||
void mapChanged(Map *map);
|
||||
void modified();
|
||||
void mapDimensionsChanged(const QSize &size);
|
||||
void mapNeedsRedrawing();
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include <QString>
|
||||
#include <QHash>
|
||||
|
||||
class Map;
|
||||
|
||||
class MapConnection {
|
||||
public:
|
||||
QString direction;
|
||||
|
@ -12,12 +14,15 @@ public:
|
|||
QString map_name;
|
||||
};
|
||||
|
||||
inline bool operator==(const MapConnection &c1, const MapConnection &c2) {
|
||||
return c1.map_name == c2.map_name;
|
||||
}
|
||||
struct MapConnectionMirror {
|
||||
MapConnection * connection = nullptr;
|
||||
Map * map = nullptr;
|
||||
};
|
||||
|
||||
inline uint qHash(const MapConnection &key) {
|
||||
return qHash(key.map_name);
|
||||
inline bool operator==(const MapConnection &c1, const MapConnection &c2) {
|
||||
return c1.direction == c2.direction &&
|
||||
c1.offset == c2.offset &&
|
||||
c1.map_name == c2.map_name;
|
||||
}
|
||||
|
||||
#endif // MAPCONNECTION_H
|
||||
|
|
|
@ -75,9 +75,10 @@ public:
|
|||
void setEditingConnections();
|
||||
void setMapEditingButtonsEnabled(bool enabled);
|
||||
void setConnectionsVisibility(bool visible);
|
||||
void updateConnectionOffset(int offset);
|
||||
void addNewConnection();
|
||||
void removeConnection(ConnectionPixmapItem* connectionItem);
|
||||
void addConnection(Map* map, MapConnection* connection);
|
||||
void removeConnection(Map* map, MapConnection* connection);
|
||||
void removeConnectionItem(ConnectionPixmapItem* connectionItem, bool removeMirror = true);
|
||||
void removeSelectedConnection();
|
||||
void addNewWildMonGroup(QWidget *window);
|
||||
void deleteWildMonGroup();
|
||||
|
@ -168,17 +169,16 @@ private:
|
|||
|
||||
void updateBorderVisibility();
|
||||
QPoint calculateConnectionPosition(const MapConnection *connection, const QPixmap &pixmap);
|
||||
void redrawConnection(ConnectionPixmapItem* connectionItem);
|
||||
void updateConnectionItem(ConnectionPixmapItem* connectionItem);
|
||||
void updateConnectionItemPos(ConnectionPixmapItem* connectionItem);
|
||||
void createConnectionItem(MapConnection* connection);
|
||||
void populateConnectionsList();
|
||||
void addConnectionToList(ConnectionPixmapItem* connection);
|
||||
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);
|
||||
bool shouldMirrorConnection(const MapConnection &source);
|
||||
MapConnectionMirror getMirroredConnection(const MapConnection&);
|
||||
void addMirroredConnection(const MapConnection&);
|
||||
void removeMirroredConnection(const MapConnection&);
|
||||
void updateEncounterFields(EncounterFields newFields);
|
||||
QString getMovementPermissionText(uint16_t collision, uint16_t elevation);
|
||||
QString getMetatileDisplayMessage(uint16_t metatileId);
|
||||
|
@ -194,7 +194,9 @@ private slots:
|
|||
void setStraightPathCursorMode(QGraphicsSceneMouseEvent *event);
|
||||
void mouseEvent_map(QGraphicsSceneMouseEvent *event, MapPixmapItem *item);
|
||||
void mouseEvent_collision(QGraphicsSceneMouseEvent *event, CollisionPixmapItem *item);
|
||||
void onConnectionMoved(MapConnection*);
|
||||
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 onHoveredMovementPermissionChanged(uint16_t, uint16_t);
|
||||
void onHoveredMovementPermissionCleared();
|
||||
|
@ -215,7 +217,7 @@ signals:
|
|||
void warpEventDoubleClicked(QString, int, Event::Group);
|
||||
void currentMetatilesSelectionChanged();
|
||||
void mapRulerStatusChanged(const QString &);
|
||||
void editedMapData();
|
||||
void editedMapData(Map*);
|
||||
void tilesetUpdated(QString);
|
||||
};
|
||||
|
||||
|
|
|
@ -178,7 +178,6 @@ private slots:
|
|||
void paste();
|
||||
|
||||
void onConnectionItemDoubleClicked(QString, QString);
|
||||
void onMapChanged(Map *map);
|
||||
void onMapNeedsRedrawing();
|
||||
void onTilesetsSaved(QString, QString);
|
||||
void onWildMonDataChanged();
|
||||
|
@ -366,6 +365,7 @@ private:
|
|||
void clickToolButtonFromEditMode(QString editMode);
|
||||
|
||||
void markMapEdited();
|
||||
void markMapEdited(Map*);
|
||||
void showWindowTitle();
|
||||
|
||||
void initWindow();
|
||||
|
|
|
@ -44,7 +44,7 @@ protected:
|
|||
signals:
|
||||
void connectionItemSelected(ConnectionPixmapItem* connectionItem);
|
||||
void connectionItemDoubleClicked(ConnectionPixmapItem* connectionItem);
|
||||
void connectionMoved(MapConnection*);
|
||||
void connectionMoved(MapConnection *, int newOffset);
|
||||
void highlightChanged(bool highlighted);
|
||||
};
|
||||
|
||||
|
|
|
@ -19,15 +19,16 @@ class ConnectionsListItem : public QFrame
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConnectionsListItem(QWidget *parent, MapConnection * connection, const QStringList &mapNames);
|
||||
explicit ConnectionsListItem(QWidget *parent, MapConnection *connection, const QStringList &mapNames);
|
||||
~ConnectionsListItem();
|
||||
|
||||
void updateUI();
|
||||
void setSelected(bool selected);
|
||||
|
||||
MapConnection * connection;
|
||||
|
||||
private:
|
||||
Ui::ConnectionsListItem *ui;
|
||||
MapConnection * const connection;
|
||||
bool isSelected = false;
|
||||
|
||||
protected:
|
||||
|
@ -35,10 +36,12 @@ protected:
|
|||
void mouseDoubleClickEvent(QMouseEvent *);
|
||||
|
||||
signals:
|
||||
void edited();
|
||||
void deleteRequested();
|
||||
void editedOffset(MapConnection *connection, int newOffset);
|
||||
void editedDirection(MapConnection *connection, const QString &direction);
|
||||
void editedMapName(MapConnection *connection, const QString &mapName);
|
||||
void removed();
|
||||
void selected();
|
||||
void doubleClicked();
|
||||
void doubleClicked(const QString &mapName);
|
||||
|
||||
private slots:
|
||||
void on_comboBox_Direction_currentTextChanged(const QString &direction);
|
||||
|
|
|
@ -304,8 +304,8 @@ void Map::setDimensions(int newWidth, int newHeight, bool setNewBlockdata, bool
|
|||
Scripting::cb_MapResized(oldWidth, oldHeight, newWidth, newHeight);
|
||||
}
|
||||
|
||||
emit mapChanged(this);
|
||||
emit mapDimensionsChanged(QSize(getWidth(), getHeight()));
|
||||
modify();
|
||||
}
|
||||
|
||||
void Map::setBorderDimensions(int newWidth, int newHeight, bool setNewBlockdata, bool enableScriptCallback) {
|
||||
|
@ -322,7 +322,7 @@ void Map::setBorderDimensions(int newWidth, int newHeight, bool setNewBlockdata,
|
|||
Scripting::cb_BorderResized(oldWidth, oldHeight, newWidth, newHeight);
|
||||
}
|
||||
|
||||
emit mapChanged(this);
|
||||
modify();
|
||||
}
|
||||
|
||||
void Map::openScript(QString label) {
|
||||
|
|
43
src/core/mapconnection.cpp
Normal file
43
src/core/mapconnection.cpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
#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);
|
||||
}
|
||||
|
||||
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) {
|
||||
static const QMap<QString, QString> oppositeDirections = {
|
||||
{"up", "down"}, {"down", "up"},
|
||||
{"right", "left"}, {"left", "right"},
|
||||
{"dive", "emerge"}, {"emerge", "dive"}
|
||||
};
|
||||
return oppositeDirections.value(direction);
|
||||
}
|
||||
|
||||
static MapConnection* MapConnection::getMirror(const MapConnection*, const Map*) {
|
||||
|
||||
}
|
||||
|
||||
static MapConnection* MapConnection::newMirror(const MapConnection*) {
|
||||
|
||||
}*/
|
490
src/editor.cpp
490
src/editor.cpp
|
@ -726,14 +726,14 @@ 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_DiveMap->addItems(project->mapNames);
|
||||
ui->comboBox_DiveMap->setCurrentText("");
|
||||
ui->comboBox_DiveMap->lineEdit()->setClearButtonEnabled(true);
|
||||
|
||||
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) {
|
||||
|
@ -745,24 +745,22 @@ void Editor::populateConnectionsList() {
|
|||
}
|
||||
|
||||
// Clear any existing connections in list
|
||||
for (auto w : ui->scrollAreaContents_ConnectionsList->findChildren<ConnectionsListItem*>())
|
||||
w->deleteLater();
|
||||
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
|
||||
|
||||
// Connect the pixmap item to the list item
|
||||
connect(connectionItem, &ConnectionPixmapItem::connectionMoved, listItem, &ConnectionsListItem::updateUI);
|
||||
// Sync the selection highlight between the list UI and the graphical map connection
|
||||
connect(connectionItem, &ConnectionPixmapItem::highlightChanged, listItem, &ConnectionsListItem::setSelected);
|
||||
connect(connectionItem, &ConnectionPixmapItem::destroyed, listItem, &ConnectionsListItem::deleteLater);
|
||||
if (connectionItem == selected_connection_item)
|
||||
listItem->setSelected(true);
|
||||
|
||||
connect(listItem, &ConnectionsListItem::selected, [this, connectionItem] {
|
||||
// When the list item is selected, select the pixmap too
|
||||
if (connectionItem == selected_connection_item) {
|
||||
|
@ -774,32 +772,113 @@ void Editor::addConnectionToList(ConnectionPixmapItem * connectionItem) {
|
|||
selected_connection_item = connectionItem;
|
||||
selected_connection_item->updateHighlight(true);
|
||||
});
|
||||
connect(listItem, &ConnectionsListItem::edited, [this, connectionItem] {
|
||||
// When the list item is edited update the pixmap
|
||||
// TODO: This is probably slower than necessary (we don't need a full redraw if we're just moving it)
|
||||
// TODO: Handle mirroring
|
||||
redrawConnection(connectionItem);
|
||||
emit editedMapData();
|
||||
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) {
|
||||
setConnectionOffset(connection, offset);
|
||||
listItem->updateUI();
|
||||
});
|
||||
connect(listItem, &ConnectionsListItem::deleteRequested, [this, connectionItem] {
|
||||
connect (listItem, &ConnectionsListItem::editedOffset, [this, connectionItem](MapConnection* connection, int offset) {
|
||||
setConnectionOffset(connection, offset);
|
||||
updateConnectionItemPos(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) {
|
||||
setConnectionDirection(connection, direction);
|
||||
updateConnectionItem(connectionItem); // TODO: Simplify?
|
||||
});
|
||||
connect(listItem, &ConnectionsListItem::editedMapName, [this, connectionItem](MapConnection* connection, QString mapName) {
|
||||
setConnectionMap(connection, mapName);
|
||||
updateConnectionItem(connectionItem);
|
||||
});
|
||||
|
||||
// Sync deleting the map connection
|
||||
connect(connectionItem, &ConnectionPixmapItem::destroyed, listItem, &ConnectionsListItem::deleteLater);
|
||||
connect(listItem, &ConnectionsListItem::removed, [this, connectionItem] {
|
||||
// 'Remove' button has been clicked. Delete the pixmap.
|
||||
// The list item will be deleted via the earlier connection to the pixmap's 'destroyed' signal.
|
||||
removeConnection(connectionItem);
|
||||
// The list item will be deleted via the above connection to the pixmap's 'destroyed' signal.
|
||||
removeConnectionItem(connectionItem);
|
||||
});
|
||||
connect(listItem, &ConnectionsListItem::doubleClicked, [this, connectionItem] {
|
||||
// Double clicking the list item opens the connected map
|
||||
emit connectionItemDoubleClicked(connectionItem->connection->map_name, map->name);
|
||||
|
||||
// Double clicking the list item opens the connected map
|
||||
connect(listItem, &ConnectionsListItem::doubleClicked, [this](QString connectedMapName) {
|
||||
emit connectionItemDoubleClicked(connectedMapName, map->name);
|
||||
});
|
||||
}
|
||||
|
||||
void Editor::removeConnection(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}});
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
MapConnection* newConnection = new MapConnection;
|
||||
newConnection->direction = minDirection;
|
||||
newConnection->offset = 0;
|
||||
newConnection->map_name = defaultMapName;
|
||||
addConnection(map, newConnection);
|
||||
onConnectionItemSelected(connection_items.last());
|
||||
addMirroredConnection(*newConnection);
|
||||
}
|
||||
|
||||
void Editor::addConnection(Map* map, MapConnection * connection) {
|
||||
map->connections.append(connection);
|
||||
if (map == this->map) {
|
||||
// Adding a connection to the current map, we need to display it visually.
|
||||
// Note that for the Dive/Emerge combo boxes this is normally redundant
|
||||
// as the user can only create these by having already set the text,
|
||||
// *except* in the case where they're connecting a map to itself.
|
||||
if (connection->direction == "dive") {
|
||||
const QSignalBlocker blocker(ui->comboBox_DiveMap);
|
||||
ui->comboBox_DiveMap->setCurrentText(connection->map_name);
|
||||
} else if (connection->direction == "emerge") {
|
||||
const QSignalBlocker blocker(ui->comboBox_EmergeMap);
|
||||
ui->comboBox_EmergeMap->setCurrentText(connection->map_name);
|
||||
} else {
|
||||
createConnectionItem(connection);
|
||||
addConnectionToList(connection_items.last());
|
||||
}
|
||||
}
|
||||
emit editedMapData(map);
|
||||
}
|
||||
|
||||
void Editor::removeConnectionItem(ConnectionPixmapItem* connectionItem, bool removeMirror) {
|
||||
if (!connectionItem)
|
||||
return;
|
||||
|
||||
map->connections.removeOne(connectionItem->connection);
|
||||
connection_items.removeOne(connectionItem);
|
||||
//removeMirroredConnection(connectionItem->connection); // TODO
|
||||
if (connectionItem->connection) {
|
||||
if (removeMirror) {
|
||||
// If a map is connected to itself and we delete the connection then this function
|
||||
// will be called twice, once for the target of the delete and once for its mirror.
|
||||
// We only want to try deleting the mirror once, on the first call (because the mirror
|
||||
// of the mirror is the original target again, and we already deleted it).
|
||||
removeMirroredConnection(*connectionItem->connection);
|
||||
}
|
||||
removeConnection(map, connectionItem->connection);
|
||||
}
|
||||
|
||||
connection_items.removeOne(connectionItem);
|
||||
if (connectionItem->scene())
|
||||
connectionItem->scene()->removeItem(connectionItem);
|
||||
|
||||
|
@ -808,14 +887,136 @@ void Editor::removeConnection(ConnectionPixmapItem* connectionItem) {
|
|||
if (!connection_items.isEmpty())
|
||||
onConnectionItemSelected(connection_items.first());
|
||||
}
|
||||
|
||||
delete connectionItem->connection;
|
||||
delete connectionItem;
|
||||
emit editedMapData();
|
||||
}
|
||||
|
||||
void Editor::removeConnection(Map* map, MapConnection* connection) {
|
||||
if (!map)
|
||||
return;
|
||||
map->connections.removeOne(connection);
|
||||
delete connection;
|
||||
emit editedMapData(map);
|
||||
}
|
||||
|
||||
void Editor::removeSelectedConnection() {
|
||||
removeConnection(selected_connection_item);
|
||||
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))
|
||||
return mirror;
|
||||
|
||||
// Note: It's possible (and ok) for mirror.map == this->map
|
||||
mirror.map = project->getMap(source.map_name);
|
||||
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.
|
||||
for (auto connection : mirror.map->connections) {
|
||||
if (*connection == target) {
|
||||
mirror.connection = connection;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return mirror;
|
||||
}
|
||||
|
||||
void Editor::addMirroredConnection(const MapConnection &source) {
|
||||
MapConnectionMirror mirror = getMirroredConnection(source);
|
||||
if (!mirror.map)
|
||||
return;
|
||||
|
||||
mirror.connection = new MapConnection;
|
||||
mirror.connection->direction = oppositeDirections.value(source.direction);
|
||||
mirror.connection->map_name = map->name;
|
||||
mirror.connection->offset = -source.offset;
|
||||
|
||||
addConnection(mirror.map, mirror.connection);
|
||||
}
|
||||
|
||||
void Editor::removeMirroredConnection(const MapConnection &source) {
|
||||
MapConnectionMirror mirror = getMirroredConnection(source);
|
||||
if (!mirror.map || !mirror.connection)
|
||||
return;
|
||||
|
||||
if (map == mirror.map) {
|
||||
// The connection to delete is displayed on the currently-opened map, we need to delete it visually as well.
|
||||
if (source.direction == "dive") {
|
||||
const QSignalBlocker blocker(ui->comboBox_DiveMap);
|
||||
ui->comboBox_DiveMap->setCurrentText("");
|
||||
} else if (source.direction == "emerge") {
|
||||
const QSignalBlocker blocker(ui->comboBox_EmergeMap);
|
||||
ui->comboBox_EmergeMap->setCurrentText("");
|
||||
} else {
|
||||
// Find and delete the matching connection graphics
|
||||
for (auto item :connection_items) {
|
||||
if (item->connection == mirror.connection) {
|
||||
removeConnectionItem(item, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
removeConnection(mirror.map, mirror.connection);
|
||||
}
|
||||
|
||||
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)) {
|
||||
logError(QString("Invalid %1 connection map name: '%2'").arg(direction).arg(mapName));
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: How does the game handle having multiple Dive/Emerge maps. Should we support this?
|
||||
MapConnection* connection = nullptr;
|
||||
for (MapConnection* conn : map->connections) {
|
||||
if (conn->direction == direction) {
|
||||
connection = conn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
if (connection) {
|
||||
removeMirroredConnection(*connection);
|
||||
removeConnection(map, connection);
|
||||
}
|
||||
if (!mapName.isEmpty() && mapName != DYNAMIC_MAP_NAME) {
|
||||
connection = new MapConnection;
|
||||
connection->direction = direction;
|
||||
connection->offset = 0;
|
||||
connection->map_name = mapName;
|
||||
addConnection(map, connection);
|
||||
addMirroredConnection(*connection);
|
||||
}
|
||||
}
|
||||
|
||||
QPoint Editor::calculateConnectionPosition(const MapConnection *connection, const QPixmap &pixmap) {
|
||||
|
@ -837,7 +1038,7 @@ QPoint Editor::calculateConnectionPosition(const MapConnection *connection, cons
|
|||
return QPoint(x, y);
|
||||
}
|
||||
|
||||
void Editor::redrawConnection(ConnectionPixmapItem* connectionItem) {
|
||||
void Editor::updateConnectionItem(ConnectionPixmapItem* connectionItem) {
|
||||
if (!connectionItem || !connectionItem->connection)
|
||||
return;
|
||||
|
||||
|
@ -870,36 +1071,80 @@ void Editor::redrawConnection(ConnectionPixmapItem* connectionItem) {
|
|||
connectionItem->setZValue(-1);
|
||||
connectionItem->blockSignals(false);
|
||||
|
||||
// TODO:
|
||||
//updateMirroredConnectionMap(selected_connection_item->connection, originalMapName);
|
||||
|
||||
maskNonVisibleConnectionTiles();
|
||||
}
|
||||
|
||||
// TODO: Generalize, maybe use in addConnectionToList connection instead of full render
|
||||
void Editor::updateConnectionOffset(int offset) {
|
||||
/*if (!selected_connection_item)
|
||||
void Editor::updateConnectionItemPos(ConnectionPixmapItem* connectionItem) {
|
||||
if (!connectionItem || !connectionItem->connection)
|
||||
return;
|
||||
|
||||
selected_connection_item->blockSignals(true);
|
||||
selected_connection_item->connection->offset = 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);
|
||||
MapConnection *connection = connectionItem->connection;
|
||||
connectionItem->blockSignals(true);
|
||||
if (connection->direction == "up" || connection->direction == "down") {
|
||||
connectionItem->setX(connectionItem->initialX + (connection->offset - connectionItem->initialOffset) * 16);
|
||||
} else if (connection->direction == "left" || connection->direction == "right") {
|
||||
connectionItem->setY(connectionItem->initialY + (connection->offset - connectionItem->initialOffset) * 16);
|
||||
}
|
||||
selected_connection_item->blockSignals(false);
|
||||
updateMirroredConnectionOffset(selected_connection_item->connection);
|
||||
maskNonVisibleConnectionTiles();*/
|
||||
connectionItem->blockSignals(false);
|
||||
maskNonVisibleConnectionTiles();
|
||||
}
|
||||
|
||||
void Editor::onConnectionMoved(MapConnection* connection) {
|
||||
// TODO:
|
||||
//updateMirroredConnectionOffset(connection);
|
||||
void Editor::setConnectionOffset(MapConnection *connection, int offset) {
|
||||
if (!connection || !map || connection->offset == offset)
|
||||
return;
|
||||
|
||||
MapConnectionMirror mirror = getMirroredConnection(*connection);
|
||||
if (mirror.connection && mirror.map) {
|
||||
mirror.connection->offset = -offset;
|
||||
if (mirror.map != map) {
|
||||
emit editedMapData(mirror.map);
|
||||
} else {
|
||||
// The mirror is displayed on the current map, update its graphics
|
||||
for (auto item :connection_items) {
|
||||
if (item->connection == mirror.connection) {
|
||||
updateConnectionItemPos(item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO: We should be signaling to the list item from the pixmap item, rather than searching for it.
|
||||
for (auto listItem : ui->scrollAreaContents_ConnectionsList->findChildren<ConnectionsListItem*>()) {
|
||||
if (listItem->connection == mirror.connection){
|
||||
listItem->updateUI();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: If there's no mirror but there should be we're not creating one
|
||||
|
||||
connection->offset = offset;
|
||||
emit editedMapData(map);
|
||||
|
||||
// TODO: This is likely the source of the visual masking bug while dragging (this happens after the move)
|
||||
maskNonVisibleConnectionTiles();
|
||||
emit editedMapData();
|
||||
}
|
||||
|
||||
void Editor::setConnectionMap(MapConnection *connection, const QString &mapName) {
|
||||
if (!connection || !map || connection->map_name == mapName)
|
||||
return;
|
||||
|
||||
removeMirroredConnection(*connection);
|
||||
connection->map_name = mapName;
|
||||
addMirroredConnection(*connection);
|
||||
|
||||
emit editedMapData(map);
|
||||
}
|
||||
|
||||
void Editor::setConnectionDirection(MapConnection *connection, const QString &direction) {
|
||||
if (!connection || !map || connection->direction == direction)
|
||||
return;
|
||||
|
||||
// TODO: Lazy
|
||||
removeMirroredConnection(*connection);
|
||||
connection->direction = direction;
|
||||
addMirroredConnection(*connection);
|
||||
|
||||
emit editedMapData(map);
|
||||
}
|
||||
|
||||
void Editor::onConnectionItemSelected(ConnectionPixmapItem* connectionItem) {
|
||||
|
@ -1579,7 +1824,6 @@ void Editor::createConnectionItem(MapConnection* connection) {
|
|||
item->setZValue(-1);
|
||||
scene->addItem(item);
|
||||
|
||||
connect(item, &ConnectionPixmapItem::connectionMoved, this, &Editor::onConnectionMoved);
|
||||
connect(item, &ConnectionPixmapItem::connectionItemSelected, this, &Editor::onConnectionItemSelected);
|
||||
connect(item, &ConnectionPixmapItem::connectionItemDoubleClicked, [this, item] {
|
||||
emit this->connectionItemDoubleClicked(item->connection->map_name, map->name);
|
||||
|
@ -1703,144 +1947,6 @@ void Editor::displayMapGrid() {
|
|||
connect(ui->checkBox_ToggleGrid, &QCheckBox::toggled, this, &Editor::onToggleGridClicked);
|
||||
}
|
||||
|
||||
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);
|
||||
addConnectionToList(connection_items.last());
|
||||
onConnectionItemSelected(connection_items.last());
|
||||
|
||||
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;
|
||||
Map* otherMap = project->getMap(originalMapName);
|
||||
if (!otherMap)
|
||||
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;
|
||||
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 = -connection->offset;
|
||||
}
|
||||
|
||||
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)) {
|
||||
logError(QString("Invalid %1 connection map name: '%2'").arg(direction).arg(mapName));
|
||||
return;
|
||||
}
|
||||
|
||||
MapConnection* connection = nullptr;
|
||||
for (MapConnection* conn : map->connections) {
|
||||
if (conn->direction == direction) {
|
||||
connection = conn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mapName.isEmpty() || mapName == DYNAMIC_MAP_NAME) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::updatePrimaryTileset(QString tilesetLabel, bool forceLoad)
|
||||
{
|
||||
if (map->layout->tileset_primary_label != tilesetLabel || forceLoad)
|
||||
|
@ -1893,7 +1999,7 @@ void Editor::updateBorderVisibility() {
|
|||
void Editor::updateCustomMapHeaderValues(QTableWidget *table)
|
||||
{
|
||||
map->customHeaders = CustomAttributesTable::getAttributes(table);
|
||||
emit editedMapData();
|
||||
emit editedMapData(map);
|
||||
}
|
||||
|
||||
Tileset* Editor::getCurrentMapPrimaryTileset()
|
||||
|
|
|
@ -310,7 +310,7 @@ void MainWindow::initEditor() {
|
|||
connect(this->editor, &Editor::currentMetatilesSelectionChanged, this, &MainWindow::currentMetatilesSelectionChanged);
|
||||
connect(this->editor, &Editor::wildMonDataChanged, this, &MainWindow::onWildMonDataChanged);
|
||||
connect(this->editor, &Editor::mapRulerStatusChanged, this, &MainWindow::onMapRulerStatusChanged);
|
||||
connect(this->editor, &Editor::editedMapData, this, &MainWindow::markMapEdited);
|
||||
connect(this->editor, &Editor::editedMapData, [this](Map* map) { this->markMapEdited(map); });
|
||||
connect(this->editor, &Editor::tilesetUpdated, this, &Scripting::cb_TilesetUpdated);
|
||||
connect(ui->toolButton_Open_Scripts, &QToolButton::pressed, this->editor, &Editor::openMapScripts);
|
||||
connect(ui->actionOpen_Project_in_Text_Editor, &QAction::triggered, this->editor, &Editor::openProjectInTextEditor);
|
||||
|
@ -413,10 +413,19 @@ void MainWindow::showWindowTitle() {
|
|||
}
|
||||
|
||||
void MainWindow::markMapEdited() {
|
||||
if (editor && editor->map) {
|
||||
editor->map->hasUnsavedDataChanges = true;
|
||||
if (editor) markMapEdited(editor->map);
|
||||
}
|
||||
|
||||
void MainWindow::markMapEdited(Map* map) {
|
||||
if (!map)
|
||||
return;
|
||||
map->hasUnsavedDataChanges = true;
|
||||
|
||||
// TODO: Only update the necessary list icon
|
||||
updateMapList();
|
||||
|
||||
if (editor && editor->map == map)
|
||||
showWindowTitle();
|
||||
}
|
||||
}
|
||||
|
||||
// Update the UI using information we've read from the user's project files.
|
||||
|
@ -769,7 +778,6 @@ bool MainWindow::setMap(QString map_name, bool scrollTreeView) {
|
|||
|
||||
showWindowTitle();
|
||||
|
||||
connect(editor->map, &Map::mapChanged, this, &MainWindow::onMapChanged);
|
||||
connect(editor->map, &Map::mapNeedsRedrawing, this, &MainWindow::onMapNeedsRedrawing);
|
||||
connect(editor->map, &Map::modified, [this](){ this->markMapEdited(); });
|
||||
|
||||
|
@ -2440,10 +2448,6 @@ void MainWindow::onConnectionItemDoubleClicked(QString mapName, QString fromMapN
|
|||
editor->setSelectedConnectionFromMap(fromMapName);
|
||||
}
|
||||
|
||||
void MainWindow::onMapChanged(Map *) {
|
||||
updateMapList();
|
||||
}
|
||||
|
||||
void MainWindow::onMapNeedsRedrawing() {
|
||||
redrawMapScene();
|
||||
}
|
||||
|
@ -2555,9 +2559,8 @@ void MainWindow::showExportMapImageWindow(ImageExporterMode mode) {
|
|||
|
||||
void MainWindow::on_pushButton_AddConnection_clicked()
|
||||
{
|
||||
// TODO: Bring up a prompt for information. Mark the current map *AND* the connected map as edited
|
||||
// TODO: Bring up a prompt for information?
|
||||
editor->addNewConnection();
|
||||
markMapEdited();
|
||||
}
|
||||
|
||||
void MainWindow::on_pushButton_NewWildMonGroup_clicked() {
|
||||
|
@ -2584,20 +2587,15 @@ void MainWindow::on_button_OpenEmergeMap_clicked() {
|
|||
userSetMap(mapName, true);
|
||||
}
|
||||
|
||||
// TODO: Mirror change to/from other maps
|
||||
void MainWindow::on_comboBox_DiveMap_currentTextChanged(const QString &mapName) {
|
||||
// Include empty names as an update (user is deleting the connection)
|
||||
if (mapName.isEmpty() || editor->project->mapNames.contains(mapName)) {
|
||||
if (mapName.isEmpty() || editor->project->mapNames.contains(mapName))
|
||||
editor->updateDiveMap(mapName);
|
||||
markMapEdited();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_comboBox_EmergeMap_currentTextChanged(const QString &mapName) {
|
||||
if (mapName.isEmpty() || editor->project->mapNames.contains(mapName)) {
|
||||
if (mapName.isEmpty() || editor->project->mapNames.contains(mapName))
|
||||
editor->updateEmergeMap(mapName);
|
||||
markMapEdited();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_comboBox_PrimaryTileset_currentTextChanged(const QString &tilesetLabel)
|
||||
|
|
|
@ -38,8 +38,8 @@ QVariant ConnectionPixmapItem::itemChange(GraphicsItemChange change, const QVari
|
|||
y = this->initialY;
|
||||
}
|
||||
|
||||
this->connection->offset = newOffset;
|
||||
emit connectionMoved(this->connection);
|
||||
if (this->connection->offset != newOffset)
|
||||
emit connectionMoved(this->connection, newOffset);
|
||||
return QPointF(x, y);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -5,8 +5,7 @@ static const QStringList directions = {"up", "down", "left", "right"};
|
|||
|
||||
ConnectionsListItem::ConnectionsListItem(QWidget *parent, MapConnection * connection, const QStringList &mapNames) :
|
||||
QFrame(parent),
|
||||
ui(new Ui::ConnectionsListItem),
|
||||
connection(connection)
|
||||
ui(new Ui::ConnectionsListItem)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
|
@ -24,6 +23,7 @@ ConnectionsListItem::ConnectionsListItem(QWidget *parent, MapConnection * connec
|
|||
ui->spinBox_Offset->setMinimum(INT_MIN);
|
||||
ui->spinBox_Offset->setMaximum(INT_MAX);
|
||||
|
||||
this->connection = connection;
|
||||
this->updateUI();
|
||||
}
|
||||
|
||||
|
@ -58,33 +58,31 @@ void ConnectionsListItem::mousePressEvent(QMouseEvent *) {
|
|||
}
|
||||
|
||||
void ConnectionsListItem::mouseDoubleClickEvent(QMouseEvent *) {
|
||||
emit doubleClicked();
|
||||
emit doubleClicked(this->connection->map_name);
|
||||
}
|
||||
|
||||
void ConnectionsListItem::on_comboBox_Direction_currentTextChanged(const QString &direction)
|
||||
{
|
||||
this->connection->direction = direction;
|
||||
this->setSelected(true);
|
||||
emit this->edited();
|
||||
if (this->connection->direction != direction)
|
||||
emit this->editedDirection(this->connection, direction);
|
||||
}
|
||||
|
||||
void ConnectionsListItem::on_comboBox_Map_currentTextChanged(const QString &mapName)
|
||||
{
|
||||
if (ui->comboBox_Map->findText(mapName) >= 0) {
|
||||
this->connection->map_name = mapName;
|
||||
this->setSelected(true);
|
||||
emit this->edited();
|
||||
}
|
||||
this->setSelected(true);
|
||||
if (ui->comboBox_Map->findText(mapName) >= 0 && this->connection->map_name != mapName)
|
||||
emit this->editedMapName(this->connection, mapName);
|
||||
}
|
||||
|
||||
void ConnectionsListItem::on_spinBox_Offset_valueChanged(int offset)
|
||||
{
|
||||
this->connection->offset = offset;
|
||||
this->setSelected(true);
|
||||
emit this->edited();
|
||||
if (this->connection->offset != offset)
|
||||
emit editedOffset(this->connection, offset);
|
||||
}
|
||||
|
||||
void ConnectionsListItem::on_button_Delete_clicked()
|
||||
{
|
||||
emit this->deleteRequested();
|
||||
emit this->removed();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue