mirror of
https://github.com/huderlem/porymap.git
synced 2026-09-26 09:56:32 -05:00
Fix some problems with layout directory creation
This commit is contained in:
@@ -67,12 +67,10 @@ public:
|
||||
QString sharedEventsMap() const { return m_sharedEventsMap; }
|
||||
QString sharedScriptsMap() const { return m_sharedScriptsMap; }
|
||||
|
||||
void setNeedsLayoutDir(bool needsLayoutDir) { m_needsLayoutDir = needsLayoutDir; }
|
||||
void setNeedsHealLocation(bool needsHealLocation) { m_needsHealLocation = needsHealLocation; }
|
||||
void setIsPersistedToFile(bool persistedToFile) { m_isPersistedToFile = persistedToFile; }
|
||||
void setHasUnsavedDataChanges(bool unsavedDataChanges) { m_hasUnsavedDataChanges = unsavedDataChanges; }
|
||||
|
||||
bool needsLayoutDir() const { return m_needsLayoutDir; }
|
||||
bool needsHealLocation() const { return m_needsHealLocation; }
|
||||
bool isPersistedToFile() const { return m_isPersistedToFile; }
|
||||
bool hasUnsavedDataChanges() const { return m_hasUnsavedDataChanges; }
|
||||
@@ -121,7 +119,6 @@ private:
|
||||
|
||||
bool m_isPersistedToFile = true;
|
||||
bool m_hasUnsavedDataChanges = false;
|
||||
bool m_needsLayoutDir = true;
|
||||
bool m_needsHealLocation = false;
|
||||
bool m_scriptsLoaded = false;
|
||||
|
||||
|
||||
@@ -22,8 +22,9 @@ public:
|
||||
Layout() {}
|
||||
Layout(const Layout &other);
|
||||
|
||||
static QString layoutNameFromMapName(const QString &mapName);
|
||||
static QString layoutConstantFromName(QString mapName);
|
||||
static QString defaultSuffix();
|
||||
|
||||
|
||||
bool loaded = false;
|
||||
|
||||
@@ -77,6 +78,9 @@ public:
|
||||
struct Settings {
|
||||
QString id;
|
||||
QString name;
|
||||
// The name of a new layout's folder in `data/layouts/` is not always the same as the layout's name
|
||||
// (e.g. the majority of the default layouts use the name of their associated map).
|
||||
QString folderName;
|
||||
int width;
|
||||
int height;
|
||||
int borderWidth;
|
||||
|
||||
@@ -40,7 +40,6 @@ private:
|
||||
|
||||
void refresh();
|
||||
void saveSettings();
|
||||
void setLayout(const Layout *mapLayout);
|
||||
|
||||
private slots:
|
||||
void dialogButtonClicked(QAbstractButton *button);
|
||||
|
||||
@@ -32,8 +32,8 @@ void Layout::copyFrom(const Layout *other) {
|
||||
this->border = other->border;
|
||||
}
|
||||
|
||||
QString Layout::layoutNameFromMapName(const QString &mapName) {
|
||||
return QString("%1_Layout").arg(mapName);
|
||||
QString Layout::defaultSuffix() {
|
||||
return "_Layout";
|
||||
}
|
||||
|
||||
QString Layout::layoutConstantFromName(QString mapName) {
|
||||
|
||||
@@ -1382,7 +1382,9 @@ void MainWindow::mapListAddArea() {
|
||||
void MainWindow::onNewMapCreated(Map *newMap, const QString &groupName) {
|
||||
logInfo(QString("Created a new map named %1.").arg(newMap->name()));
|
||||
|
||||
// TODO: Creating a new map shouldn't be automatically saved
|
||||
// TODO: Creating a new map shouldn't be automatically saved.
|
||||
// For one, it takes away the option to discard the new map.
|
||||
// For two, if the new map uses an existing layout, any unsaved changes to that layout will also be saved.
|
||||
editor->project->saveMap(newMap);
|
||||
editor->project->saveAllDataStructures();
|
||||
|
||||
|
||||
@@ -382,15 +382,17 @@ Map *Project::createNewMap(const Project::NewMapSettings &settings, const Map* t
|
||||
map->setConstantName(mapConstant);
|
||||
|
||||
Layout *layout = this->mapLayouts.value(settings.layout.id);
|
||||
if (layout) {
|
||||
// Layout already exists
|
||||
map->setNeedsLayoutDir(false); // TODO: Remove this member?
|
||||
} else {
|
||||
layout = createNewLayout(settings.layout, toDuplicate ? toDuplicate->layout() : nullptr);
|
||||
}
|
||||
if (!layout) {
|
||||
delete map;
|
||||
return nullptr;
|
||||
// Layout doesn't already exist, create it.
|
||||
layout = createNewLayout(settings.layout, toDuplicate ? toDuplicate->layout() : nullptr);
|
||||
if (!layout) {
|
||||
// Layout creation failed.
|
||||
delete map;
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
// This layout already exists. Make sure it's loaded.
|
||||
loadLayout(layout);
|
||||
}
|
||||
map->setLayout(layout);
|
||||
|
||||
@@ -444,14 +446,17 @@ Layout *Project::createNewLayout(const Layout::Settings &settings, const Layout
|
||||
layout->tileset_primary_label = settings.primaryTilesetLabel;
|
||||
layout->tileset_secondary_label = settings.secondaryTilesetLabel;
|
||||
|
||||
const QString basePath = projectConfig.getFilePath(ProjectFilePath::data_layouts_folders);
|
||||
layout->border_path = QString("%1%2/border.bin").arg(basePath, layout->name);
|
||||
layout->blockdata_path = QString("%1%2/map.bin").arg(basePath, layout->name);
|
||||
// If a special folder name was specified (as in the case when we're creating a layout for a new map) then use that name.
|
||||
// Otherwise the new layout's folder name will just be the layout's name.
|
||||
const QString folderName = !settings.folderName.isEmpty() ? settings.folderName : layout->name;
|
||||
const QString folderPath = projectConfig.getFilePath(ProjectFilePath::data_layouts_folders) + folderName;
|
||||
layout->border_path = folderPath + "/border.bin";
|
||||
layout->blockdata_path = folderPath + "/map.bin";
|
||||
|
||||
// Create a new directory for the layout
|
||||
QString newLayoutDir = QString(root + "/%1%2").arg(projectConfig.getFilePath(ProjectFilePath::data_layouts_folders), layout->name);
|
||||
if (!QDir::root().mkdir(newLayoutDir)) {
|
||||
logError(QString("Error: failed to create directory for new layout: '%1'").arg(newLayoutDir));
|
||||
// Create a new directory for the layout, if it doesn't already exist.
|
||||
const QString fullPath = QString("%1/%2").arg(this->root).arg(folderPath);
|
||||
if (!QDir::root().mkpath(fullPath)) {
|
||||
logError(QString("Failed to create directory for new layout: '%1'").arg(fullPath));
|
||||
delete layout;
|
||||
return nullptr;
|
||||
}
|
||||
@@ -493,14 +498,14 @@ bool Project::loadLayout(Layout *layout) {
|
||||
}
|
||||
|
||||
Layout *Project::loadLayout(QString layoutId) {
|
||||
if (mapLayouts.contains(layoutId)) {
|
||||
Layout *layout = mapLayouts[layoutId];
|
||||
if (this->mapLayouts.contains(layoutId)) {
|
||||
Layout *layout = this->mapLayouts[layoutId];
|
||||
if (loadLayout(layout)) {
|
||||
return layout;
|
||||
}
|
||||
}
|
||||
|
||||
logError(QString("Error: Failed to load layout '%1'").arg(layoutId));
|
||||
logError(QString("Failed to load layout '%1'").arg(layoutId));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -509,10 +514,10 @@ bool Project::loadMapLayout(Map* map) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mapLayouts.contains(map->layoutId())) {
|
||||
map->setLayout(mapLayouts[map->layoutId()]);
|
||||
if (this->mapLayouts.contains(map->layoutId())) {
|
||||
map->setLayout(this->mapLayouts[map->layoutId()]);
|
||||
} else {
|
||||
logError(QString("Error: Map '%1' has an unknown layout '%2'").arg(map->name()).arg(map->layoutId()));
|
||||
logError(QString("Map '%1' has an unknown layout '%2'").arg(map->name()).arg(map->layoutId()));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -535,8 +540,8 @@ void Project::clearMapLayouts() {
|
||||
bool Project::readMapLayouts() {
|
||||
clearMapLayouts();
|
||||
|
||||
QString layoutsFilepath = projectConfig.getFilePath(ProjectFilePath::json_layouts);
|
||||
QString fullFilepath = QString("%1/%2").arg(root).arg(layoutsFilepath);
|
||||
const QString layoutsFilepath = projectConfig.getFilePath(ProjectFilePath::json_layouts);
|
||||
const QString fullFilepath = QString("%1/%2").arg(this->root).arg(layoutsFilepath);
|
||||
fileWatcher.addPath(fullFilepath);
|
||||
QJsonDocument layoutsDoc;
|
||||
if (!parser.tryParseJsonFile(&layoutsDoc, fullFilepath)) {
|
||||
@@ -1295,40 +1300,32 @@ void Project::saveAllMaps() {
|
||||
|
||||
void Project::saveMap(Map *map) {
|
||||
// Create/Modify a few collateral files for brand new maps.
|
||||
QString basePath = projectConfig.getFilePath(ProjectFilePath::data_map_folders);
|
||||
QString mapDataDir = root + "/" + basePath + map->name();
|
||||
const QString folderPath = projectConfig.getFilePath(ProjectFilePath::data_map_folders) + map->name();
|
||||
const QString fullPath = QString("%1/%2").arg(this->root).arg(folderPath);
|
||||
if (!map->isPersistedToFile()) {
|
||||
if (!QDir::root().mkdir(mapDataDir)) {
|
||||
logError(QString("Error: failed to create directory for new map: '%1'").arg(mapDataDir));
|
||||
if (!QDir::root().mkpath(fullPath)) {
|
||||
logError(QString("Failed to create directory for new map: '%1'").arg(fullPath));
|
||||
}
|
||||
|
||||
// Create file data/maps/<map_name>/scripts.inc
|
||||
QString text = this->getScriptDefaultString(projectConfig.usePoryScript, map->name());
|
||||
saveTextFile(mapDataDir + "/scripts" + this->getScriptFileExtension(projectConfig.usePoryScript), text);
|
||||
saveTextFile(fullPath + "/scripts" + this->getScriptFileExtension(projectConfig.usePoryScript), text);
|
||||
|
||||
if (projectConfig.createMapTextFileEnabled) {
|
||||
// Create file data/maps/<map_name>/text.inc
|
||||
saveTextFile(mapDataDir + "/text" + this->getScriptFileExtension(projectConfig.usePoryScript), "\n");
|
||||
saveTextFile(fullPath + "/text" + this->getScriptFileExtension(projectConfig.usePoryScript), "\n");
|
||||
}
|
||||
|
||||
// Simply append to data/event_scripts.s.
|
||||
text = QString("\n\t.include \"%1%2/scripts.inc\"\n").arg(basePath, map->name());
|
||||
text = QString("\n\t.include \"%1/scripts.inc\"\n").arg(folderPath);
|
||||
if (projectConfig.createMapTextFileEnabled) {
|
||||
text += QString("\t.include \"%1%2/text.inc\"\n").arg(basePath, map->name());
|
||||
text += QString("\t.include \"%1/text.inc\"\n").arg(folderPath);
|
||||
}
|
||||
appendTextFile(root + "/" + projectConfig.getFilePath(ProjectFilePath::data_event_scripts), text);
|
||||
|
||||
// TODO: Either simplify this redundancy or explain why we need it (to create folders without the _Layout suffix)
|
||||
if (map->needsLayoutDir()) {
|
||||
QString newLayoutDir = QString(root + "/%1%2").arg(projectConfig.getFilePath(ProjectFilePath::data_layouts_folders), map->name());
|
||||
if (!QDir::root().mkdir(newLayoutDir)) {
|
||||
logError(QString("Error: failed to create directory for new layout: '%1'").arg(newLayoutDir));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create map.json for map data.
|
||||
QString mapFilepath = QString("%1/map.json").arg(mapDataDir);
|
||||
QString mapFilepath = fullPath + "/map.json";
|
||||
QFile mapFile(mapFilepath);
|
||||
if (!mapFile.open(QIODevice::WriteOnly)) {
|
||||
logError(QString("Error: Could not open %1 for writing").arg(mapFilepath));
|
||||
@@ -1428,7 +1425,6 @@ void Project::saveMap(Map *map) {
|
||||
}
|
||||
|
||||
void Project::saveLayout(Layout *layout) {
|
||||
//
|
||||
saveLayoutBorder(layout);
|
||||
saveLayoutBlockdata(layout);
|
||||
|
||||
@@ -2022,7 +2018,8 @@ void Project::initNewMapSettings() {
|
||||
this->newMapSettings.group = this->groupNames.at(0);
|
||||
this->newMapSettings.canFlyTo = false;
|
||||
|
||||
this->newMapSettings.layout.name = Layout::layoutNameFromMapName(this->newMapSettings.name);
|
||||
this->newMapSettings.layout.folderName = this->newMapSettings.name;
|
||||
this->newMapSettings.layout.name = QString("%1%2").arg(this->newMapSettings.name).arg(Layout::defaultSuffix());
|
||||
this->newMapSettings.layout.id = Layout::layoutConstantFromName(this->newMapSettings.name);
|
||||
this->newMapSettings.layout.width = getDefaultMapDimension();
|
||||
this->newMapSettings.layout.height = getDefaultMapDimension();
|
||||
|
||||
@@ -28,26 +28,12 @@ NewLayoutDialog::NewLayoutDialog(Project *project, const Layout *layoutToCopy, Q
|
||||
if (this->layoutToCopy && !this->layoutToCopy->name.isEmpty()) {
|
||||
// Duplicating a layout, the initial name will be the base layout's name
|
||||
// with a numbered suffix to make it unique.
|
||||
// Note: Layouts imported with AdvanceMap have no name, so they'll use the default new layout name instead.
|
||||
|
||||
// If the layout name ends with the default '_Layout' suffix we'll ignore it.
|
||||
// This is because (normally) the ID for these layouts will not have this suffix,
|
||||
// so you can end up in a situation where you might have Map_Layout and Map_2_Layout,
|
||||
// and if you try to duplicate Map_Layout the next available name (because of ID collisions)
|
||||
// would be Map_Layout_3 instead of Map_3_Layout.
|
||||
QString baseName = this->layoutToCopy->name;
|
||||
QString suffix = "_Layout";
|
||||
if (baseName.length() > suffix.length() && baseName.endsWith(suffix)) {
|
||||
baseName.truncate(baseName.length() - suffix.length());
|
||||
} else {
|
||||
suffix = "";
|
||||
}
|
||||
|
||||
// Note: If 'layoutToCopy' is an imported AdvanceMap layout it won't have
|
||||
// a name, so it uses the default new layout name instead.
|
||||
int i = 2;
|
||||
do {
|
||||
newName = QString("%1_%2%3").arg(baseName).arg(i).arg(suffix);
|
||||
newId = QString("%1_%2").arg(this->layoutToCopy->id).arg(i);
|
||||
i++;
|
||||
newName = QString("%1_%2").arg(this->layoutToCopy->name).arg(i++);
|
||||
newId = Layout::layoutConstantFromName(newName);
|
||||
} while (!project->isIdentifierUnique(newName) || !project->isIdentifierUnique(newId));
|
||||
} else {
|
||||
newName = project->getNewLayoutName();
|
||||
|
||||
@@ -71,6 +71,7 @@ Layout::Settings NewLayoutForm::settings() const {
|
||||
return settings;
|
||||
}
|
||||
|
||||
// TODO: Validate while typing
|
||||
bool NewLayoutForm::validate() {
|
||||
// Make sure to call each validation function so that all errors are shown at once.
|
||||
bool valid = true;
|
||||
|
||||
@@ -71,12 +71,12 @@ NewMapDialog::NewMapDialog(Project *project, const Map *mapToCopy, QWidget *pare
|
||||
connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &NewMapDialog::dialogButtonClicked);
|
||||
|
||||
refresh();
|
||||
adjustSize(); // TODO: Save geometry?
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
// Adding new map to existing map list folder. Initialize settings accordingly.
|
||||
// Adding new map to an existing map list folder. Initialize settings accordingly.
|
||||
// Even if we initialize settings like this we'll allow users to change them afterwards,
|
||||
// because nothing is expecting them to stay at these values.
|
||||
// because nothing is expecting them to stay at these values (with exception to layouts).
|
||||
NewMapDialog::NewMapDialog(Project *project, int mapListTab, const QString &mapListItem, QWidget *parent) :
|
||||
NewMapDialog(project, parent)
|
||||
{
|
||||
@@ -132,21 +132,18 @@ void NewMapDialog::saveSettings() {
|
||||
settings->group = ui->comboBox_Group->currentText();
|
||||
settings->layout = ui->newLayoutForm->settings();
|
||||
settings->layout.id = ui->comboBox_LayoutID->currentText();
|
||||
settings->layout.name = Layout::layoutNameFromMapName(settings->name); // TODO: Verify uniqueness
|
||||
settings->canFlyTo = ui->checkBox_CanFlyTo->isChecked();
|
||||
settings->header = this->headerForm->headerData();
|
||||
|
||||
porymapConfig.newMapHeaderSectionExpanded = this->headerSection->isExpanded();
|
||||
}
|
||||
// TODO: Verify uniqueness. If the layout ID belongs to an existing layout we don't need to do this at all.
|
||||
settings->layout.name = QString("%1%2").arg(settings->name).arg(Layout::defaultSuffix());
|
||||
|
||||
void NewMapDialog::setLayout(const Layout *layout) {
|
||||
if (layout) {
|
||||
ui->comboBox_LayoutID->setTextItem(layout->id);
|
||||
ui->newLayoutForm->setSettings(layout->settings());
|
||||
ui->newLayoutForm->setDisabled(true);
|
||||
} else {
|
||||
ui->newLayoutForm->setDisabled(false);
|
||||
}
|
||||
// Folders for new layouts created for new maps use the map name, rather than the layout name.
|
||||
// There's no real reason for this, aside from maintaining consistency with the default layout
|
||||
// folder names that do this (which would otherwise all have a '_Layout' suffix in the name).
|
||||
settings->layout.folderName = settings->name;
|
||||
|
||||
porymapConfig.newMapHeaderSectionExpanded = this->headerSection->isExpanded();
|
||||
}
|
||||
|
||||
bool NewMapDialog::validateName(bool allowEmpty) {
|
||||
@@ -168,6 +165,8 @@ bool NewMapDialog::validateName(bool allowEmpty) {
|
||||
|
||||
void NewMapDialog::on_lineEdit_Name_textChanged(const QString &text) {
|
||||
validateName(true);
|
||||
|
||||
// Changing the map name updates the layout ID field to match.
|
||||
if (ui->comboBox_LayoutID->isEnabled()) {
|
||||
ui->comboBox_LayoutID->setCurrentText(Layout::layoutConstantFromName(text));
|
||||
}
|
||||
@@ -219,7 +218,15 @@ bool NewMapDialog::validateLayoutID(bool allowEmpty) {
|
||||
|
||||
void NewMapDialog::on_comboBox_LayoutID_currentTextChanged(const QString &text) {
|
||||
validateLayoutID(true);
|
||||
setLayout(this->project->mapLayouts.value(text));
|
||||
|
||||
// Changing the layout ID to an existing layout updates the layout settings to match.
|
||||
const Layout *layout = this->project->mapLayouts.value(text);
|
||||
if (layout) {
|
||||
ui->newLayoutForm->setSettings(layout->settings());
|
||||
ui->newLayoutForm->setDisabled(true);
|
||||
} else {
|
||||
ui->newLayoutForm->setDisabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void NewMapDialog::dialogButtonClicked(QAbstractButton *button) {
|
||||
|
||||
Reference in New Issue
Block a user