Map connection edit history
This commit is contained in:
parent
0b800c1201
commit
cbd75dc20b
19 changed files with 691 additions and 240 deletions
|
@ -3,9 +3,11 @@
|
||||||
#define EDITCOMMANDS_H
|
#define EDITCOMMANDS_H
|
||||||
|
|
||||||
#include "blockdata.h"
|
#include "blockdata.h"
|
||||||
|
#include "mapconnection.h"
|
||||||
|
|
||||||
#include <QUndoCommand>
|
#include <QUndoCommand>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
#include <QPointer>
|
||||||
|
|
||||||
class MapPixmapItem;
|
class MapPixmapItem;
|
||||||
class Map;
|
class Map;
|
||||||
|
@ -31,6 +33,11 @@ enum CommandId {
|
||||||
ID_EventDelete,
|
ID_EventDelete,
|
||||||
ID_EventDuplicate,
|
ID_EventDuplicate,
|
||||||
ID_EventPaste,
|
ID_EventPaste,
|
||||||
|
ID_MapConnectionMove,
|
||||||
|
ID_MapConnectionChangeDirection,
|
||||||
|
ID_MapConnectionChangeMap,
|
||||||
|
ID_MapConnectionAdd,
|
||||||
|
ID_MapConnectionRemove,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IDMask_EventType_Object (1 << 8)
|
#define IDMask_EventType_Object (1 << 8)
|
||||||
|
@ -379,4 +386,113 @@ private:
|
||||||
int newBorderHeight;
|
int newBorderHeight;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Implements a command to commit Map Connectien move actions.
|
||||||
|
/// Actions are merged into one until the mouse is released when editing by click-and-drag,
|
||||||
|
/// or when the offset spin box loses focus when editing with the list UI.
|
||||||
|
class MapConnectionMove : public QUndoCommand {
|
||||||
|
public:
|
||||||
|
MapConnectionMove(MapConnection *connection, int newOffset, unsigned actionId,
|
||||||
|
QUndoCommand *parent = nullptr);
|
||||||
|
|
||||||
|
void undo() override;
|
||||||
|
void redo() override;
|
||||||
|
|
||||||
|
bool mergeWith(const QUndoCommand *command) override;
|
||||||
|
int id() const override { return CommandId::ID_MapConnectionMove; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
MapConnection *connection;
|
||||||
|
int newOffset;
|
||||||
|
int oldOffset;
|
||||||
|
bool mirrored;
|
||||||
|
unsigned actionId;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Implements a command to commit changes to a Map Connectien's 'direction' field.
|
||||||
|
class MapConnectionChangeDirection : public QUndoCommand {
|
||||||
|
public:
|
||||||
|
MapConnectionChangeDirection(MapConnection *connection, QString newDirection,
|
||||||
|
QUndoCommand *parent = nullptr);
|
||||||
|
|
||||||
|
void undo() override;
|
||||||
|
void redo() override;
|
||||||
|
|
||||||
|
int id() const override { return CommandId::ID_MapConnectionChangeDirection; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPointer<MapConnection> connection;
|
||||||
|
QString newDirection;
|
||||||
|
QString oldDirection;
|
||||||
|
int oldOffset;
|
||||||
|
int newOffset;
|
||||||
|
bool mirrored;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Implements a command to commit changes to a Map Connectien's 'map' field.
|
||||||
|
class MapConnectionChangeMap : public QUndoCommand {
|
||||||
|
public:
|
||||||
|
MapConnectionChangeMap(MapConnection *connection, QString newMapName,
|
||||||
|
QUndoCommand *parent = nullptr);
|
||||||
|
|
||||||
|
void undo() override;
|
||||||
|
void redo() override;
|
||||||
|
|
||||||
|
int id() const override { return CommandId::ID_MapConnectionChangeMap; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPointer<MapConnection> connection;
|
||||||
|
QString newMapName;
|
||||||
|
QString oldMapName;
|
||||||
|
int oldOffset;
|
||||||
|
int newOffset;
|
||||||
|
bool mirrored;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Implements a command to commit adding a Map Connection to a map.
|
||||||
|
class MapConnectionAdd : public QUndoCommand {
|
||||||
|
public:
|
||||||
|
MapConnectionAdd(Map *map, MapConnection *connection,
|
||||||
|
QUndoCommand *parent = nullptr);
|
||||||
|
|
||||||
|
void undo() override;
|
||||||
|
void redo() override;
|
||||||
|
|
||||||
|
int id() const override { return CommandId::ID_MapConnectionAdd; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Map *map = nullptr;
|
||||||
|
Map *mirrorMap = nullptr;
|
||||||
|
QPointer<MapConnection> connection = nullptr;
|
||||||
|
QPointer<MapConnection> mirror = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Implements a command to commit removing a Map Connection from a map.
|
||||||
|
class MapConnectionRemove : public QUndoCommand {
|
||||||
|
public:
|
||||||
|
MapConnectionRemove(Map *map, MapConnection *connection,
|
||||||
|
QUndoCommand *parent = nullptr);
|
||||||
|
|
||||||
|
void undo() override;
|
||||||
|
void redo() override;
|
||||||
|
|
||||||
|
int id() const override { return CommandId::ID_MapConnectionRemove; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Map *map = nullptr;
|
||||||
|
Map *mirrorMap = nullptr;
|
||||||
|
QPointer<MapConnection> connection = nullptr;
|
||||||
|
QPointer<MapConnection> mirror = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // EDITCOMMANDS_H
|
#endif // EDITCOMMANDS_H
|
||||||
|
|
|
@ -99,10 +99,12 @@ public:
|
||||||
void addEvent(Event *);
|
void addEvent(Event *);
|
||||||
void deleteConnections();
|
void deleteConnections();
|
||||||
QList<MapConnection*> getConnections() const;
|
QList<MapConnection*> getConnections() const;
|
||||||
void removeConnection(MapConnection *);
|
bool takeConnection(MapConnection *);
|
||||||
void addConnection(MapConnection *);
|
bool removeConnection(MapConnection *);
|
||||||
|
bool addConnection(MapConnection *);
|
||||||
void loadConnection(MapConnection *);
|
void loadConnection(MapConnection *);
|
||||||
QPixmap renderConnection(const QString &, MapLayout *);
|
QRect getConnectionRect(const QString &direction, MapLayout *fromLayout = nullptr);
|
||||||
|
QPixmap renderConnection(const QString &direction, MapLayout *fromLayout = nullptr);
|
||||||
QPixmap renderBorder(bool ignoreCache = false);
|
QPixmap renderBorder(bool ignoreCache = false);
|
||||||
void setDimensions(int newWidth, int newHeight, bool setNewBlockdata = true, bool enableScriptCallback = 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);
|
void setBorderDimensions(int newWidth, int newHeight, bool setNewBlockdata = true, bool enableScriptCallback = false);
|
||||||
|
@ -126,12 +128,15 @@ public:
|
||||||
QUndoStack editHistory;
|
QUndoStack editHistory;
|
||||||
void modify();
|
void modify();
|
||||||
void clean();
|
void clean();
|
||||||
|
void pruneEditHistory();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setNewDimensionsBlockdata(int newWidth, int newHeight);
|
void setNewDimensionsBlockdata(int newWidth, int newHeight);
|
||||||
void setNewBorderDimensionsBlockdata(int newWidth, int newHeight);
|
void setNewBorderDimensionsBlockdata(int newWidth, int newHeight);
|
||||||
|
|
||||||
|
// MapConnections in 'ownedConnections' but not 'connections' persist in the edit history.
|
||||||
QList<MapConnection*> connections;
|
QList<MapConnection*> connections;
|
||||||
|
QSet<MapConnection*> ownedConnections;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void modified();
|
void modified();
|
||||||
|
|
|
@ -29,7 +29,6 @@ public:
|
||||||
int offset() const { return m_offset; }
|
int offset() const { return m_offset; }
|
||||||
void setOffset(int offset, bool mirror = true);
|
void setOffset(int offset, bool mirror = true);
|
||||||
|
|
||||||
bool isMirror(const MapConnection*);
|
|
||||||
MapConnection* findMirror();
|
MapConnection* findMirror();
|
||||||
MapConnection* createMirror();
|
MapConnection* createMirror();
|
||||||
|
|
||||||
|
@ -43,6 +42,7 @@ public:
|
||||||
static bool isVertical(const QString &direction);
|
static bool isVertical(const QString &direction);
|
||||||
static bool isDiving(const QString &direction);
|
static bool isDiving(const QString &direction);
|
||||||
static QString oppositeDirection(const QString &direction) { return oppositeDirections.value(direction, direction); }
|
static QString oppositeDirection(const QString &direction) { return oppositeDirections.value(direction, direction); }
|
||||||
|
static bool areMirrored(const MapConnection*, const MapConnection*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Map* m_parentMap;
|
Map* m_parentMap;
|
||||||
|
|
|
@ -79,6 +79,7 @@ public:
|
||||||
void setConnectionsVisibility(bool visible);
|
void setConnectionsVisibility(bool visible);
|
||||||
void updateDivingMapsVisibility();
|
void updateDivingMapsVisibility();
|
||||||
void displayDivingConnections();
|
void displayDivingConnections();
|
||||||
|
void renderDivingConnections();
|
||||||
void addConnection(MapConnection* connection);
|
void addConnection(MapConnection* connection);
|
||||||
void removeConnection(MapConnection* connection);
|
void removeConnection(MapConnection* connection);
|
||||||
void removeSelectedConnection();
|
void removeSelectedConnection();
|
||||||
|
@ -111,7 +112,6 @@ public:
|
||||||
QPointer<QGraphicsScene> scene = nullptr;
|
QPointer<QGraphicsScene> scene = nullptr;
|
||||||
QGraphicsPixmapItem *current_view = nullptr;
|
QGraphicsPixmapItem *current_view = nullptr;
|
||||||
QPointer<MapPixmapItem> map_item = nullptr;
|
QPointer<MapPixmapItem> map_item = nullptr;
|
||||||
QPointer<ConnectionPixmapItem> selected_connection_item = nullptr;
|
|
||||||
QList<QPointer<ConnectionPixmapItem>> connection_items;
|
QList<QPointer<ConnectionPixmapItem>> connection_items;
|
||||||
QMap<QString, QPointer<DivingMapPixmapItem>> diving_map_items;
|
QMap<QString, QPointer<DivingMapPixmapItem>> diving_map_items;
|
||||||
QGraphicsPathItem *connection_mask = nullptr;
|
QGraphicsPathItem *connection_mask = nullptr;
|
||||||
|
@ -134,6 +134,8 @@ public:
|
||||||
QPointer<MovementPermissionsSelector> movement_permissions_selector_item = nullptr;
|
QPointer<MovementPermissionsSelector> movement_permissions_selector_item = nullptr;
|
||||||
|
|
||||||
QList<DraggablePixmapItem *> *selected_events = nullptr;
|
QList<DraggablePixmapItem *> *selected_events = nullptr;
|
||||||
|
QPointer<ConnectionPixmapItem> selected_connection_item = nullptr;
|
||||||
|
QPointer<MapConnection> connection_to_select = nullptr;
|
||||||
|
|
||||||
QString map_edit_mode = "paint";
|
QString map_edit_mode = "paint";
|
||||||
QString obj_edit_mode = "select";
|
QString obj_edit_mode = "select";
|
||||||
|
@ -183,10 +185,9 @@ private:
|
||||||
void clearMapGrid();
|
void clearMapGrid();
|
||||||
void clearWildMonTables();
|
void clearWildMonTables();
|
||||||
void updateBorderVisibility();
|
void updateBorderVisibility();
|
||||||
QPoint calculateConnectionPosition(MapConnection *connection, const QPixmap &pixmap);
|
QPoint getConnectionOrigin(MapConnection *connection);
|
||||||
void removeConnectionPixmap(MapConnection* connection);
|
void removeConnectionPixmap(MapConnection* connection);
|
||||||
void updateConnectionPixmap(ConnectionPixmapItem* connectionItem);
|
void updateConnectionPixmap(ConnectionPixmapItem* connectionItem);
|
||||||
void updateConnectionPixmapPos(ConnectionPixmapItem* connectionItem);
|
|
||||||
void displayConnection(MapConnection* connection);
|
void displayConnection(MapConnection* connection);
|
||||||
void displayDivingConnection(MapConnection* connection);
|
void displayDivingConnection(MapConnection* connection);
|
||||||
void setDivingMapName(QString mapName, QString direction);
|
void setDivingMapName(QString mapName, QString direction);
|
||||||
|
|
|
@ -9,36 +9,37 @@
|
||||||
class ConnectionPixmapItem : public QObject, public QGraphicsPixmapItem {
|
class ConnectionPixmapItem : public QObject, public QGraphicsPixmapItem {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
ConnectionPixmapItem(QPixmap pixmap, MapConnection* connection, int x, int y)
|
ConnectionPixmapItem(MapConnection* connection, int originX, int originY);
|
||||||
: QGraphicsPixmapItem(pixmap)
|
ConnectionPixmapItem(MapConnection* connection, QPoint origin);
|
||||||
{
|
|
||||||
this->basePixmap = pixmap;
|
const QPointer<MapConnection> connection;
|
||||||
this->connection = connection;
|
|
||||||
setFlag(ItemIsMovable);
|
void setOrigin(int x, int y);
|
||||||
setFlag(ItemSendsGeometryChanges);
|
void setOrigin(QPoint pos);
|
||||||
this->initialX = x;
|
|
||||||
this->initialY = y;
|
|
||||||
this->initialOffset = connection->offset();
|
|
||||||
this->setPos(x, y);
|
|
||||||
}
|
|
||||||
QPixmap basePixmap;
|
|
||||||
QPointer<MapConnection> connection;
|
|
||||||
int initialX;
|
|
||||||
int initialY;
|
|
||||||
int initialOffset;
|
|
||||||
|
|
||||||
void setEditable(bool editable);
|
void setEditable(bool editable);
|
||||||
bool getEditable();
|
bool getEditable();
|
||||||
|
|
||||||
void setSelected(bool selected);
|
void setSelected(bool selected);
|
||||||
void render();
|
|
||||||
|
void updatePos();
|
||||||
|
void render(bool ignoreCache = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QPixmap basePixmap;
|
||||||
|
qreal originX;
|
||||||
|
qreal originY;
|
||||||
bool selected = false;
|
bool selected = false;
|
||||||
|
unsigned actionId = 0;
|
||||||
|
|
||||||
|
static const int mWidth = 16;
|
||||||
|
static const int mHeight = 16;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
|
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
|
||||||
void mousePressEvent(QGraphicsSceneMouseEvent*);
|
void mousePressEvent(QGraphicsSceneMouseEvent*) override;
|
||||||
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent*);
|
void mouseReleaseEvent(QGraphicsSceneMouseEvent*) override;
|
||||||
|
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent*) override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void connectionItemDoubleClicked(MapConnection*);
|
void connectionItemDoubleClicked(MapConnection*);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define CONNECTIONSLISTITEM_H
|
#define CONNECTIONSLISTITEM_H
|
||||||
|
|
||||||
#include "mapconnection.h"
|
#include "mapconnection.h"
|
||||||
|
#include "map.h"
|
||||||
|
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
|
@ -30,11 +31,13 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::ConnectionsListItem *ui;
|
Ui::ConnectionsListItem *ui;
|
||||||
|
Map *map;
|
||||||
bool isSelected = false;
|
bool isSelected = false;
|
||||||
|
unsigned actionId = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void mousePressEvent(QMouseEvent *);
|
void mousePressEvent(QMouseEvent*) override;
|
||||||
void mouseDoubleClickEvent(QMouseEvent *);
|
void mouseDoubleClickEvent(QMouseEvent*) override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void removed(MapConnection*);
|
void removed(MapConnection*);
|
||||||
|
|
|
@ -5,30 +5,26 @@
|
||||||
|
|
||||||
#include <QGraphicsPixmapItem>
|
#include <QGraphicsPixmapItem>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
#include <QComboBox>
|
||||||
|
|
||||||
class DivingMapPixmapItem : public QObject, public QGraphicsPixmapItem {
|
class DivingMapPixmapItem : public QObject, public QGraphicsPixmapItem {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
DivingMapPixmapItem(MapConnection* connection)
|
DivingMapPixmapItem(MapConnection *connection, QComboBox *combo);
|
||||||
: QGraphicsPixmapItem(getBasePixmap(connection))
|
~DivingMapPixmapItem();
|
||||||
{
|
|
||||||
m_connection = connection;
|
|
||||||
|
|
||||||
// Update pixmap if the connected map is swapped.
|
|
||||||
connect(m_connection, &MapConnection::targetMapNameChanged, this, &DivingMapPixmapItem::updatePixmap);
|
|
||||||
}
|
|
||||||
MapConnection* connection() const { return m_connection; }
|
MapConnection* connection() const { return m_connection; }
|
||||||
|
void updatePixmap();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QPointer<MapConnection> m_connection;
|
QPointer<MapConnection> m_connection;
|
||||||
|
QPointer<QComboBox> m_combo;
|
||||||
|
|
||||||
static QPixmap getBasePixmap(MapConnection* connection) {
|
void setComboText(const QString &text);
|
||||||
// If the map is connected to itself then rendering is pointless.
|
static QPixmap getBasePixmap(MapConnection* connection);
|
||||||
if (!connection || connection->targetMapName() == connection->parentMapName())
|
|
||||||
return QPixmap();
|
private slots:
|
||||||
return connection->getPixmap();
|
void onTargetMapChanged();
|
||||||
}
|
|
||||||
void updatePixmap() { setPixmap(getBasePixmap(m_connection)); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DIVINGMAPPIXMAPITEM_H
|
#endif // DIVINGMAPPIXMAPITEM_H
|
||||||
|
|
|
@ -17,10 +17,11 @@ public:
|
||||||
explicit NewMapConnectionDialog(QWidget *parent, Map* map, const QStringList &mapNames);
|
explicit NewMapConnectionDialog(QWidget *parent, Map* map, const QStringList &mapNames);
|
||||||
~NewMapConnectionDialog();
|
~NewMapConnectionDialog();
|
||||||
|
|
||||||
MapConnection *result;
|
|
||||||
|
|
||||||
virtual void accept() override;
|
virtual void accept() override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void accepted(MapConnection *result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::NewMapConnectionDialog *ui;
|
Ui::NewMapConnectionDialog *ui;
|
||||||
};
|
};
|
||||||
|
|
|
@ -50,6 +50,7 @@ SOURCES += src/core/block.cpp \
|
||||||
src/ui/connectionslistitem.cpp \
|
src/ui/connectionslistitem.cpp \
|
||||||
src/ui/customscriptseditor.cpp \
|
src/ui/customscriptseditor.cpp \
|
||||||
src/ui/customscriptslistitem.cpp \
|
src/ui/customscriptslistitem.cpp \
|
||||||
|
src/ui/divingmappixmapitem.cpp \
|
||||||
src/ui/draggablepixmapitem.cpp \
|
src/ui/draggablepixmapitem.cpp \
|
||||||
src/ui/bordermetatilespixmapitem.cpp \
|
src/ui/bordermetatilespixmapitem.cpp \
|
||||||
src/ui/collisionpixmapitem.cpp \
|
src/ui/collisionpixmapitem.cpp \
|
||||||
|
|
|
@ -569,3 +569,205 @@ void ScriptEditMap::undo() {
|
||||||
|
|
||||||
QUndoCommand::undo();
|
QUndoCommand::undo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
************************************************************************
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
MapConnectionMove::MapConnectionMove(MapConnection *connection, int newOffset, unsigned actionId,
|
||||||
|
QUndoCommand *parent) : QUndoCommand(parent) {
|
||||||
|
setText("Move Map Connection");
|
||||||
|
|
||||||
|
this->connection = connection;
|
||||||
|
this->oldOffset = connection->offset();
|
||||||
|
this->newOffset = newOffset;
|
||||||
|
|
||||||
|
this->mirrored = porymapConfig.mirrorConnectingMaps;
|
||||||
|
|
||||||
|
this->actionId = actionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapConnectionMove::redo() {
|
||||||
|
QUndoCommand::redo();
|
||||||
|
if (this->connection)
|
||||||
|
this->connection->setOffset(this->newOffset, this->mirrored);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapConnectionMove::undo() {
|
||||||
|
if (this->connection)
|
||||||
|
this->connection->setOffset(this->oldOffset, this->mirrored);
|
||||||
|
QUndoCommand::undo();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MapConnectionMove::mergeWith(const QUndoCommand *command) {
|
||||||
|
if (this->id() != command->id())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const MapConnectionMove *other = static_cast<const MapConnectionMove *>(command);
|
||||||
|
if (this->connection != other->connection)
|
||||||
|
return false;
|
||||||
|
if (this->actionId != other->actionId)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
this->newOffset = other->newOffset;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
************************************************************************
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
MapConnectionChangeDirection::MapConnectionChangeDirection(MapConnection *connection, QString newDirection,
|
||||||
|
QUndoCommand *parent) : QUndoCommand(parent) {
|
||||||
|
setText("Change Map Connection Direction");
|
||||||
|
|
||||||
|
this->connection = connection;
|
||||||
|
|
||||||
|
this->oldDirection = connection->direction();
|
||||||
|
this->newDirection = newDirection;
|
||||||
|
|
||||||
|
this->oldOffset = connection->offset();
|
||||||
|
|
||||||
|
// If the direction changes between vertical/horizontal then the old offset may not make sense, so we reset it.
|
||||||
|
if (MapConnection::isHorizontal(this->oldDirection) != MapConnection::isHorizontal(this->newDirection)
|
||||||
|
|| MapConnection::isVertical(this->oldDirection) != MapConnection::isVertical(this->newDirection)) {
|
||||||
|
this->newOffset = 0;
|
||||||
|
} else {
|
||||||
|
this->newOffset = oldOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->mirrored = porymapConfig.mirrorConnectingMaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapConnectionChangeDirection::redo() {
|
||||||
|
QUndoCommand::redo();
|
||||||
|
if (this->connection) {
|
||||||
|
this->connection->setDirection(this->newDirection, this->mirrored);
|
||||||
|
this->connection->setOffset(this->newOffset, this->mirrored);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapConnectionChangeDirection::undo() {
|
||||||
|
if (this->connection) {
|
||||||
|
this->connection->setDirection(this->oldDirection, this->mirrored);
|
||||||
|
this->connection->setOffset(this->oldOffset, this->mirrored);
|
||||||
|
}
|
||||||
|
QUndoCommand::undo();
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
************************************************************************
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
MapConnectionChangeMap::MapConnectionChangeMap(MapConnection *connection, QString newMapName,
|
||||||
|
QUndoCommand *parent) : QUndoCommand(parent) {
|
||||||
|
setText("Change Map Connection Map");
|
||||||
|
|
||||||
|
this->connection = connection;
|
||||||
|
|
||||||
|
this->oldMapName = connection->targetMapName();
|
||||||
|
this->newMapName = newMapName;
|
||||||
|
|
||||||
|
this->oldOffset = connection->offset();
|
||||||
|
this->newOffset = 0; // The old offset may not make sense, so we reset it
|
||||||
|
|
||||||
|
this->mirrored = porymapConfig.mirrorConnectingMaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapConnectionChangeMap::redo() {
|
||||||
|
QUndoCommand::redo();
|
||||||
|
if (this->connection) {
|
||||||
|
this->connection->setTargetMapName(this->newMapName, this->mirrored);
|
||||||
|
this->connection->setOffset(this->newOffset, this->mirrored);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapConnectionChangeMap::undo() {
|
||||||
|
if (this->connection) {
|
||||||
|
this->connection->setTargetMapName(this->oldMapName, this->mirrored);
|
||||||
|
this->connection->setOffset(this->oldOffset, this->mirrored);
|
||||||
|
}
|
||||||
|
QUndoCommand::undo();
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
************************************************************************
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
MapConnectionAdd::MapConnectionAdd(Map *map, MapConnection *connection,
|
||||||
|
QUndoCommand *parent) : QUndoCommand(parent) {
|
||||||
|
setText("Add Map Connection");
|
||||||
|
|
||||||
|
this->map = map;
|
||||||
|
this->connection = connection;
|
||||||
|
|
||||||
|
// Set this now because it's needed to create a mirror below.
|
||||||
|
// It would otherwise be set by Map::addConnection.
|
||||||
|
this->connection->setParentMap(this->map, false);
|
||||||
|
|
||||||
|
if (porymapConfig.mirrorConnectingMaps) {
|
||||||
|
this->mirror = this->connection->createMirror();
|
||||||
|
this->mirrorMap = this->connection->targetMap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapConnectionAdd::redo() {
|
||||||
|
QUndoCommand::redo();
|
||||||
|
|
||||||
|
this->map->addConnection(this->connection);
|
||||||
|
if (this->mirrorMap)
|
||||||
|
this->mirrorMap->addConnection(this->mirror);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapConnectionAdd::undo() {
|
||||||
|
if (this->mirrorMap) {
|
||||||
|
// We can't guarantee that the mirror we created earlier is still our connection's
|
||||||
|
// mirror because there is no strict source->mirror pairing for map connections
|
||||||
|
// (a different identical map connection can take its place during any mirrored change).
|
||||||
|
if (!MapConnection::areMirrored(this->connection, this->mirror))
|
||||||
|
this->mirror = this->connection->findMirror();
|
||||||
|
|
||||||
|
this->mirrorMap->removeConnection(this->mirror);
|
||||||
|
}
|
||||||
|
this->map->removeConnection(this->connection);
|
||||||
|
|
||||||
|
QUndoCommand::undo();
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
************************************************************************
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
MapConnectionRemove::MapConnectionRemove(Map *map, MapConnection *connection,
|
||||||
|
QUndoCommand *parent) : QUndoCommand(parent) {
|
||||||
|
setText("Remove Map Connection");
|
||||||
|
|
||||||
|
this->map = map;
|
||||||
|
this->connection = connection;
|
||||||
|
|
||||||
|
if (porymapConfig.mirrorConnectingMaps) {
|
||||||
|
this->mirror = this->connection->findMirror();
|
||||||
|
this->mirrorMap = this->connection->targetMap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapConnectionRemove::redo() {
|
||||||
|
QUndoCommand::redo();
|
||||||
|
|
||||||
|
if (this->mirrorMap) {
|
||||||
|
// See comment in MapConnectionAdd::undo
|
||||||
|
if (!MapConnection::areMirrored(this->connection, this->mirror))
|
||||||
|
this->mirror = this->connection->findMirror();
|
||||||
|
|
||||||
|
this->mirrorMap->removeConnection(this->mirror);
|
||||||
|
}
|
||||||
|
this->map->removeConnection(this->connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapConnectionRemove::undo() {
|
||||||
|
this->map->addConnection(this->connection);
|
||||||
|
if (this->mirrorMap)
|
||||||
|
this->mirrorMap->addConnection(this->mirror);
|
||||||
|
|
||||||
|
QUndoCommand::undo();
|
||||||
|
}
|
||||||
|
|
106
src/core/map.cpp
106
src/core/map.cpp
|
@ -215,11 +215,13 @@ QPixmap Map::renderBorder(bool ignoreCache) {
|
||||||
return layout->border_pixmap;
|
return layout->border_pixmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap Map::renderConnection(const QString &direction, MapLayout * fromLayout) {
|
// Get the portion of the map that can be rendered when rendered as a map connection.
|
||||||
// Cardinal connections are rendered within the bounds of the border draw distance,
|
// Cardinal connections render the nearest segment of their map and within the bounds of the border draw distance,
|
||||||
// and we need to render the nearest segment of the map.
|
// Dive/Emerge connections are rendered normally within the bounds of their parent map.
|
||||||
// Dive/Emerge maps are rendered normally, but within the bounds of their parent map.
|
QRect Map::getConnectionRect(const QString &direction, MapLayout * fromLayout) {
|
||||||
int x = 0, y = 0, w = getWidth(), h = getHeight();
|
int x = 0, y = 0;
|
||||||
|
int w = getWidth(), h = getHeight();
|
||||||
|
|
||||||
if (direction == "up") {
|
if (direction == "up") {
|
||||||
h = qMin(h, BORDER_DISTANCE);
|
h = qMin(h, BORDER_DISTANCE);
|
||||||
y = getHeight() - h;
|
y = getHeight() - h;
|
||||||
|
@ -234,15 +236,26 @@ QPixmap Map::renderConnection(const QString &direction, MapLayout * fromLayout)
|
||||||
if (fromLayout) {
|
if (fromLayout) {
|
||||||
w = qMin(w, fromLayout->getWidth());
|
w = qMin(w, fromLayout->getWidth());
|
||||||
h = qMin(h, fromLayout->getHeight());
|
h = qMin(h, fromLayout->getHeight());
|
||||||
fromLayout = nullptr; // This would be used for palettes later, but we want our own palettes, not the parent's.
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Unknown direction
|
// Unknown direction
|
||||||
return QPixmap();
|
return QRect();
|
||||||
}
|
}
|
||||||
|
return QRect(x, y, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
render(true, fromLayout, QRect(x, y, w, h));
|
QPixmap Map::renderConnection(const QString &direction, MapLayout * fromLayout) {
|
||||||
QImage connection_image = image.copy(x * 16, y * 16, w * 16, h * 16);
|
QRect bounds = getConnectionRect(direction, fromLayout);
|
||||||
|
if (!bounds.isValid())
|
||||||
|
return QPixmap();
|
||||||
|
|
||||||
|
// 'fromLayout' will be used in 'render' to get the palettes from the parent map.
|
||||||
|
// Dive/Emerge connections render normally with their own palettes, so we ignore this.
|
||||||
|
if (MapConnection::isDiving(direction))
|
||||||
|
fromLayout = nullptr;
|
||||||
|
|
||||||
|
render(true, fromLayout, bounds);
|
||||||
|
QImage connection_image = image.copy(bounds.x() * 16, bounds.y() * 16, bounds.width() * 16, bounds.height() * 16);
|
||||||
return QPixmap::fromImage(connection_image);
|
return QPixmap::fromImage(connection_image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,54 +531,62 @@ void Map::addEvent(Event *event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::deleteConnections() {
|
void Map::deleteConnections() {
|
||||||
qDeleteAll(connections);
|
qDeleteAll(this->ownedConnections);
|
||||||
connections.clear();
|
this->ownedConnections.clear();
|
||||||
|
this->connections.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<MapConnection*> Map::getConnections() const {
|
QList<MapConnection*> Map::getConnections() const {
|
||||||
return connections;
|
return connections;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::addConnection(MapConnection *connection) {
|
bool Map::addConnection(MapConnection *connection) {
|
||||||
if (!connection || connections.contains(connection))
|
if (!connection || this->connections.contains(connection))
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
// Adding new Dive/Emerge maps replaces an existing one.
|
// Maps should only have one Dive/Emerge connection at a time.
|
||||||
|
// (Users can technically have more by editing their data manually, but we will only display one at a time)
|
||||||
|
// Any additional connections being added (this can happen via mirroring) are tracked for deleting but otherwise ignored.
|
||||||
if (MapConnection::isDiving(connection->direction())) {
|
if (MapConnection::isDiving(connection->direction())) {
|
||||||
for (auto connectionToReplace : connections) {
|
for (auto i : this->connections) {
|
||||||
if (connectionToReplace->direction() != connection->direction())
|
if (i->direction() == connection->direction()) {
|
||||||
continue;
|
this->ownedConnections.insert(connection);
|
||||||
if (porymapConfig.mirrorConnectingMaps) {
|
connection->setParentMap(this, false);
|
||||||
auto mirror = connectionToReplace->findMirror();
|
return true;
|
||||||
if (mirror && mirror->parentMap())
|
|
||||||
mirror->parentMap()->removeConnection(mirror);
|
|
||||||
delete mirror;
|
|
||||||
}
|
}
|
||||||
removeConnection(connectionToReplace);
|
|
||||||
delete connectionToReplace;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadConnection(connection);
|
loadConnection(connection);
|
||||||
modify();
|
modify();
|
||||||
emit connectionAdded(connection);
|
emit connectionAdded(connection);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::loadConnection(MapConnection *connection) {
|
void Map::loadConnection(MapConnection *connection) {
|
||||||
if (!connection)
|
if (!connection)
|
||||||
return;
|
return;
|
||||||
connections.append(connection);
|
this->connections.append(connection);
|
||||||
|
this->ownedConnections.insert(connection);
|
||||||
connection->setParentMap(this, false);
|
connection->setParentMap(this, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Caller takes ownership of connection
|
// connection should not be deleted here, a pointer to it is allowed to persist in the edit history
|
||||||
void Map::removeConnection(MapConnection *connection) {
|
bool Map::removeConnection(MapConnection *connection) {
|
||||||
if (!connections.removeOne(connection))
|
if (!this->connections.removeOne(connection))
|
||||||
return;
|
return false;
|
||||||
connection->setParentMap(nullptr, false);
|
|
||||||
modify();
|
modify();
|
||||||
emit connectionRemoved(connection);
|
emit connectionRemoved(connection);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same as Map::removeConnection but caller takes ownership of connection.
|
||||||
|
bool Map::takeConnection(MapConnection *connection) {
|
||||||
|
if (!this->removeConnection(connection))
|
||||||
|
return false;
|
||||||
|
connection->setParentMap(nullptr, false);
|
||||||
|
this->ownedConnections.remove(connection);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::modify() {
|
void Map::modify() {
|
||||||
|
@ -580,6 +601,27 @@ bool Map::hasUnsavedChanges() {
|
||||||
return !editHistory.isClean() || hasUnsavedDataChanges || !isPersistedToFile;
|
return !editHistory.isClean() || hasUnsavedDataChanges || !isPersistedToFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Map::pruneEditHistory() {
|
||||||
|
// Edit history for map connections gets messy because edits on other maps can affect the current map.
|
||||||
|
// To avoid complications we clear MapConnection edit history when the user opens a different map.
|
||||||
|
// No other edits within a single map depend on MapConnections so they can be pruned safely.
|
||||||
|
static const QSet<int> mapConnectionIds = {
|
||||||
|
ID_MapConnectionMove,
|
||||||
|
ID_MapConnectionChangeDirection,
|
||||||
|
ID_MapConnectionChangeMap,
|
||||||
|
ID_MapConnectionAdd,
|
||||||
|
ID_MapConnectionRemove
|
||||||
|
};
|
||||||
|
for (int i = 0; i < this->editHistory.count(); i++) {
|
||||||
|
// Qt really doesn't expect editing commands in the stack to be valid (fair).
|
||||||
|
// A better future design might be to have separate edit histories per map tab,
|
||||||
|
// and dumping the entire Connections tab history with QUndoStack::clear.
|
||||||
|
auto command = const_cast<QUndoCommand*>(this->editHistory.command(i));
|
||||||
|
if (mapConnectionIds.contains(command->id()))
|
||||||
|
command->setObsolete(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Map::isWithinBounds(int x, int y) {
|
bool Map::isWithinBounds(int x, int y) {
|
||||||
return (x >= 0 && x < this->getWidth() && y >= 0 && y < this->getHeight());
|
return (x >= 0 && x < this->getWidth() && y >= 0 && y < this->getHeight());
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,14 +16,14 @@ MapConnection::MapConnection(const QString &targetMapName, const QString &direct
|
||||||
m_offset = offset;
|
m_offset = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MapConnection::isMirror(const MapConnection* other) {
|
bool MapConnection::areMirrored(const MapConnection* a, const MapConnection* b) {
|
||||||
if (!other || !other->m_parentMap)
|
if (!a || !b || !a->m_parentMap || !b->m_parentMap)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return parentMapName() == other->m_targetMapName
|
return a->parentMapName() == b->m_targetMapName
|
||||||
&& m_targetMapName == other->parentMapName()
|
&& a->m_targetMapName == b->parentMapName()
|
||||||
&& m_offset == -other->m_offset
|
&& a->m_offset == -b->m_offset
|
||||||
&& m_direction == oppositeDirection(other->m_direction);
|
&& a->m_direction == oppositeDirection(b->m_direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
MapConnection* MapConnection::findMirror() {
|
MapConnection* MapConnection::findMirror() {
|
||||||
|
@ -35,7 +35,7 @@ MapConnection* MapConnection::findMirror() {
|
||||||
// Note: There is no strict source -> mirror pairing, i.e. we are not guaranteed
|
// 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.
|
// to always get the same MapConnection if there are multiple identical copies.
|
||||||
for (auto connection : map->getConnections()) {
|
for (auto connection : map->getConnections()) {
|
||||||
if (this != connection && this->isMirror(connection))
|
if (this != connection && areMirrored(this, connection))
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -72,14 +72,14 @@ void MapConnection::setParentMap(Map* map, bool mirror) {
|
||||||
if (map == m_parentMap)
|
if (map == m_parentMap)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mirror && porymapConfig.mirrorConnectingMaps) {
|
if (mirror) {
|
||||||
auto connection = findMirror();
|
auto connection = findMirror();
|
||||||
if (connection)
|
if (connection)
|
||||||
connection->setTargetMapName(map ? map->name : QString(), false);
|
connection->setTargetMapName(map ? map->name : QString(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_parentMap)
|
if (m_parentMap)
|
||||||
m_parentMap->removeConnection(this);
|
m_parentMap->takeConnection(this);
|
||||||
|
|
||||||
auto before = m_parentMap;
|
auto before = m_parentMap;
|
||||||
m_parentMap = map;
|
m_parentMap = map;
|
||||||
|
@ -98,7 +98,7 @@ void MapConnection::setTargetMapName(const QString &targetMapName, bool mirror)
|
||||||
if (targetMapName == m_targetMapName)
|
if (targetMapName == m_targetMapName)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mirror && porymapConfig.mirrorConnectingMaps) {
|
if (mirror) {
|
||||||
auto connection = findMirror();
|
auto connection = findMirror();
|
||||||
if (connection)
|
if (connection)
|
||||||
connection->setParentMap(getMap(targetMapName), false);
|
connection->setParentMap(getMap(targetMapName), false);
|
||||||
|
@ -114,7 +114,7 @@ void MapConnection::setDirection(const QString &direction, bool mirror) {
|
||||||
if (direction == m_direction)
|
if (direction == m_direction)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mirror && porymapConfig.mirrorConnectingMaps) {
|
if (mirror) {
|
||||||
auto connection = findMirror();
|
auto connection = findMirror();
|
||||||
if (connection)
|
if (connection)
|
||||||
connection->setDirection(oppositeDirection(direction), false);
|
connection->setDirection(oppositeDirection(direction), false);
|
||||||
|
@ -130,7 +130,7 @@ void MapConnection::setOffset(int offset, bool mirror) {
|
||||||
if (offset == m_offset)
|
if (offset == m_offset)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mirror && porymapConfig.mirrorConnectingMaps) {
|
if (mirror) {
|
||||||
auto connection = findMirror();
|
auto connection = findMirror();
|
||||||
if (connection)
|
if (connection)
|
||||||
connection->setOffset(-offset, false);
|
connection->setOffset(-offset, false);
|
||||||
|
|
191
src/editor.cpp
191
src/editor.cpp
|
@ -743,9 +743,7 @@ void Editor::displayConnection(MapConnection* connection) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create connection image
|
// Create connection image
|
||||||
QPixmap pixmap = connection->getPixmap();
|
ConnectionPixmapItem *pixmapItem = new ConnectionPixmapItem(connection, getConnectionOrigin(connection));
|
||||||
QPoint pos = calculateConnectionPosition(connection, pixmap);
|
|
||||||
ConnectionPixmapItem *pixmapItem = new ConnectionPixmapItem(pixmap, connection, pos.x(), pos.y());
|
|
||||||
pixmapItem->render();
|
pixmapItem->render();
|
||||||
scene->addItem(pixmapItem);
|
scene->addItem(pixmapItem);
|
||||||
maskNonVisibleConnectionTiles();
|
maskNonVisibleConnectionTiles();
|
||||||
|
@ -756,82 +754,70 @@ void Editor::displayConnection(MapConnection* connection) {
|
||||||
|
|
||||||
// It's possible for a map connection to be displayed repeatedly if it's being
|
// It's possible for a map connection to be displayed repeatedly if it's being
|
||||||
// updated by mirroring and the target map is changing to/from the current map.
|
// updated by mirroring and the target map is changing to/from the current map.
|
||||||
connection->disconnect();
|
QObject::disconnect(connection, &MapConnection::targetMapNameChanged, nullptr, nullptr);
|
||||||
|
QObject::disconnect(connection, &MapConnection::directionChanged, nullptr, nullptr);
|
||||||
|
QObject::disconnect(connection, &MapConnection::offsetChanged, nullptr, nullptr);
|
||||||
|
|
||||||
// Double clicking the list item or pixmap opens the connected map
|
// Double clicking the list item or pixmap opens the connected map
|
||||||
connect(listItem, &ConnectionsListItem::doubleClicked, this, &Editor::onMapConnectionDoubleClicked);
|
connect(listItem, &ConnectionsListItem::doubleClicked, this, &Editor::onMapConnectionDoubleClicked);
|
||||||
connect(pixmapItem, &ConnectionPixmapItem::connectionItemDoubleClicked, this, &Editor::onMapConnectionDoubleClicked);
|
connect(pixmapItem, &ConnectionPixmapItem::connectionItemDoubleClicked, this, &Editor::onMapConnectionDoubleClicked);
|
||||||
|
|
||||||
// Sync the selection highlight between the list UI and the pixmap
|
// Sync the selection highlight between the list UI and the pixmap
|
||||||
connect(pixmapItem, &ConnectionPixmapItem::selectionChanged, [this, listItem, pixmapItem](bool selected) {
|
connect(pixmapItem, &ConnectionPixmapItem::selectionChanged, [=](bool selected) {
|
||||||
listItem->setSelected(selected);
|
listItem->setSelected(selected);
|
||||||
if (selected) setSelectedConnectionItem(pixmapItem);
|
if (selected) setSelectedConnectionItem(pixmapItem);
|
||||||
});
|
});
|
||||||
connect(listItem, &ConnectionsListItem::selected, [this, pixmapItem] {
|
connect(listItem, &ConnectionsListItem::selected, [=] {
|
||||||
setSelectedConnectionItem(pixmapItem);
|
setSelectedConnectionItem(pixmapItem);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Sync edits to 'offset' between the list UI and the pixmap
|
// Sync edits to 'offset' between the list UI and the pixmap
|
||||||
connect(connection, &MapConnection::offsetChanged, [this, listItem, pixmapItem](int, int) {
|
connect(connection, &MapConnection::offsetChanged, [=](int, int) {
|
||||||
listItem->updateUI();
|
listItem->updateUI();
|
||||||
updateConnectionPixmapPos(pixmapItem);
|
pixmapItem->updatePos();
|
||||||
|
maskNonVisibleConnectionTiles();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Sync edits to 'direction' between the list UI and the pixmap
|
// Sync edits to 'direction' between the list UI and the pixmap
|
||||||
connect(connection, &MapConnection::directionChanged, [this, listItem, pixmapItem](QString before, QString after) {
|
connect(connection, &MapConnection::directionChanged, [=](QString, QString) {
|
||||||
if (MapConnection::isHorizontal(before) != MapConnection::isHorizontal(after)
|
|
||||||
|| MapConnection::isVertical(before) != MapConnection::isVertical(after)) {
|
|
||||||
// If the direction has changed between vertical/horizontal then the old offset may not make sense, so we reset it
|
|
||||||
pixmapItem->connection->setOffset(0);
|
|
||||||
}
|
|
||||||
listItem->updateUI();
|
listItem->updateUI();
|
||||||
updateConnectionPixmap(pixmapItem);
|
updateConnectionPixmap(pixmapItem);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Sync edits to 'map' between the list UI and the pixmap
|
// Sync edits to 'map' between the list UI and the pixmap
|
||||||
connect(connection, &MapConnection::targetMapNameChanged, [this, listItem, pixmapItem](QString, QString) {
|
connect(connection, &MapConnection::targetMapNameChanged, [=](QString, QString) {
|
||||||
// The old offset may not make sense, so we reset it
|
|
||||||
pixmapItem->connection->setOffset(0);
|
|
||||||
listItem->updateUI();
|
listItem->updateUI();
|
||||||
updateConnectionPixmap(pixmapItem);
|
updateConnectionPixmap(pixmapItem);
|
||||||
});
|
});
|
||||||
|
|
||||||
// User manually deleting connection via the remove button
|
|
||||||
connect(listItem, &ConnectionsListItem::removed, [this](MapConnection* connection) { removeConnection(connection); });
|
|
||||||
|
|
||||||
// When the pixmap is deleted, remove its associated list item
|
// When the pixmap is deleted, remove its associated list item
|
||||||
connect(pixmapItem, &ConnectionPixmapItem::destroyed, listItem, &ConnectionsListItem::deleteLater);
|
connect(pixmapItem, &ConnectionPixmapItem::destroyed, listItem, &ConnectionsListItem::deleteLater);
|
||||||
|
|
||||||
connection_items.append(pixmapItem);
|
connection_items.append(pixmapItem);
|
||||||
|
|
||||||
|
// If this was a recent addition from the user we should select it.
|
||||||
|
// We intentionally exclude connections added programmatically, e.g. by mirroring.
|
||||||
|
if (connection_to_select == connection) {
|
||||||
|
connection_to_select = nullptr;
|
||||||
|
setSelectedConnectionItem(pixmapItem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::addConnection(MapConnection * connection) {
|
void Editor::addConnection(MapConnection* connection) {
|
||||||
if (!connection)
|
if (!connection)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this->map->addConnection(connection);
|
// Mark this connection to be selected once its display elements have been created.
|
||||||
if (porymapConfig.mirrorConnectingMaps)
|
// It's possible this is a Dive/Emerge connection, but that's ok (no selection will occur).
|
||||||
connection->createMirror();
|
connection_to_select = connection;
|
||||||
|
|
||||||
// TODO: Edit history
|
this->map->editHistory.push(new MapConnectionAdd(this->map, connection));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::removeConnection(MapConnection* connection) {
|
void Editor::removeConnection(MapConnection* connection) {
|
||||||
if (!connection)
|
if (!connection)
|
||||||
return;
|
return;
|
||||||
|
this->map->editHistory.push(new MapConnectionRemove(this->map, connection));
|
||||||
if (porymapConfig.mirrorConnectingMaps) {
|
|
||||||
auto mirror = connection->findMirror();
|
|
||||||
if (mirror && mirror->parentMap())
|
|
||||||
mirror->parentMap()->removeConnection(mirror);
|
|
||||||
delete mirror;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (connection->parentMap())
|
|
||||||
connection->parentMap()->removeConnection(connection);
|
|
||||||
delete connection;
|
|
||||||
|
|
||||||
// TODO: Edit history
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::removeSelectedConnection() {
|
void Editor::removeSelectedConnection() {
|
||||||
|
@ -887,10 +873,6 @@ void Editor::displayDivingConnection(MapConnection* connection) {
|
||||||
if (!MapConnection::isDiving(direction))
|
if (!MapConnection::isDiving(direction))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Save some rendering time if it won't be displayed
|
|
||||||
if (!porymapConfig.showDiveEmergeMaps)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Note: We only support editing 1 Dive and Emerge connection per map.
|
// 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
|
// 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
|
// users to have multiple is likely to lead to confusion. In case users have changed
|
||||||
|
@ -898,15 +880,18 @@ void Editor::displayDivingConnection(MapConnection* connection) {
|
||||||
if (diving_map_items.value(direction))
|
if (diving_map_items.value(direction))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Create map image
|
// Create map display
|
||||||
auto item = new DivingMapPixmapItem(connection);
|
auto comboBox = (direction == "dive") ? ui->comboBox_DiveMap : ui->comboBox_EmergeMap;
|
||||||
|
auto item = new DivingMapPixmapItem(connection, comboBox);
|
||||||
scene->addItem(item);
|
scene->addItem(item);
|
||||||
diving_map_items.insert(direction, item);
|
diving_map_items.insert(direction, item);
|
||||||
|
|
||||||
// Display map name in combo box
|
updateDivingMapsVisibility();
|
||||||
auto comboBox = (direction == "dive") ? ui->comboBox_DiveMap : ui->comboBox_EmergeMap;
|
}
|
||||||
const QSignalBlocker blocker(comboBox);
|
|
||||||
comboBox->setCurrentText(connection->targetMapName());
|
void Editor::renderDivingConnections() {
|
||||||
|
for (auto item : diving_map_items.values())
|
||||||
|
item->updatePixmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::removeDivingMapPixmap(MapConnection *connection) {
|
void Editor::removeDivingMapPixmap(MapConnection *connection) {
|
||||||
|
@ -917,7 +902,7 @@ void Editor::removeDivingMapPixmap(MapConnection *connection) {
|
||||||
if (!diving_map_items.contains(direction))
|
if (!diving_map_items.contains(direction))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If the diving map being displayed is different than the one being removed we don't need to do anything.
|
// If the diving map being removed is different than the one that's currently displayed we don't need to do anything.
|
||||||
if (diving_map_items.value(direction)->connection() != connection)
|
if (diving_map_items.value(direction)->connection() != connection)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -927,11 +912,6 @@ void Editor::removeDivingMapPixmap(MapConnection *connection) {
|
||||||
pixmapItem->scene()->removeItem(pixmapItem);
|
pixmapItem->scene()->removeItem(pixmapItem);
|
||||||
delete pixmapItem;
|
delete pixmapItem;
|
||||||
|
|
||||||
// Clear map name from combo box
|
|
||||||
auto comboBox = (direction == "dive") ? ui->comboBox_DiveMap : ui->comboBox_EmergeMap;
|
|
||||||
const QSignalBlocker blocker(comboBox);
|
|
||||||
comboBox->setCurrentText("");
|
|
||||||
|
|
||||||
// Reveal any previously-hidden connection (because we only ever display one diving map of each type).
|
// Reveal any previously-hidden connection (because we only ever display one diving map of each type).
|
||||||
// Note: When this occurs as a result of the user clicking the 'X' clear button it seems the QComboBox
|
// Note: When this occurs as a result of the user clicking the 'X' clear button it seems the QComboBox
|
||||||
// doesn't expect the line edit to be immediately repopulated, and the 'X' doesn't reappear.
|
// doesn't expect the line edit to be immediately repopulated, and the 'X' doesn't reappear.
|
||||||
|
@ -942,6 +922,7 @@ void Editor::removeDivingMapPixmap(MapConnection *connection) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
updateDivingMapsVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::updateDiveMap(QString mapName) {
|
void Editor::updateDiveMap(QString mapName) {
|
||||||
|
@ -953,27 +934,24 @@ void Editor::updateEmergeMap(QString mapName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::setDivingMapName(QString mapName, QString direction) {
|
void Editor::setDivingMapName(QString mapName, QString direction) {
|
||||||
// Only the first Dive/Emerge map (if present) is considered, as in-game.
|
auto pixmapItem = diving_map_items.value(direction);
|
||||||
MapConnection* connection = nullptr;
|
MapConnection *connection = pixmapItem ? pixmapItem->connection() : nullptr;
|
||||||
for (auto i : map->getConnections()) {
|
|
||||||
if (i->direction() == direction) {
|
|
||||||
connection = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// TODO: Test edit history
|
||||||
if (connection) {
|
if (connection) {
|
||||||
|
if (mapName == connection->targetMapName())
|
||||||
|
return; // No change
|
||||||
|
|
||||||
// Update existing connection
|
// Update existing connection
|
||||||
if (mapName.isEmpty()) {
|
if (mapName.isEmpty()) {
|
||||||
removeConnection(connection);
|
removeConnection(connection);
|
||||||
} else {
|
} else {
|
||||||
connection->setTargetMapName(mapName);
|
map->editHistory.push(new MapConnectionChangeMap(connection, mapName));
|
||||||
}
|
}
|
||||||
} else if (!mapName.isEmpty()) {
|
} else if (!mapName.isEmpty()) {
|
||||||
// Create new connection
|
// Create new connection
|
||||||
addConnection(new MapConnection(mapName, direction));
|
addConnection(new MapConnection(mapName, direction));
|
||||||
}
|
}
|
||||||
updateDivingMapsVisibility();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::updateDivingMapsVisibility() {
|
void Editor::updateDivingMapsVisibility() {
|
||||||
|
@ -994,58 +972,36 @@ void Editor::updateDivingMapsVisibility() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QPoint Editor::calculateConnectionPosition(MapConnection *connection, const QPixmap &pixmap) {
|
// Get the 'origin' point for the connection's pixmap, i.e. where it should be positioned in the editor when connection->offset() == 0.
|
||||||
|
// This differs depending on the connection's direction and the dimensions of its target map or parent map.
|
||||||
|
QPoint Editor::getConnectionOrigin(MapConnection *connection) {
|
||||||
|
if (!connection)
|
||||||
|
return QPoint(0, 0);
|
||||||
|
|
||||||
|
Map *parentMap = connection->parentMap();
|
||||||
|
Map *targetMap = connection->targetMap();
|
||||||
const QString direction = connection->direction();
|
const QString direction = connection->direction();
|
||||||
int offset = connection->offset();
|
|
||||||
int x = 0, y = 0;
|
int x = 0, y = 0;
|
||||||
const int mWidth = 16, mHeight = 16;
|
|
||||||
if (direction == "up") {
|
if (direction == "right") {
|
||||||
x = offset * mWidth;
|
if (parentMap) x = parentMap->getWidth();
|
||||||
y = -pixmap.height();
|
|
||||||
} else if (direction == "down") {
|
} else if (direction == "down") {
|
||||||
x = offset * mWidth;
|
if (parentMap) y = parentMap->getHeight();
|
||||||
y = map->getHeight() * mHeight;
|
|
||||||
} else if (direction == "left") {
|
} else if (direction == "left") {
|
||||||
x = -pixmap.width();
|
if (targetMap) x = -targetMap->getConnectionRect(direction).width();
|
||||||
y = offset * mHeight;
|
} else if (direction == "up") {
|
||||||
} else if (direction == "right") {
|
if (targetMap) y = -targetMap->getConnectionRect(direction).height();
|
||||||
x = map->getWidth() * mWidth;
|
|
||||||
y = offset * mHeight;
|
|
||||||
}
|
}
|
||||||
return QPoint(x, y);
|
return QPoint(x * 16, y * 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::updateConnectionPixmap(ConnectionPixmapItem* pixmapItem) {
|
void Editor::updateConnectionPixmap(ConnectionPixmapItem* pixmapItem) {
|
||||||
if (!pixmapItem || !pixmapItem->connection)
|
if (!pixmapItem)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pixmapItem->initialOffset = pixmapItem->connection->offset();
|
pixmapItem->setOrigin(getConnectionOrigin(pixmapItem->connection));
|
||||||
pixmapItem->basePixmap = pixmapItem->connection->getPixmap();
|
pixmapItem->render(true); // Full render to reflect map changes
|
||||||
QPoint pos = calculateConnectionPosition(pixmapItem->connection, pixmapItem->basePixmap);
|
|
||||||
|
|
||||||
const QSignalBlocker blocker(pixmapItem);
|
|
||||||
pixmapItem->setPixmap(pixmapItem->basePixmap);
|
|
||||||
pixmapItem->initialX = pos.x();
|
|
||||||
pixmapItem->initialY = pos.y();
|
|
||||||
pixmapItem->setPos(pos);
|
|
||||||
pixmapItem->render();
|
|
||||||
|
|
||||||
maskNonVisibleConnectionTiles();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Editor::updateConnectionPixmapPos(ConnectionPixmapItem* pixmapItem) {
|
|
||||||
if (!pixmapItem || !pixmapItem->connection)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const QSignalBlocker blocker(pixmapItem);
|
|
||||||
MapConnection *connection = pixmapItem->connection;
|
|
||||||
if (MapConnection::isVertical(connection->direction())) {
|
|
||||||
qreal x = pixmapItem->initialX + (connection->offset() - pixmapItem->initialOffset) * 16;
|
|
||||||
if (x != pixmapItem->x()) pixmapItem->setX(x);
|
|
||||||
} else if (MapConnection::isHorizontal(connection->direction())) {
|
|
||||||
qreal y = pixmapItem->initialY + (connection->offset() - pixmapItem->initialOffset) * 16;
|
|
||||||
if (y != pixmapItem->y()) pixmapItem->setY(y);
|
|
||||||
}
|
|
||||||
maskNonVisibleConnectionTiles();
|
maskNonVisibleConnectionTiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1257,9 +1213,14 @@ bool Editor::setMap(QString map_name) {
|
||||||
// disconnect previous map's signals so they are not firing
|
// disconnect previous map's signals so they are not firing
|
||||||
// multiple times if set again in the future
|
// multiple times if set again in the future
|
||||||
if (map) {
|
if (map) {
|
||||||
|
map->pruneEditHistory();
|
||||||
map->disconnect(this);
|
map->disconnect(this);
|
||||||
for (auto connection : map->getConnections())
|
for (auto connection : map->getConnections()) {
|
||||||
connection->disconnect();
|
// Disconnect signals used by the display
|
||||||
|
QObject::disconnect(connection, &MapConnection::targetMapNameChanged, nullptr, nullptr);
|
||||||
|
QObject::disconnect(connection, &MapConnection::directionChanged, nullptr, nullptr);
|
||||||
|
QObject::disconnect(connection, &MapConnection::offsetChanged, nullptr, nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (project) {
|
if (project) {
|
||||||
|
@ -1777,19 +1738,20 @@ void Editor::clearMapConnections() {
|
||||||
}
|
}
|
||||||
diving_map_items.clear();
|
diving_map_items.clear();
|
||||||
|
|
||||||
|
// Reset to single opacity slider
|
||||||
|
ui->stackedWidget_DiveMapOpacity->setCurrentIndex(1);
|
||||||
|
|
||||||
selected_connection_item = nullptr;
|
selected_connection_item = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::displayMapConnections() {
|
void Editor::displayMapConnections() {
|
||||||
clearMapConnections();
|
clearMapConnections();
|
||||||
|
|
||||||
for (MapConnection *connection : map->getConnections())
|
for (auto connection : map->getConnections())
|
||||||
displayConnection(connection);
|
displayConnection(connection);
|
||||||
|
|
||||||
if (!connection_items.isEmpty())
|
if (!connection_items.isEmpty())
|
||||||
setSelectedConnectionItem(connection_items.first());
|
setSelectedConnectionItem(connection_items.first());
|
||||||
|
|
||||||
updateDivingMapsVisibility();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::clearConnectionMask() {
|
void Editor::clearConnectionMask() {
|
||||||
|
@ -1859,16 +1821,13 @@ void Editor::updateMapBorder() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::updateMapConnections() {
|
void Editor::updateMapConnections() {
|
||||||
for (auto item : connection_items) {
|
for (auto item : connection_items)
|
||||||
if (!item->connection)
|
item->render(true);
|
||||||
continue;
|
|
||||||
item->basePixmap = item->connection->getPixmap();
|
|
||||||
item->render();
|
|
||||||
}
|
|
||||||
|
|
||||||
maskNonVisibleConnectionTiles();
|
maskNonVisibleConnectionTiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Check first condition, move to Map
|
||||||
int Editor::getBorderDrawDistance(int dimension) {
|
int Editor::getBorderDrawDistance(int dimension) {
|
||||||
// Draw sufficient border blocks to fill the player's view (BORDER_DISTANCE)
|
// Draw sufficient border blocks to fill the player's view (BORDER_DISTANCE)
|
||||||
if (dimension >= BORDER_DISTANCE) {
|
if (dimension >= BORDER_DISTANCE) {
|
||||||
|
|
|
@ -2306,7 +2306,7 @@ void MainWindow::setDivingMapsVisible(bool visible) {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
// We skip rendering diving maps if this setting is not enabled,
|
// We skip rendering diving maps if this setting is not enabled,
|
||||||
// so when we enable it we need to make sure they've rendered.
|
// so when we enable it we need to make sure they've rendered.
|
||||||
this->editor->displayDivingConnections();
|
this->editor->renderDivingConnections();
|
||||||
}
|
}
|
||||||
this->editor->updateDivingMapsVisibility();
|
this->editor->updateDivingMapsVisibility();
|
||||||
}
|
}
|
||||||
|
@ -2662,14 +2662,12 @@ void MainWindow::showExportMapImageWindow(ImageExporterMode mode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_pushButton_AddConnection_clicked() {
|
void MainWindow::on_pushButton_AddConnection_clicked() {
|
||||||
if (!this->editor || !this->editor->map)
|
if (!this->editor || !this->editor->map || !this->editor->project)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto dialog = new NewMapConnectionDialog(this, this->editor->map, this->editor->project->mapNames);
|
auto dialog = new NewMapConnectionDialog(this, this->editor->map, this->editor->project->mapNames);
|
||||||
if (dialog->exec() == QDialog::Accepted) {
|
connect(dialog, &NewMapConnectionDialog::accepted, this->editor, &Editor::addConnection);
|
||||||
this->editor->addConnection(dialog->result);
|
dialog->exec();
|
||||||
this->editor->setSelectedConnection(dialog->result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_pushButton_NewWildMonGroup_clicked() {
|
void MainWindow::on_pushButton_NewWildMonGroup_clicked() {
|
||||||
|
|
|
@ -1,8 +1,27 @@
|
||||||
#include "connectionpixmapitem.h"
|
#include "connectionpixmapitem.h"
|
||||||
|
#include "editcommands.h"
|
||||||
|
#include "map.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
void ConnectionPixmapItem::render() {
|
ConnectionPixmapItem::ConnectionPixmapItem(MapConnection* connection, int x, int y)
|
||||||
|
: QGraphicsPixmapItem(connection->getPixmap()),
|
||||||
|
connection(connection)
|
||||||
|
{
|
||||||
|
this->setEditable(true);
|
||||||
|
this->basePixmap = pixmap();
|
||||||
|
this->setOrigin(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionPixmapItem::ConnectionPixmapItem(MapConnection* connection, QPoint pos)
|
||||||
|
: ConnectionPixmapItem(connection, pos.x(), pos.y())
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Render additional visual effects on top of the base map image.
|
||||||
|
void ConnectionPixmapItem::render(bool ignoreCache) {
|
||||||
|
if (ignoreCache)
|
||||||
|
this->basePixmap = this->connection->getPixmap();
|
||||||
|
|
||||||
QPixmap pixmap = this->basePixmap.copy(0, 0, this->basePixmap.width(), this->basePixmap.height());
|
QPixmap pixmap = this->basePixmap.copy(0, 0, this->basePixmap.width(), this->basePixmap.height());
|
||||||
this->setZValue(-1);
|
this->setZValue(-1);
|
||||||
|
|
||||||
|
@ -31,27 +50,23 @@ QVariant ConnectionPixmapItem::itemChange(GraphicsItemChange change, const QVari
|
||||||
if (change == ItemPositionChange) {
|
if (change == ItemPositionChange) {
|
||||||
QPointF newPos = value.toPointF();
|
QPointF newPos = value.toPointF();
|
||||||
|
|
||||||
qreal x, y;
|
qreal x = this->originX;
|
||||||
int newOffset = this->initialOffset;
|
qreal y = this->originY;
|
||||||
|
int newOffset = this->connection->offset();
|
||||||
|
|
||||||
|
// Restrict movement to the metatile grid and perpendicular to the connection direction.
|
||||||
if (MapConnection::isVertical(this->connection->direction())) {
|
if (MapConnection::isVertical(this->connection->direction())) {
|
||||||
x = round(newPos.x() / 16) * 16;
|
x = (round(newPos.x() / this->mWidth) * this->mWidth) - this->originX;
|
||||||
newOffset += (x - initialX) / 16;
|
newOffset = x / this->mWidth;
|
||||||
x = newOffset * 16;
|
} else if (MapConnection::isHorizontal(this->connection->direction())) {
|
||||||
}
|
y = (round(newPos.y() / this->mHeight) * this->mHeight) - this->originY;
|
||||||
else {
|
newOffset = y / this->mHeight;
|
||||||
x = this->initialX;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MapConnection::isHorizontal(this->connection->direction())) {
|
// This is convoluted because of how our edit history works; this would otherwise just be 'this->connection->setOffset(newOffset);'
|
||||||
y = round(newPos.y() / 16) * 16;
|
if (this->connection->parentMap() && newOffset != this->connection->offset())
|
||||||
newOffset += (y - this->initialY) / 16;
|
this->connection->parentMap()->editHistory.push(new MapConnectionMove(this->connection, newOffset, this->actionId));
|
||||||
y = newOffset * 16;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
y = this->initialY;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->connection->setOffset(newOffset);
|
|
||||||
return QPointF(x, y);
|
return QPointF(x, y);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -59,6 +74,32 @@ QVariant ConnectionPixmapItem::itemChange(GraphicsItemChange change, const QVari
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If connection->offset changed externally we call this to correct our position.
|
||||||
|
void ConnectionPixmapItem::updatePos() {
|
||||||
|
const QSignalBlocker blocker(this);
|
||||||
|
|
||||||
|
qreal x = this->originX;
|
||||||
|
qreal y = this->originY;
|
||||||
|
|
||||||
|
if (MapConnection::isVertical(this->connection->direction())) {
|
||||||
|
x += this->connection->offset() * this->mWidth;
|
||||||
|
} else if (MapConnection::isHorizontal(this->connection->direction())) {
|
||||||
|
y += this->connection->offset() * this->mHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->setPos(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the pixmap's external origin point, i.e. the pixmap's position when connection->offset == 0
|
||||||
|
void ConnectionPixmapItem::setOrigin(int x, int y) {
|
||||||
|
this->originX = x;
|
||||||
|
this->originY = y;
|
||||||
|
updatePos();
|
||||||
|
}
|
||||||
|
void ConnectionPixmapItem::setOrigin(QPoint pos) {
|
||||||
|
this->setOrigin(pos.x(), pos.y());
|
||||||
|
}
|
||||||
|
|
||||||
void ConnectionPixmapItem::setEditable(bool editable) {
|
void ConnectionPixmapItem::setEditable(bool editable) {
|
||||||
setFlag(ItemIsMovable, editable);
|
setFlag(ItemIsMovable, editable);
|
||||||
setFlag(ItemSendsGeometryChanges, editable);
|
setFlag(ItemSendsGeometryChanges, editable);
|
||||||
|
@ -82,6 +123,11 @@ void ConnectionPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *) {
|
||||||
this->setSelected(true);
|
this->setSelected(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConnectionPixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
|
||||||
|
this->actionId++; // Distinguish between move actions for the edit history
|
||||||
|
QGraphicsPixmapItem::mouseReleaseEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
void ConnectionPixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) {
|
void ConnectionPixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) {
|
||||||
emit connectionItemDoubleClicked(this->connection);
|
emit connectionItemDoubleClicked(this->connection);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
#include "connectionslistitem.h"
|
#include "connectionslistitem.h"
|
||||||
#include "ui_connectionslistitem.h"
|
#include "ui_connectionslistitem.h"
|
||||||
|
#include "editcommands.h"
|
||||||
|
#include "map.h"
|
||||||
|
|
||||||
|
#include <QLineEdit>
|
||||||
|
|
||||||
ConnectionsListItem::ConnectionsListItem(QWidget *parent, MapConnection * connection, const QStringList &mapNames) :
|
ConnectionsListItem::ConnectionsListItem(QWidget *parent, MapConnection * connection, const QStringList &mapNames) :
|
||||||
QFrame(parent),
|
QFrame(parent),
|
||||||
|
@ -18,11 +22,23 @@ ConnectionsListItem::ConnectionsListItem(QWidget *parent, MapConnection * connec
|
||||||
ui->comboBox_Map->setMinimumContentsLength(6);
|
ui->comboBox_Map->setMinimumContentsLength(6);
|
||||||
ui->comboBox_Map->addItems(mapNames);
|
ui->comboBox_Map->addItems(mapNames);
|
||||||
ui->comboBox_Map->setFocusedScrollingEnabled(false); // Scrolling could cause rapid changes to many different maps
|
ui->comboBox_Map->setFocusedScrollingEnabled(false); // Scrolling could cause rapid changes to many different maps
|
||||||
|
ui->comboBox_Map->setInsertPolicy(QComboBox::NoInsert);
|
||||||
|
|
||||||
ui->spinBox_Offset->setMinimum(INT_MIN);
|
ui->spinBox_Offset->setMinimum(INT_MIN);
|
||||||
ui->spinBox_Offset->setMaximum(INT_MAX);
|
ui->spinBox_Offset->setMaximum(INT_MAX);
|
||||||
|
|
||||||
|
// Invalid map names are not considered a change. If editing finishes with an invalid name, restore the previous name.
|
||||||
|
connect(ui->comboBox_Map->lineEdit(), &QLineEdit::editingFinished, [this] {
|
||||||
|
const QSignalBlocker blocker(ui->comboBox_Map);
|
||||||
|
if (ui->comboBox_Map->findText(ui->comboBox_Map->currentText()) < 0)
|
||||||
|
ui->comboBox_Map->setTextItem(this->connection->targetMapName());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Distinguish between move actions for the edit history
|
||||||
|
connect(ui->spinBox_Offset, &QSpinBox::editingFinished, [this] { this->actionId++; });
|
||||||
|
|
||||||
this->connection = connection;
|
this->connection = connection;
|
||||||
|
this->map = connection->parentMap();
|
||||||
this->updateUI();
|
this->updateUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +48,9 @@ ConnectionsListItem::~ConnectionsListItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionsListItem::updateUI() {
|
void ConnectionsListItem::updateUI() {
|
||||||
|
if (!this->connection)
|
||||||
|
return;
|
||||||
|
|
||||||
const QSignalBlocker blocker1(ui->comboBox_Direction);
|
const QSignalBlocker blocker1(ui->comboBox_Direction);
|
||||||
const QSignalBlocker blocker2(ui->comboBox_Map);
|
const QSignalBlocker blocker2(ui->comboBox_Map);
|
||||||
const QSignalBlocker blocker3(ui->spinBox_Offset);
|
const QSignalBlocker blocker3(ui->spinBox_Offset);
|
||||||
|
@ -56,26 +75,30 @@ void ConnectionsListItem::mousePressEvent(QMouseEvent *) {
|
||||||
this->setSelected(true);
|
this->setSelected(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This happens by accident a lot. Convert to button?
|
||||||
void ConnectionsListItem::mouseDoubleClickEvent(QMouseEvent *) {
|
void ConnectionsListItem::mouseDoubleClickEvent(QMouseEvent *) {
|
||||||
emit doubleClicked(this->connection);
|
emit doubleClicked(this->connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionsListItem::on_comboBox_Direction_currentTextChanged(const QString &direction) {
|
void ConnectionsListItem::on_comboBox_Direction_currentTextChanged(const QString &direction) {
|
||||||
this->setSelected(true);
|
this->setSelected(true);
|
||||||
this->connection->setDirection(direction);
|
if (this->map)
|
||||||
|
this->map->editHistory.push(new MapConnectionChangeDirection(this->connection, direction));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionsListItem::on_comboBox_Map_currentTextChanged(const QString &mapName) {
|
void ConnectionsListItem::on_comboBox_Map_currentTextChanged(const QString &mapName) {
|
||||||
this->setSelected(true);
|
this->setSelected(true);
|
||||||
if (ui->comboBox_Map->findText(mapName) >= 0)
|
if (this->map && ui->comboBox_Map->findText(mapName) >= 0)
|
||||||
this->connection->setTargetMapName(mapName);
|
this->map->editHistory.push(new MapConnectionChangeMap(this->connection, mapName));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionsListItem::on_spinBox_Offset_valueChanged(int offset) {
|
void ConnectionsListItem::on_spinBox_Offset_valueChanged(int offset) {
|
||||||
this->setSelected(true);
|
this->setSelected(true);
|
||||||
this->connection->setOffset(offset);
|
if (this->map)
|
||||||
|
this->map->editHistory.push(new MapConnectionMove(this->connection, offset, this->actionId));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionsListItem::on_button_Delete_clicked() {
|
void ConnectionsListItem::on_button_Delete_clicked() {
|
||||||
emit this->removed(this->connection);
|
if (this->map)
|
||||||
|
this->map->editHistory.push(new MapConnectionRemove(this->map, this->connection));
|
||||||
}
|
}
|
||||||
|
|
46
src/ui/divingmappixmapitem.cpp
Normal file
46
src/ui/divingmappixmapitem.cpp
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#include "divingmappixmapitem.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
DivingMapPixmapItem::DivingMapPixmapItem(MapConnection *connection, QComboBox *combo)
|
||||||
|
: QGraphicsPixmapItem(getBasePixmap(connection))
|
||||||
|
{
|
||||||
|
m_connection = connection;
|
||||||
|
m_combo = combo;
|
||||||
|
|
||||||
|
setComboText(connection->targetMapName());
|
||||||
|
|
||||||
|
// Update display if the connected map is swapped.
|
||||||
|
connect(m_connection, &MapConnection::targetMapNameChanged, this, &DivingMapPixmapItem::onTargetMapChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
DivingMapPixmapItem::~DivingMapPixmapItem() {
|
||||||
|
// Clear map name from combo box
|
||||||
|
setComboText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
QPixmap DivingMapPixmapItem::getBasePixmap(MapConnection* connection) {
|
||||||
|
if (!connection)
|
||||||
|
return QPixmap();
|
||||||
|
if (!porymapConfig.showDiveEmergeMaps)
|
||||||
|
return QPixmap(); // Save some rendering time if it won't be displayed
|
||||||
|
if (connection->targetMapName() == connection->parentMapName())
|
||||||
|
return QPixmap(); // If the map is connected to itself then rendering is pointless.
|
||||||
|
return connection->getPixmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivingMapPixmapItem::updatePixmap() {
|
||||||
|
setPixmap(getBasePixmap(m_connection));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivingMapPixmapItem::onTargetMapChanged() {
|
||||||
|
updatePixmap();
|
||||||
|
setComboText(m_connection->targetMapName());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivingMapPixmapItem::setComboText(const QString &text) {
|
||||||
|
if (!m_combo)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QSignalBlocker blocker(m_combo);
|
||||||
|
m_combo->setCurrentText(text);
|
||||||
|
}
|
|
@ -192,6 +192,12 @@ bool MapImageExporter::historyItemAppliesToFrame(const QUndoCommand *command) {
|
||||||
return this->showCollision;
|
return this->showCollision;
|
||||||
case CommandId::ID_PaintBorder:
|
case CommandId::ID_PaintBorder:
|
||||||
return this->showBorder;
|
return this->showBorder;
|
||||||
|
case CommandId::ID_MapConnectionMove:
|
||||||
|
case CommandId::ID_MapConnectionChangeDirection:
|
||||||
|
case CommandId::ID_MapConnectionChangeMap:
|
||||||
|
case CommandId::ID_MapConnectionAdd:
|
||||||
|
case CommandId::ID_MapConnectionRemove:
|
||||||
|
return this->showUpConnections || this->showDownConnections || this->showLeftConnections || this->showRightConnections;
|
||||||
case CommandId::ID_EventMove:
|
case CommandId::ID_EventMove:
|
||||||
case CommandId::ID_EventShift:
|
case CommandId::ID_EventShift:
|
||||||
case CommandId::ID_EventCreate:
|
case CommandId::ID_EventCreate:
|
||||||
|
@ -398,14 +404,15 @@ QPixmap MapImageExporter::getFormattedMapPixmap(Map *map, bool ignoreBorder) {
|
||||||
if (!this->mode) {
|
if (!this->mode) {
|
||||||
// if showing connections, draw on outside of image
|
// if showing connections, draw on outside of image
|
||||||
QPainter connectionPainter(&pixmap);
|
QPainter connectionPainter(&pixmap);
|
||||||
|
// TODO: Is this still the most sensible way to do this (esp. rendering pixmap)
|
||||||
for (auto connectionItem : editor->connection_items) {
|
for (auto connectionItem : editor->connection_items) {
|
||||||
const QString direction = connectionItem->connection->direction();
|
const QString direction = connectionItem->connection->direction();
|
||||||
if ((showUpConnections && direction == "up")
|
if ((showUpConnections && direction == "up")
|
||||||
|| (showDownConnections && direction == "down")
|
|| (showDownConnections && direction == "down")
|
||||||
|| (showLeftConnections && direction == "left")
|
|| (showLeftConnections && direction == "left")
|
||||||
|| (showRightConnections && direction == "right"))
|
|| (showRightConnections && direction == "right"))
|
||||||
connectionPainter.drawImage(connectionItem->initialX + borderWidth, connectionItem->initialY + borderHeight,
|
connectionPainter.drawImage(connectionItem->x() + borderWidth, connectionItem->y() + borderHeight,
|
||||||
connectionItem->basePixmap.toImage());
|
connectionItem->connection->getPixmap().toImage());
|
||||||
}
|
}
|
||||||
connectionPainter.end();
|
connectionPainter.end();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,14 +8,13 @@ NewMapConnectionDialog::NewMapConnectionDialog(QWidget *parent, Map* map, const
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
||||||
this->result = nullptr;
|
|
||||||
|
|
||||||
ui->comboBox_Direction->setEditable(false);
|
ui->comboBox_Direction->setEditable(false);
|
||||||
ui->comboBox_Direction->setMinimumContentsLength(0);
|
ui->comboBox_Direction->setMinimumContentsLength(0);
|
||||||
ui->comboBox_Direction->addItems(MapConnection::cardinalDirections);
|
ui->comboBox_Direction->addItems(MapConnection::cardinalDirections);
|
||||||
|
|
||||||
ui->comboBox_Map->setMinimumContentsLength(6);
|
ui->comboBox_Map->setMinimumContentsLength(6);
|
||||||
ui->comboBox_Map->addItems(mapNames);
|
ui->comboBox_Map->addItems(mapNames);
|
||||||
|
ui->comboBox_Map->setInsertPolicy(QComboBox::NoInsert);
|
||||||
|
|
||||||
// Choose default direction
|
// Choose default direction
|
||||||
QMap<QString, int> directionCounts;
|
QMap<QString, int> directionCounts;
|
||||||
|
@ -51,6 +50,11 @@ NewMapConnectionDialog::~NewMapConnectionDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
void NewMapConnectionDialog::accept() {
|
void NewMapConnectionDialog::accept() {
|
||||||
this->result = new MapConnection(ui->comboBox_Map->currentText(), ui->comboBox_Direction->currentText());
|
// Invalid map names are not allowed
|
||||||
|
if (ui->comboBox_Map->findText(ui->comboBox_Map->currentText()) < 0) {
|
||||||
|
// TODO: Display error message
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emit accepted(new MapConnection(ui->comboBox_Map->currentText(), ui->comboBox_Direction->currentText()));
|
||||||
QDialog::accept();
|
QDialog::accept();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue