Merge branch 'master' of https://github.com/huderlem/porymap into slam

This commit is contained in:
garak
2024-09-24 11:31:06 -04:00
84 changed files with 4880 additions and 3019 deletions

View File

@@ -17,11 +17,9 @@ Map::Map(QObject *parent) : QObject(parent)
}
Map::~Map() {
// delete all associated events
while (!ownedEvents.isEmpty()) {
Event *last = ownedEvents.takeLast();
if (last) delete last;
}
qDeleteAll(ownedEvents);
ownedEvents.clear();
deleteConnections();
}
void Map::setName(QString mapName) {
@@ -69,40 +67,47 @@ int Map::getBorderHeight() {
return layout->getBorderHeight();
}
QPixmap Map::renderConnection(MapConnection connection, Layout * fromLayout) {
int x, y, w, h;
if (connection.direction == "up") {
x = 0;
y = getHeight() - BORDER_DISTANCE;
w = getWidth();
h = BORDER_DISTANCE;
} else if (connection.direction == "down") {
x = 0;
y = 0;
w = getWidth();
h = BORDER_DISTANCE;
} else if (connection.direction == "left") {
x = getWidth() - BORDER_DISTANCE;
y = 0;
w = BORDER_DISTANCE;
h = getHeight();
} else if (connection.direction == "right") {
x = 0;
y = 0;
w = BORDER_DISTANCE;
h = getHeight();
} else {
// this should not happen
x = 0;
y = 0;
w = getWidth();
h = getHeight();
}
// Get the portion of the map that can be rendered when rendered as a map connection.
// Cardinal connections render the nearest segment of their map and within the bounds of the border draw distance,
// Dive/Emerge connections are rendered normally within the bounds of their parent map.
QRect Map::getConnectionRect(const QString &direction, Layout * fromLayout) {
int x = 0, y = 0;
int w = getWidth(), h = getHeight();
//render(true, fromLayout, QRect(x, y, w, h));
//QImage connection_image = image.copy(x * 16, y * 16, w * 16, h * 16);
return this->layout->render(true, fromLayout, QRect(x, y, w, h)).copy(x * 16, y * 16, w * 16, h * 16);
//return QPixmap::fromImage(connection_image);
if (direction == "up") {
h = qMin(h, BORDER_DISTANCE);
y = getHeight() - h;
} else if (direction == "down") {
h = qMin(h, BORDER_DISTANCE);
} else if (direction == "left") {
w = qMin(w, BORDER_DISTANCE);
x = getWidth() - w;
} else if (direction == "right") {
w = qMin(w, BORDER_DISTANCE);
} else if (MapConnection::isDiving(direction)) {
if (fromLayout) {
w = qMin(w, fromLayout->getWidth());
h = qMin(h, fromLayout->getHeight());
}
} else {
// Unknown direction
return QRect();
}
return QRect(x, y, w, h);
}
QPixmap Map::renderConnection(const QString &direction, Layout * fromLayout) {
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;
QPixmap connectionPixmap = this->layout->render(true, fromLayout, bounds);
return connectionPixmap.copy(bounds.x() * 16, bounds.y() * 16, bounds.width() * 16, bounds.height() * 16);
}
void Map::openScript(QString label) {
@@ -153,9 +158,9 @@ QStringList Map::getScriptLabels(Event::Group group) {
}
QString Map::getScriptsFilePath() const {
const bool usePoryscript = projectConfig.getUsePoryScript();
const bool usePoryscript = projectConfig.usePoryScript;
auto path = QDir::cleanPath(QString("%1/%2/%3/scripts")
.arg(projectConfig.getProjectDir())
.arg(projectConfig.projectDir)
.arg(projectConfig.getFilePath(ProjectFilePath::data_map_folders))
.arg(this->name));
auto extension = Project::getScriptFileExtension(usePoryscript);
@@ -177,6 +182,72 @@ void Map::addEvent(Event *event) {
if (!ownedEvents.contains(event)) ownedEvents.append(event);
}
void Map::deleteConnections() {
qDeleteAll(this->ownedConnections);
this->ownedConnections.clear();
this->connections.clear();
}
QList<MapConnection*> Map::getConnections() const {
return this->connections;
}
void Map::addConnection(MapConnection *connection) {
if (!connection || this->connections.contains(connection))
return;
// 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())) {
for (auto i : this->connections) {
if (i->direction() == connection->direction()) {
trackConnection(connection);
return;
}
}
}
loadConnection(connection);
modify();
emit connectionAdded(connection);
return;
}
void Map::loadConnection(MapConnection *connection) {
if (!connection)
return;
if (!this->connections.contains(connection))
this->connections.append(connection);
trackConnection(connection);
}
void Map::trackConnection(MapConnection *connection) {
connection->setParentMap(this, false);
if (!this->ownedConnections.contains(connection)) {
this->ownedConnections.insert(connection);
connect(connection, &MapConnection::parentMapChanged, [=](Map *, Map *after) {
if (after != this && after != nullptr) {
// MapConnection's parent has been reassigned, it's no longer our responsibility
this->ownedConnections.remove(connection);
QObject::disconnect(connection, &MapConnection::parentMapChanged, this, nullptr);
}
});
}
}
// We retain ownership of this MapConnection until it's assigned to a new parent map.
void Map::removeConnection(MapConnection *connection) {
if (!this->connections.removeOne(connection))
return;
connection->setParentMap(nullptr, false);
modify();
emit connectionRemoved(connection);
}
void Map::modify() {
emit modified();
}
@@ -188,3 +259,24 @@ void Map::clean() {
bool Map::hasUnsavedChanges() {
return !editHistory.isClean() || !this->layout->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);
}
}