diff --git a/forms/newlayoutform.ui b/forms/newlayoutform.ui new file mode 100644 index 00000000..65183046 --- /dev/null +++ b/forms/newlayoutform.ui @@ -0,0 +1,236 @@ + + + NewLayoutForm + + + + 0 + 0 + 304 + 344 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Map Dimensions + + + + + + + 0 + 0 + + + + Width + + + + + + + <html><head/><body><p>Width (in metatiles) of the new map.</p></body></html> + + + 1 + + + + + + + + 0 + 0 + + + + Height + + + + + + + <html><head/><body><p>Height (in metatiles) of the new map.</p></body></html> + + + 1 + + + + + + + false + + + color: rgb(255, 0, 0) + + + + + + true + + + + + + + + + + Border Dimensions + + + + + + + 0 + 0 + + + + Width + + + + + + + <html><head/><body><p>Width (in metatiles) of the new map's border.</p></body></html> + + + 1 + + + + + + + <html><head/><body><p>Height (in metatiles) of the new map's border.</p></body></html> + + + 1 + + + + + + + + 0 + 0 + + + + Height + + + + + + + + + + Tilesets + + + + + + Primary + + + + + + + <html><head/><body><p>The primary tileset for the new map.</p></body></html> + + + true + + + QComboBox::InsertPolicy::NoInsert + + + + + + + Secondary + + + + + + + <html><head/><body><p>The secondary tileset for the new map.</p></body></html> + + + true + + + QComboBox::InsertPolicy::NoInsert + + + + + + + false + + + color: rgb(255, 0, 0) + + + + + + true + + + + + + + + + + + NoScrollComboBox + QComboBox +
noscrollcombobox.h
+
+ + NoScrollSpinBox + QSpinBox +
noscrollspinbox.h
+
+
+ + +
diff --git a/forms/newmapdialog.ui b/forms/newmapdialog.ui index 3ddba1dc..911050d3 100644 --- a/forms/newmapdialog.ui +++ b/forms/newmapdialog.ui @@ -32,14 +32,27 @@ 10 - - + + - Name + Map ID - + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + false @@ -55,287 +68,10 @@ - - - - false - - - color: rgb(255, 0, 0) - - - - - - true - - + + - - - - Border Dimensions - - - - - - - 0 - 0 - - - - Width - - - - - - - <html><head/><body><p>Width (in metatiles) of the new map's border.</p></body></html> - - - 1 - - - - - - - <html><head/><body><p>Height (in metatiles) of the new map's border.</p></body></html> - - - 1 - - - - - - - - 0 - 0 - - - - Height - - - - - - - - - - ID - - - - - - - Map Dimensions - - - - - - - 0 - 0 - - - - Width - - - - - - - <html><head/><body><p>Width (in metatiles) of the new map.</p></body></html> - - - 1 - - - - - - - - 0 - 0 - - - - Height - - - - - - - <html><head/><body><p>Height (in metatiles) of the new map.</p></body></html> - - - 1 - - - - - - - false - - - color: rgb(255, 0, 0) - - - - - - true - - - - - - - - - - <html><head/><body><p>The name of the group this map will be added to.</p></body></html> - - - true - - - QComboBox::InsertPolicy::NoInsert - - - - - - - <html><head/><body><p>The constant that will be used to refer to this map. It cannot be the same as any other existing map, and it must start with the specified prefix.</p></body></html> - - - - - - - <html><head/><body><p>The name of the new map. The name cannot be the same as any other existing map.</p></body></html> - - - true - - - - - - - Tilesets - - - - - - Primary - - - - - - - <html><head/><body><p>The primary tileset for the new map.</p></body></html> - - - true - - - QComboBox::InsertPolicy::NoInsert - - - - - - - Secondary - - - - - - - <html><head/><body><p>The secondary tileset for the new map.</p></body></html> - - - true - - - QComboBox::InsertPolicy::NoInsert - - - - - - - false - - - color: rgb(255, 0, 0) - - - - - - true - - - - - - - - - - false - - - color: rgb(255, 0, 0) - - - - - - true - - - - - - - Qt::Orientation::Vertical - - - - 20 - 40 - - - - - - - - Group - - - - + @@ -353,7 +89,83 @@ - + + + + false + + + color: rgb(255, 0, 0) + + + + + + true + + + + + + + <html><head/><body><p>The name of the new map. The name cannot be the same as any other existing map.</p></body></html> + + + true + + + + + + + Can Fly To + + + + + + + <html><head/><body><p>The name of the group this map will be added to.</p></body></html> + + + true + + + QComboBox::InsertPolicy::NoInsert + + + + + + + Map Group + + + + + + + false + + + color: rgb(255, 0, 0) + + + + + + true + + + + + + + Map Name + + + + <html><head/><body><p>If checked, a Heal Location will be added to this map automatically.</p></body></html> @@ -363,13 +175,23 @@ - - + + - Can Fly To + Layout ID + + + + <html><head/><body><p>The constant that will be used to refer to this map. It cannot be the same as any other existing map, and it must start with the specified prefix.</p></body></html> + + + + + + @@ -394,9 +216,10 @@
noscrollcombobox.h
- NoScrollSpinBox - QSpinBox -
noscrollspinbox.h
+ NewLayoutForm + QWidget +
newlayoutform.h
+ 1
diff --git a/include/config.h b/include/config.h index 0655c0bd..21e2dde7 100644 --- a/include/config.h +++ b/include/config.h @@ -70,7 +70,7 @@ public: this->showTilesetEditorLayerGrid = true; this->monitorFiles = true; this->tilesetCheckerboardFill = true; - this->newMapHeaderSectionExpanded = false; + this->newMapHeaderSectionExpanded = true; this->theme = "default"; this->wildMonChartTheme = ""; this->textEditorOpenFolder = ""; diff --git a/include/core/map.h b/include/core/map.h index 314013d7..55eee303 100644 --- a/include/core/map.h +++ b/include/core/map.h @@ -7,6 +7,7 @@ #include "maplayout.h" #include "tileset.h" #include "events.h" +#include "mapheader.h" #include #include @@ -56,30 +57,8 @@ public: int getBorderWidth() const; int getBorderHeight() const; - // TODO: Combine these into a separate MapHeader class? - void setSong(const QString &song); - void setLocation(const QString &location); - void setRequiresFlash(bool requiresFlash); - void setWeather(const QString &weather); - void setType(const QString &type); - void setShowsLocationName(bool showsLocationName); - void setAllowsRunning(bool allowsRunning); - void setAllowsBiking(bool allowsBiking); - void setAllowsEscaping(bool allowsEscaping); - void setFloorNumber(int floorNumber); - void setBattleScene(const QString &battleScene); - - QString song() const { return m_song; } - QString location() const { return m_location; } - bool requiresFlash() const { return m_requiresFlash; } - QString weather() const { return m_weather; } - QString type() const { return m_type; } - bool showsLocationName() const { return m_showsLocationName; } - bool allowsRunning() const { return m_allowsRunning; } - bool allowsBiking() const { return m_allowsBiking; } - bool allowsEscaping() const { return m_allowsEscaping; } - int floorNumber() const { return m_floorNumber; } - QString battleScene() const { return m_battleScene; } + void setHeader(const MapHeader &header) { *m_header = header; } + MapHeader* header() const { return m_header; } void setSharedEventsMap(const QString &sharedEventsMap) { m_sharedEventsMap = sharedEventsMap; } void setSharedScriptsMap(const QString &sharedScriptsMap) { m_sharedScriptsMap = sharedScriptsMap; } @@ -130,25 +109,13 @@ private: QString m_name; QString m_constantName; QString m_layoutId; // TODO: Why do we do half this->layout()->id and half this->layoutId. Should these ever be different? - - QString m_song; - QString m_location; - bool m_requiresFlash; - QString m_weather; - QString m_type; - bool m_showsLocationName; - bool m_allowsRunning; - bool m_allowsBiking; - bool m_allowsEscaping; - int m_floorNumber = 0; - QString m_battleScene; - QString m_sharedEventsMap = ""; QString m_sharedScriptsMap = ""; QStringList m_scriptsFileLabels; QMap m_customAttributes; + MapHeader *m_header = nullptr; Layout *m_layout = nullptr; bool m_isPersistedToFile = true; diff --git a/include/core/mapheader.h b/include/core/mapheader.h new file mode 100644 index 00000000..ee2c354e --- /dev/null +++ b/include/core/mapheader.h @@ -0,0 +1,83 @@ +#ifndef MAPHEADER_H +#define MAPHEADER_H + +#include + +class MapHeader : public QObject +{ + Q_OBJECT +public: + MapHeader(QObject *parent = nullptr) : QObject(parent) {}; + ~MapHeader() {}; + MapHeader(const MapHeader& other); + MapHeader& operator=(const MapHeader& other); + bool operator==(const MapHeader& other) const { + return m_song == other.m_song + && m_location == other.m_location + && m_requiresFlash == other.m_requiresFlash + && m_weather == other.m_weather + && m_type == other.m_type + && m_showsLocationName == other.m_showsLocationName + && m_allowsRunning == other.m_allowsRunning + && m_allowsBiking == other.m_allowsBiking + && m_allowsEscaping == other.m_allowsEscaping + && m_floorNumber == other.m_floorNumber + && m_battleScene == other.m_battleScene; + } + bool operator!=(const MapHeader& other) const { + return !(operator==(other)); + } + + void setSong(const QString &song); + void setLocation(const QString &location); + void setRequiresFlash(bool requiresFlash); + void setWeather(const QString &weather); + void setType(const QString &type); + void setShowsLocationName(bool showsLocationName); + void setAllowsRunning(bool allowsRunning); + void setAllowsBiking(bool allowsBiking); + void setAllowsEscaping(bool allowsEscaping); + void setFloorNumber(int floorNumber); + void setBattleScene(const QString &battleScene); + + QString song() const { return m_song; } + QString location() const { return m_location; } + bool requiresFlash() const { return m_requiresFlash; } + QString weather() const { return m_weather; } + QString type() const { return m_type; } + bool showsLocationName() const { return m_showsLocationName; } + bool allowsRunning() const { return m_allowsRunning; } + bool allowsBiking() const { return m_allowsBiking; } + bool allowsEscaping() const { return m_allowsEscaping; } + int floorNumber() const { return m_floorNumber; } + QString battleScene() const { return m_battleScene; } + +signals: + void songChanged(QString, QString); + void locationChanged(QString, QString); + void requiresFlashChanged(bool, bool); + void weatherChanged(QString, QString); + void typeChanged(QString, QString); + void showsLocationNameChanged(bool, bool); + void allowsRunningChanged(bool, bool); + void allowsBikingChanged(bool, bool); + void allowsEscapingChanged(bool, bool); + void floorNumberChanged(int, int); + void battleSceneChanged(QString, QString); + void modified(); + +private: + QString m_song; + QString m_location; + bool m_requiresFlash = false; + QString m_weather; + QString m_type; + bool m_showsLocationName = false; + bool m_allowsRunning = false; + bool m_allowsBiking = false; + bool m_allowsEscaping = false; + int m_floorNumber = 0; + QString m_battleScene; +}; + +#endif // MAPHEADER_H diff --git a/include/mainwindow.h b/include/mainwindow.h index ab4e0482..a506f5e0 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -327,7 +327,7 @@ private: QAction *copyAction = nullptr; QAction *pasteAction = nullptr; - MapHeaderForm *mapHeader = nullptr; + MapHeaderForm *mapHeaderForm = nullptr; QMap lastSelectedEvent; diff --git a/include/project.h b/include/project.h index c76fcd72..f28f9259 100644 --- a/include/project.h +++ b/include/project.h @@ -263,7 +263,7 @@ private: signals: void fileChanged(QString filepath); - void mapSectionIdNamesChanged(); + void mapSectionIdNamesChanged(const QStringList &idNames); void mapLoaded(Map *map); }; diff --git a/include/ui/mapheaderform.h b/include/ui/mapheaderform.h index afdee728..897b8e9a 100644 --- a/include/ui/mapheaderform.h +++ b/include/ui/mapheaderform.h @@ -1,18 +1,18 @@ #ifndef MAPHEADERFORM_H #define MAPHEADERFORM_H -#include "project.h" -#include "map.h" -#include "ui_mapheaderform.h" - -#include - /* This is the UI class used to edit the fields in a map's header. It's intended to be used anywhere the UI needs to present an editor for a map's header, e.g. for the current map in the main editor or in the new map dialog. */ +#include +#include +#include "mapheader.h" + +class Project; + namespace Ui { class MapHeaderForm; } @@ -25,32 +25,43 @@ public: explicit MapHeaderForm(QWidget *parent = nullptr); ~MapHeaderForm(); - void setProject(Project * project); - void setMap(Map * map); - - void clearDisplay(); + void init(const Project * project); void clear(); - void refreshLocationsComboBox(); + void setHeader(MapHeader *header); + MapHeader headerData() const; - Ui::MapHeaderForm *ui; + void setLocations(QStringList locations); + void setLocationsDisabled(bool disabled); private: - QPointer map = nullptr; - QPointer project = nullptr; + Ui::MapHeaderForm *ui; + QPointer m_header = nullptr; -private slots: - void on_comboBox_Song_currentTextChanged(const QString &); - void on_comboBox_Location_currentTextChanged(const QString &); - void on_comboBox_Weather_currentTextChanged(const QString &); - void on_comboBox_Type_currentTextChanged(const QString &); - void on_comboBox_BattleScene_currentTextChanged(const QString &); - void on_checkBox_RequiresFlash_stateChanged(int); - void on_checkBox_ShowLocationName_stateChanged(int); - void on_checkBox_AllowRunning_stateChanged(int); - void on_checkBox_AllowBiking_stateChanged(int); - void on_checkBox_AllowEscaping_stateChanged(int); - void on_spinBox_FloorNumber_valueChanged(int); + void updateUi(); + void updateSong(); + void updateLocation(); + void updateRequiresFlash(); + void updateWeather(); + void updateType(); + void updateBattleScene(); + void updateShowsLocationName(); + void updateAllowsRunning(); + void updateAllowsBiking(); + void updateAllowsEscaping(); + void updateFloorNumber(); + + void onSongUpdated(const QString &song); + void onLocationChanged(const QString &location); + void onWeatherChanged(const QString &weather); + void onTypeChanged(const QString &type); + void onBattleSceneChanged(const QString &battleScene); + void onRequiresFlashChanged(int selected); + void onShowLocationNameChanged(int selected); + void onAllowRunningChanged(int selected); + void onAllowBikingChanged(int selected); + void onAllowEscapingChanged(int selected); + void onFloorNumberChanged(int offset); }; #endif // MAPHEADERFORM_H diff --git a/include/ui/newlayoutform.h b/include/ui/newlayoutform.h new file mode 100644 index 00000000..6f63466b --- /dev/null +++ b/include/ui/newlayoutform.h @@ -0,0 +1,46 @@ +#ifndef NEWLAYOUTFORM_H +#define NEWLAYOUTFORM_H + +#include + +class Project; + +namespace Ui { +class NewLayoutForm; +} + +class NewLayoutForm : public QWidget +{ + Q_OBJECT + +public: + explicit NewLayoutForm(QWidget *parent = nullptr); + ~NewLayoutForm(); + + void initUi(Project *project); + + struct Settings { + int width; + int height; + int borderWidth; + int borderHeight; + QString primaryTilesetLabel; + QString secondaryTilesetLabel; + }; + + void setSettings(const Settings &settings); + NewLayoutForm::Settings settings() const; + + void setDisabled(bool disabled); + + bool validate(); + +private: + Ui::NewLayoutForm *ui; + Project *m_project; + + bool validateMapDimensions(); + bool validateTilesets(); +}; + +#endif // NEWLAYOUTFORM_H diff --git a/include/ui/newmapdialog.h b/include/ui/newmapdialog.h index 72b0b5de..e7401242 100644 --- a/include/ui/newmapdialog.h +++ b/include/ui/newmapdialog.h @@ -7,6 +7,7 @@ #include "project.h" #include "map.h" #include "mapheaderform.h" +#include "newlayoutform.h" #include "lib/collapsiblesection.h" namespace Ui { @@ -25,7 +26,6 @@ public: bool importedMap; QString layoutId; void init(); - //void initUi();//TODO void init(int tabIndex, QString data); void init(Layout *); static void setDefaultSettings(Project *project); @@ -37,11 +37,9 @@ private: Ui::NewMapDialog *ui; Project *project; CollapsibleSection *headerSection; - MapHeaderForm *headerData; + MapHeaderForm *headerForm; - bool validateMapDimensions(); bool validateMapGroup(); - bool validateTilesets(); bool validateID(); bool validateName(); @@ -51,33 +49,18 @@ private: struct Settings { QString group; - int width; - int height; - int borderWidth; - int borderHeight; - QString primaryTilesetLabel; - QString secondaryTilesetLabel; - QString song; - QString location; - bool requiresFlash; - QString weather; - QString type; - QString battleScene; - bool showLocationName; - bool allowRunning; - bool allowBiking; - bool allowEscaping; - int floorNumber; bool canFlyTo; + NewLayoutForm::Settings layout; + MapHeader header; }; static struct Settings settings; private slots: - //void on_checkBox_UseExistingLayout_stateChanged(int state); + //void on_checkBox_UseExistingLayout_stateChanged(int state); //TODO //void on_comboBox_Layout_currentTextChanged(const QString &text); void on_pushButton_Accept_clicked(); void on_lineEdit_Name_textChanged(const QString &); - void on_lineEdit_ID_textChanged(const QString &); + void on_lineEdit_MapID_textChanged(const QString &); }; #endif // NEWMAPDIALOG_H diff --git a/porymap.pro b/porymap.pro index d3d870bc..c4db35d0 100644 --- a/porymap.pro +++ b/porymap.pro @@ -30,6 +30,7 @@ SOURCES += src/core/block.cpp \ src/core/imageexport.cpp \ src/core/map.cpp \ src/core/mapconnection.cpp \ + src/core/mapheader.cpp \ src/core/maplayout.cpp \ src/core/mapparser.cpp \ src/core/metatile.cpp \ @@ -89,6 +90,7 @@ SOURCES += src/core/block.cpp \ src/ui/movablerect.cpp \ src/ui/movementpermissionsselector.cpp \ src/ui/neweventtoolbutton.cpp \ + src/ui/newlayoutform.cpp \ src/ui/noscrollcombobox.cpp \ src/ui/noscrollspinbox.cpp \ src/ui/montabwidget.cpp \ @@ -134,6 +136,7 @@ HEADERS += include/core/block.h \ include/core/imageexport.h \ include/core/map.h \ include/core/mapconnection.h \ + include/core/mapheader.h \ include/core/maplayout.h \ include/core/mapparser.h \ include/core/metatile.h \ @@ -193,6 +196,7 @@ HEADERS += include/core/block.h \ include/ui/movablerect.h \ include/ui/movementpermissionsselector.h \ include/ui/neweventtoolbutton.h \ + include/ui/newlayoutform.h \ include/ui/noscrollcombobox.h \ include/ui/noscrollspinbox.h \ include/ui/montabwidget.h \ @@ -237,6 +241,7 @@ FORMS += forms/mainwindow.ui \ forms/gridsettingsdialog.ui \ forms/mapheaderform.ui \ forms/maplisttoolbar.ui \ + forms/newlayoutform.ui \ forms/newmapconnectiondialog.ui \ forms/prefabcreationdialog.ui \ forms/prefabframe.ui \ diff --git a/src/core/map.cpp b/src/core/map.cpp index ab31ac86..1d7c4555 100644 --- a/src/core/map.cpp +++ b/src/core/map.cpp @@ -16,6 +16,9 @@ Map::Map(QObject *parent) : QObject(parent) m_scriptsLoaded = false; m_editHistory = new QUndoStack(this); resetEvents(); + + m_header = new MapHeader(this); + connect(m_header, &MapHeader::modified, this, &Map::modified); } Map::~Map() { @@ -309,48 +312,3 @@ void Map::pruneEditHistory() { command->setObsolete(true); } } - -void Map::setSong(const QString &song) { - m_song = song; -} - -void Map::setLocation(const QString &location) { - m_location = location; -} - -void Map::setRequiresFlash(bool requiresFlash) { - m_requiresFlash = requiresFlash; -} - -void Map::setWeather(const QString &weather) { - m_weather = weather; -} - -void Map::setType(const QString &type) { - m_type = type; -} - -void Map::setShowsLocationName(bool showsLocationName) { - m_showsLocationName = showsLocationName; -} - -void Map::setAllowsRunning(bool allowsRunning) { - m_allowsRunning = allowsRunning; -} - -void Map::setAllowsBiking(bool allowsBiking) { - m_allowsBiking = allowsBiking; -} - -void Map::setAllowsEscaping(bool allowsEscaping) { - m_allowsEscaping = allowsEscaping; -} - -void Map::setFloorNumber(int floorNumber) { - m_floorNumber = floorNumber; -} - -void Map::setBattleScene(const QString &battleScene) { - m_battleScene = battleScene; -} - diff --git a/src/core/mapheader.cpp b/src/core/mapheader.cpp new file mode 100644 index 00000000..4c0bc06e --- /dev/null +++ b/src/core/mapheader.cpp @@ -0,0 +1,132 @@ +#include "mapheader.h" + +MapHeader::MapHeader(const MapHeader& other) : MapHeader() { + m_song = other.m_song; + m_location = other.m_location; + m_requiresFlash = other.m_requiresFlash; + m_weather = other.m_weather; + m_type = other.m_type; + m_showsLocationName = other.m_showsLocationName; + m_allowsRunning = other.m_allowsRunning; + m_allowsBiking = other.m_allowsBiking; + m_allowsEscaping = other.m_allowsEscaping; + m_floorNumber = other.m_floorNumber; + m_battleScene = other.m_battleScene; +} + +MapHeader &MapHeader::operator=(const MapHeader &other) { + // We want to call each set function here to ensure any fieldChanged signals + // are sent as necessary. This does also mean the modified signal can be sent + // repeatedly (but for now at least that's not a big issue). + setSong(other.m_song); + setLocation(other.m_location); + setRequiresFlash(other.m_requiresFlash); + setWeather(other.m_weather); + setType(other.m_type); + setShowsLocationName(other.m_showsLocationName); + setAllowsRunning(other.m_allowsRunning); + setAllowsBiking(other.m_allowsBiking); + setAllowsEscaping(other.m_allowsEscaping); + setFloorNumber(other.m_floorNumber); + setBattleScene(other.m_battleScene); + return *this; +} + +void MapHeader::setSong(const QString &song) { + if (m_song == song) + return; + auto before = m_song; + m_song = song; + emit songChanged(before, m_song); + emit modified(); +} + +void MapHeader::setLocation(const QString &location) { + if (m_location == location) + return; + auto before = m_location; + m_location = location; + emit locationChanged(before, m_location); + emit modified(); +} + +void MapHeader::setRequiresFlash(bool requiresFlash) { + if (m_requiresFlash == requiresFlash) + return; + auto before = m_requiresFlash; + m_requiresFlash = requiresFlash; + emit requiresFlashChanged(before, m_requiresFlash); + emit modified(); +} + +void MapHeader::setWeather(const QString &weather) { + if (m_weather == weather) + return; + auto before = m_weather; + m_weather = weather; + emit weatherChanged(before, m_weather); + emit modified(); +} + +void MapHeader::setType(const QString &type) { + if (m_type == type) + return; + auto before = m_type; + m_type = type; + emit typeChanged(before, m_type); + emit modified(); +} + +void MapHeader::setShowsLocationName(bool showsLocationName) { + if (m_showsLocationName == showsLocationName) + return; + auto before = m_showsLocationName; + m_showsLocationName = showsLocationName; + emit showsLocationNameChanged(before, m_showsLocationName); + emit modified(); +} + +void MapHeader::setAllowsRunning(bool allowsRunning) { + if (m_allowsRunning == allowsRunning) + return; + auto before = m_allowsRunning; + m_allowsRunning = allowsRunning; + emit allowsRunningChanged(before, m_allowsRunning); + emit modified(); +} + +void MapHeader::setAllowsBiking(bool allowsBiking) { + if (m_allowsBiking == allowsBiking) + return; + auto before = m_allowsBiking; + m_allowsBiking = allowsBiking; + emit allowsBikingChanged(before, m_allowsBiking); + emit modified(); +} + +void MapHeader::setAllowsEscaping(bool allowsEscaping) { + if (m_allowsEscaping == allowsEscaping) + return; + auto before = m_allowsEscaping; + m_allowsEscaping = allowsEscaping; + emit allowsEscapingChanged(before, m_allowsEscaping); + emit modified(); +} + +void MapHeader::setFloorNumber(int floorNumber) { + if (m_floorNumber == floorNumber) + return; + auto before = m_floorNumber; + m_floorNumber = floorNumber; + emit floorNumberChanged(before, m_floorNumber); + emit modified(); +} + +void MapHeader::setBattleScene(const QString &battleScene) { + if (m_battleScene == battleScene) + return; + auto before = m_battleScene; + m_battleScene = battleScene; + emit battleSceneChanged(before, m_battleScene); + emit modified(); +} diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index eaa98f11..f4c96393 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -253,8 +253,8 @@ void MainWindow::initCustomUI() { } // Create map header data widget - this->mapHeader = new MapHeaderForm(); - ui->layout_HeaderData->addWidget(this->mapHeader); + this->mapHeaderForm = new MapHeaderForm(); + ui->layout_HeaderData->addWidget(this->mapHeaderForm); } void MainWindow::initExtraSignals() { @@ -617,7 +617,7 @@ bool MainWindow::openProject(QString dir, bool initial) { project->set_root(dir); connect(project, &Project::fileChanged, this, &MainWindow::showFileWatcherWarning); connect(project, &Project::mapLoaded, this, &MainWindow::onMapLoaded); - connect(project, &Project::mapSectionIdNamesChanged, this->mapHeader, &MapHeaderForm::refreshLocationsComboBox); + connect(project, &Project::mapSectionIdNamesChanged, this->mapHeaderForm, &MapHeaderForm::setLocations); this->editor->setProject(project); // Make sure project looks reasonable before attempting to load it @@ -1017,23 +1017,19 @@ void MainWindow::openWarpMap(QString map_name, int event_id, Event::Group event_ } void MainWindow::displayMapProperties() { - // Block signals to the comboboxes while they are being modified - const QSignalBlocker b_PrimaryTileset(ui->comboBox_PrimaryTileset); - const QSignalBlocker b_SecondaryTileset(ui->comboBox_SecondaryTileset); - - this->mapHeader->clearDisplay(); + this->mapHeaderForm->clear(); if (!editor || !editor->map || !editor->project) { ui->frame_HeaderData->setEnabled(false); return; } - ui->frame_HeaderData->setEnabled(true); - Map *map = editor->map; + this->mapHeaderForm->setHeader(editor->map->header()); - ui->comboBox_PrimaryTileset->setCurrentText(map->layout()->tileset_primary_label); - ui->comboBox_SecondaryTileset->setCurrentText(map->layout()->tileset_secondary_label); + const QSignalBlocker b_PrimaryTileset(ui->comboBox_PrimaryTileset); + const QSignalBlocker b_SecondaryTileset(ui->comboBox_SecondaryTileset); + ui->comboBox_PrimaryTileset->setCurrentText(editor->map->layout()->tileset_primary_label); + ui->comboBox_SecondaryTileset->setCurrentText(editor->map->layout()->tileset_secondary_label); - this->mapHeader->setMap(map); // Custom fields table. /* // TODO: Re-enable @@ -1060,26 +1056,28 @@ void MainWindow::on_comboBox_LayoutSelector_currentTextChanged(const QString &te bool MainWindow::setProjectUI() { Project *project = editor->project; - this->mapHeader->setProject(project); - - // Block signals to the comboboxes while they are being modified - const QSignalBlocker b_PrimaryTileset(ui->comboBox_PrimaryTileset); - const QSignalBlocker b_SecondaryTileset(ui->comboBox_SecondaryTileset); - const QSignalBlocker b_DiveMap(ui->comboBox_DiveMap); - const QSignalBlocker b_EmergeMap(ui->comboBox_EmergeMap); - const QSignalBlocker b_LayoutSelector(ui->comboBox_LayoutSelector); + this->mapHeaderForm->init(project); // Set up project comboboxes + const QSignalBlocker b_PrimaryTileset(ui->comboBox_PrimaryTileset); ui->comboBox_PrimaryTileset->clear(); ui->comboBox_PrimaryTileset->addItems(project->primaryTilesetLabels); + + const QSignalBlocker b_SecondaryTileset(ui->comboBox_SecondaryTileset); ui->comboBox_SecondaryTileset->clear(); ui->comboBox_SecondaryTileset->addItems(project->secondaryTilesetLabels); + + const QSignalBlocker b_LayoutSelector(ui->comboBox_LayoutSelector); ui->comboBox_LayoutSelector->clear(); ui->comboBox_LayoutSelector->addItems(project->mapLayoutsTable); + + const QSignalBlocker b_DiveMap(ui->comboBox_DiveMap); ui->comboBox_DiveMap->clear(); ui->comboBox_DiveMap->addItems(project->mapNames); ui->comboBox_DiveMap->setClearButtonEnabled(true); ui->comboBox_DiveMap->setFocusedScrollingEnabled(false); + + const QSignalBlocker b_EmergeMap(ui->comboBox_EmergeMap); ui->comboBox_EmergeMap->clear(); ui->comboBox_EmergeMap->addItems(project->mapNames); ui->comboBox_EmergeMap->setClearButtonEnabled(true); @@ -1122,20 +1120,23 @@ bool MainWindow::setProjectUI() { } void MainWindow::clearProjectUI() { - // Block signals to the comboboxes while they are being modified + // Clear project comboboxes const QSignalBlocker b_PrimaryTileset(ui->comboBox_PrimaryTileset); - const QSignalBlocker b_SecondaryTileset(ui->comboBox_SecondaryTileset); - const QSignalBlocker b_DiveMap(ui->comboBox_DiveMap); - const QSignalBlocker b_EmergeMap(ui->comboBox_EmergeMap); - const QSignalBlocker b_LayoutSelector(ui->comboBox_LayoutSelector); - ui->comboBox_PrimaryTileset->clear(); + + const QSignalBlocker b_SecondaryTileset(ui->comboBox_SecondaryTileset); ui->comboBox_SecondaryTileset->clear(); + + const QSignalBlocker b_DiveMap(ui->comboBox_DiveMap); ui->comboBox_DiveMap->clear(); + + const QSignalBlocker b_EmergeMap(ui->comboBox_EmergeMap); ui->comboBox_EmergeMap->clear(); + + const QSignalBlocker b_LayoutSelector(ui->comboBox_LayoutSelector); ui->comboBox_LayoutSelector->clear(); - this->mapHeader->clear(); + this->mapHeaderForm->clear(); // Clear map models delete this->mapGroupModel; @@ -1466,7 +1467,7 @@ void MainWindow::onNewMapCreated() { // Add new Map / Layout to the mapList models this->mapGroupModel->insertMapItem(newMapName, editor->project->groupNames[newMapGroup]); - this->mapAreaModel->insertMapItem(newMapName, newMap->location(), newMapGroup); + this->mapAreaModel->insertMapItem(newMapName, newMap->header()->location(), newMapGroup); this->layoutTreeModel->insertMapItem(newMapName, newMap->layout()->id); // Refresh any combo box that displays map names and persists between maps diff --git a/src/project.cpp b/src/project.cpp index 03f7b4df..f168099e 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -155,6 +155,9 @@ Map* Project::loadMap(QString mapName) { return nullptr; } + // If the map's MAPSEC value in the header changes, update our global array to keep it in sync. + connect(map->header(), &MapHeader::locationChanged, [this, map] { this->mapNameToMapSectionName.insert(map->name(), map->header()->location()); }); + mapCache.insert(mapName, map); emit mapLoaded(map); return map; @@ -217,22 +220,22 @@ bool Project::loadMapData(Map* map) { this->mapNamesToMapConstants.insert(map->name(), map->constantName()); this->mapConstantsToMapNames.insert(map->constantName(), map->name()); - map->setSong(ParseUtil::jsonToQString(mapObj["music"])); + map->header()->setSong(ParseUtil::jsonToQString(mapObj["music"])); map->setLayoutId(ParseUtil::jsonToQString(mapObj["layout"])); - map->setLocation(ParseUtil::jsonToQString(mapObj["region_map_section"])); - map->setRequiresFlash(ParseUtil::jsonToBool(mapObj["requires_flash"])); - map->setWeather(ParseUtil::jsonToQString(mapObj["weather"])); - map->setType(ParseUtil::jsonToQString(mapObj["map_type"])); - map->setShowsLocationName(ParseUtil::jsonToBool(mapObj["show_map_name"])); - map->setBattleScene(ParseUtil::jsonToQString(mapObj["battle_scene"])); + map->header()->setLocation(ParseUtil::jsonToQString(mapObj["region_map_section"])); + map->header()->setRequiresFlash(ParseUtil::jsonToBool(mapObj["requires_flash"])); + map->header()->setWeather(ParseUtil::jsonToQString(mapObj["weather"])); + map->header()->setType(ParseUtil::jsonToQString(mapObj["map_type"])); + map->header()->setShowsLocationName(ParseUtil::jsonToBool(mapObj["show_map_name"])); + map->header()->setBattleScene(ParseUtil::jsonToQString(mapObj["battle_scene"])); if (projectConfig.mapAllowFlagsEnabled) { - map->setAllowsBiking(ParseUtil::jsonToBool(mapObj["allow_cycling"])); - map->setAllowsEscaping(ParseUtil::jsonToBool(mapObj["allow_escaping"])); - map->setAllowsRunning(ParseUtil::jsonToBool(mapObj["allow_running"])); + map->header()->setAllowsBiking(ParseUtil::jsonToBool(mapObj["allow_cycling"])); + map->header()->setAllowsEscaping(ParseUtil::jsonToBool(mapObj["allow_escaping"])); + map->header()->setAllowsRunning(ParseUtil::jsonToBool(mapObj["allow_running"])); } if (projectConfig.floorNumberEnabled) { - map->setFloorNumber(ParseUtil::jsonToInt(mapObj["floor_number"])); + map->header()->setFloorNumber(ParseUtil::jsonToInt(mapObj["floor_number"])); } map->setSharedEventsMap(ParseUtil::jsonToQString(mapObj["shared_events_map"])); map->setSharedScriptsMap(ParseUtil::jsonToQString(mapObj["shared_scripts_map"])); @@ -1284,21 +1287,21 @@ void Project::saveMap(Map *map) { mapObj["id"] = map->constantName(); mapObj["name"] = map->name(); mapObj["layout"] = map->layout()->id; - mapObj["music"] = map->song(); - mapObj["region_map_section"] = map->location(); - mapObj["requires_flash"] = map->requiresFlash(); - mapObj["weather"] = map->weather(); - mapObj["map_type"] = map->type(); + mapObj["music"] = map->header()->song(); + mapObj["region_map_section"] = map->header()->location(); + mapObj["requires_flash"] = map->header()->requiresFlash(); + mapObj["weather"] = map->header()->weather(); + mapObj["map_type"] = map->header()->type(); if (projectConfig.mapAllowFlagsEnabled) { - mapObj["allow_cycling"] = map->allowsBiking(); - mapObj["allow_escaping"] = map->allowsEscaping(); - mapObj["allow_running"] = map->allowsRunning(); + mapObj["allow_cycling"] = map->header()->allowsBiking(); + mapObj["allow_escaping"] = map->header()->allowsEscaping(); + mapObj["allow_running"] = map->header()->allowsRunning(); } - mapObj["show_map_name"] = map->showsLocationName(); + mapObj["show_map_name"] = map->header()->showsLocationName(); if (projectConfig.floorNumberEnabled) { - mapObj["floor_number"] = map->floorNumber(); + mapObj["floor_number"] = map->header()->floorNumber(); } - mapObj["battle_scene"] = map->battleScene(); + mapObj["battle_scene"] = map->header()->battleScene(); // Connections auto connections = map->getConnections(); @@ -2301,7 +2304,7 @@ void Project::addNewMapsec(const QString &name) { this->mapSectionIdNames.append(name); } this->hasUnsavedDataChanges = true; - emit mapSectionIdNamesChanged(); + emit mapSectionIdNamesChanged(this->mapSectionIdNames); } void Project::removeMapsec(const QString &name) { @@ -2310,7 +2313,7 @@ void Project::removeMapsec(const QString &name) { this->mapSectionIdNames.removeOne(name); this->hasUnsavedDataChanges = true; - emit mapSectionIdNamesChanged(); + emit mapSectionIdNamesChanged(this->mapSectionIdNames); } // Read the constants to preserve any "unused" heal locations when writing the file later diff --git a/src/scriptapi/apimap.cpp b/src/scriptapi/apimap.cpp index 5a0fa9ce..f041b7b1 100644 --- a/src/scriptapi/apimap.cpp +++ b/src/scriptapi/apimap.cpp @@ -817,7 +817,7 @@ QJSValue MainWindow::getTilePixels(int tileId) { QString MainWindow::getSong() { if (!this->editor || !this->editor->map) return QString(); - return this->editor->map->song(); + return this->editor->map->header()->song(); } void MainWindow::setSong(QString song) { @@ -827,13 +827,13 @@ void MainWindow::setSong(QString song) { logError(QString("Unknown song '%1'").arg(song)); return; } - this->editor->map->setSong(song); + this->editor->map->header()->setSong(song); } QString MainWindow::getLocation() { if (!this->editor || !this->editor->map) return QString(); - return this->editor->map->location(); + return this->editor->map->header()->location(); } void MainWindow::setLocation(QString location) { @@ -843,25 +843,25 @@ void MainWindow::setLocation(QString location) { logError(QString("Unknown location '%1'").arg(location)); return; } - this->editor->map->setLocation(location); + this->editor->map->header()->setLocation(location); } bool MainWindow::getRequiresFlash() { if (!this->editor || !this->editor->map) return false; - return this->editor->map->requiresFlash(); + return this->editor->map->header()->requiresFlash(); } void MainWindow::setRequiresFlash(bool require) { if (!this->editor || !this->editor->map) return; - this->editor->map->setRequiresFlash(require); + this->editor->map->header()->setRequiresFlash(require); } QString MainWindow::getWeather() { if (!this->editor || !this->editor->map) return QString(); - return this->editor->map->weather(); + return this->editor->map->header()->weather(); } void MainWindow::setWeather(QString weather) { @@ -871,13 +871,13 @@ void MainWindow::setWeather(QString weather) { logError(QString("Unknown weather '%1'").arg(weather)); return; } - this->editor->map->setWeather(weather); + this->editor->map->header()->setWeather(weather); } QString MainWindow::getType() { if (!this->editor || !this->editor->map) return QString(); - return this->editor->map->type(); + return this->editor->map->header()->type(); } void MainWindow::setType(QString type) { @@ -887,13 +887,13 @@ void MainWindow::setType(QString type) { logError(QString("Unknown map type '%1'").arg(type)); return; } - this->editor->map->setType(type); + this->editor->map->header()->setType(type); } QString MainWindow::getBattleScene() { if (!this->editor || !this->editor->map) return QString(); - return this->editor->map->battleScene(); + return this->editor->map->header()->battleScene(); } void MainWindow::setBattleScene(QString battleScene) { @@ -903,66 +903,66 @@ void MainWindow::setBattleScene(QString battleScene) { logError(QString("Unknown battle scene '%1'").arg(battleScene)); return; } - this->editor->map->setBattleScene(battleScene); + this->editor->map->header()->setBattleScene(battleScene); } bool MainWindow::getShowLocationName() { if (!this->editor || !this->editor->map) return false; - return this->editor->map->showsLocationName(); + return this->editor->map->header()->showsLocationName(); } void MainWindow::setShowLocationName(bool show) { if (!this->editor || !this->editor->map) return; - this->editor->map->setShowsLocationName(show); + this->editor->map->header()->setShowsLocationName(show); } bool MainWindow::getAllowRunning() { if (!this->editor || !this->editor->map) return false; - return this->editor->map->allowsRunning(); + return this->editor->map->header()->allowsRunning(); } void MainWindow::setAllowRunning(bool allow) { if (!this->editor || !this->editor->map) return; - this->editor->map->setAllowsRunning(allow); + this->editor->map->header()->setAllowsRunning(allow); } bool MainWindow::getAllowBiking() { if (!this->editor || !this->editor->map) return false; - return this->editor->map->allowsBiking(); + return this->editor->map->header()->allowsBiking(); } void MainWindow::setAllowBiking(bool allow) { if (!this->editor || !this->editor->map) return; - this->editor->map->setAllowsBiking(allow); + this->editor->map->header()->setAllowsBiking(allow); } bool MainWindow::getAllowEscaping() { if (!this->editor || !this->editor->map) return false; - return this->editor->map->allowsEscaping(); + return this->editor->map->header()->allowsEscaping(); } void MainWindow::setAllowEscaping(bool allow) { if (!this->editor || !this->editor->map) return; - this->editor->map->setAllowsEscaping(allow); + this->editor->map->header()->setAllowsEscaping(allow); } int MainWindow::getFloorNumber() { if (!this->editor || !this->editor->map) return 0; - return this->editor->map->floorNumber(); + return this->editor->map->header()->floorNumber(); } void MainWindow::setFloorNumber(int floorNumber) { if (!this->editor || !this->editor->map) return; - this->editor->map->setFloorNumber(floorNumber); + this->editor->map->header()->setFloorNumber(floorNumber); } diff --git a/src/ui/mapheaderform.cpp b/src/ui/mapheaderform.cpp index 88d7fbf1..1fd9084c 100644 --- a/src/ui/mapheaderform.cpp +++ b/src/ui/mapheaderform.cpp @@ -1,18 +1,6 @@ #include "mapheaderform.h" - -#define BLOCK_SIGNALS \ - const QSignalBlocker b_Song(ui->comboBox_Song); \ - const QSignalBlocker b_Location(ui->comboBox_Location); \ - const QSignalBlocker b_RequiresFlash(ui->checkBox_RequiresFlash); \ - const QSignalBlocker b_Weather(ui->comboBox_Weather); \ - const QSignalBlocker b_Type(ui->comboBox_Type); \ - const QSignalBlocker b_BattleScene(ui->comboBox_BattleScene); \ - const QSignalBlocker b_ShowLocationName(ui->checkBox_ShowLocationName); \ - const QSignalBlocker b_AllowRunning(ui->checkBox_AllowRunning); \ - const QSignalBlocker b_AllowBiking(ui->checkBox_AllowBiking); \ - const QSignalBlocker b_AllowEscaping(ui->checkBox_AllowEscaping); \ - const QSignalBlocker b_FloorNumber(ui->spinBox_FloorNumber); - +#include "ui_mapheaderform.h" +#include "project.h" MapHeaderForm::MapHeaderForm(QWidget *parent) : QWidget(parent) @@ -23,6 +11,19 @@ MapHeaderForm::MapHeaderForm(QWidget *parent) // This value is an s8 by default, but we don't need to unnecessarily limit users. ui->spinBox_FloorNumber->setMinimum(INT_MIN); ui->spinBox_FloorNumber->setMaximum(INT_MAX); + + // When the UI is updated, sync those changes to the tracked MapHeader (if there is one) + connect(ui->comboBox_Song, &QComboBox::currentTextChanged, this, &MapHeaderForm::onSongUpdated); + connect(ui->comboBox_Location, &QComboBox::currentTextChanged, this, &MapHeaderForm::onLocationChanged); + connect(ui->comboBox_Weather, &QComboBox::currentTextChanged, this, &MapHeaderForm::onWeatherChanged); + connect(ui->comboBox_Type, &QComboBox::currentTextChanged, this, &MapHeaderForm::onTypeChanged); + connect(ui->comboBox_BattleScene, &QComboBox::currentTextChanged, this, &MapHeaderForm::onBattleSceneChanged); + connect(ui->checkBox_RequiresFlash, &QCheckBox::stateChanged, this, &MapHeaderForm::onRequiresFlashChanged); + connect(ui->checkBox_ShowLocationName, &QCheckBox::stateChanged, this, &MapHeaderForm::onShowLocationNameChanged); + connect(ui->checkBox_AllowRunning, &QCheckBox::stateChanged, this, &MapHeaderForm::onAllowRunningChanged); + connect(ui->checkBox_AllowBiking, &QCheckBox::stateChanged, this, &MapHeaderForm::onAllowBikingChanged); + connect(ui->checkBox_AllowEscaping, &QCheckBox::stateChanged, this, &MapHeaderForm::onAllowEscapingChanged); + connect(ui->spinBox_FloorNumber, &QSpinBox::valueChanged, this, &MapHeaderForm::onFloorNumberChanged); } MapHeaderForm::~MapHeaderForm() @@ -30,20 +31,31 @@ MapHeaderForm::~MapHeaderForm() delete ui; } -void MapHeaderForm::setProject(Project * newProject) { +void MapHeaderForm::init(const Project * project) { clear(); - this->project = newProject; - if (!this->project) + if (!project) return; // Populate combo boxes - BLOCK_SIGNALS - ui->comboBox_Song->addItems(this->project->songNames); - ui->comboBox_Weather->addItems(this->project->weatherNames); - ui->comboBox_Type->addItems(this->project->mapTypes); - ui->comboBox_BattleScene->addItems(this->project->mapBattleScenes); - refreshLocationsComboBox(); + + const QSignalBlocker b_Song(ui->comboBox_Song); + ui->comboBox_Song->clear(); + ui->comboBox_Song->addItems(project->songNames); + + const QSignalBlocker b_Weather(ui->comboBox_Weather); + ui->comboBox_Weather->clear(); + ui->comboBox_Weather->addItems(project->weatherNames); + + const QSignalBlocker b_Type(ui->comboBox_Type); + ui->comboBox_Type->clear(); + ui->comboBox_Type->addItems(project->mapTypes); + + const QSignalBlocker b_BattleScene(ui->comboBox_BattleScene); + ui->comboBox_BattleScene->clear(); + ui->comboBox_BattleScene->addItems(project->mapBattleScenes); + + setLocations(project->mapSectionIdNames); // Hide config-specific settings @@ -60,161 +72,199 @@ void MapHeaderForm::setProject(Project * newProject) { ui->label_FloorNumber->setVisible(floorNumEnabled); } -void MapHeaderForm::setMap(Map * newMap) { - this->map = newMap; - if (!this->map) { - clearDisplay(); - return; - } +// This combo box is treated specially because (unlike the other combo boxes) +// items that should be in this drop-down can be added or removed externally. +void MapHeaderForm::setLocations(QStringList locations) { + locations.sort(); - BLOCK_SIGNALS - ui->comboBox_Song->setCurrentText(this->map->song()); - ui->comboBox_Location->setCurrentText(this->map->location()); - ui->checkBox_RequiresFlash->setChecked(this->map->requiresFlash()); - ui->comboBox_Weather->setCurrentText(this->map->weather()); - ui->comboBox_Type->setCurrentText(this->map->type()); - ui->comboBox_BattleScene->setCurrentText(this->map->battleScene()); - ui->checkBox_ShowLocationName->setChecked(this->map->showsLocationName()); - ui->checkBox_AllowRunning->setChecked(this->map->allowsRunning()); - ui->checkBox_AllowBiking->setChecked(this->map->allowsBiking()); - ui->checkBox_AllowEscaping->setChecked(this->map->allowsEscaping()); - ui->spinBox_FloorNumber->setValue(this->map->floorNumber()); -} - -void MapHeaderForm::clearDisplay() { - BLOCK_SIGNALS - ui->comboBox_Song->clearEditText(); - ui->comboBox_Location->clearEditText(); - ui->comboBox_Weather->clearEditText(); - ui->comboBox_Type->clearEditText(); - ui->comboBox_BattleScene->clearEditText(); - ui->checkBox_ShowLocationName->setChecked(false); - ui->checkBox_RequiresFlash->setChecked(false); - ui->checkBox_AllowRunning->setChecked(false); - ui->checkBox_AllowBiking->setChecked(false); - ui->checkBox_AllowEscaping->setChecked(false); - ui->spinBox_FloorNumber->setValue(0); -} - -// Clear display and depopulate combo boxes -void MapHeaderForm::clear() { - BLOCK_SIGNALS - ui->comboBox_Song->clear(); - ui->comboBox_Location->clear(); - ui->comboBox_Weather->clear(); - ui->comboBox_Type->clear(); - ui->comboBox_BattleScene->clear(); - ui->checkBox_ShowLocationName->setChecked(false); - ui->checkBox_RequiresFlash->setChecked(false); - ui->checkBox_AllowRunning->setChecked(false); - ui->checkBox_AllowBiking->setChecked(false); - ui->checkBox_AllowEscaping->setChecked(false); - ui->spinBox_FloorNumber->setValue(0); -} - -void MapHeaderForm::refreshLocationsComboBox() { const QSignalBlocker b(ui->comboBox_Location); + const QString before = ui->comboBox_Location->currentText(); ui->comboBox_Location->clear(); - - if (this->project) { - QStringList locations = this->project->mapSectionIdNames; - locations.sort(); - ui->comboBox_Location->addItems(locations); - } - if (this->map) { - ui->comboBox_Location->setCurrentText(this->map->location()); - } + ui->comboBox_Location->addItems(locations); + ui->comboBox_Location->setCurrentText(before); } -void MapHeaderForm::on_comboBox_Song_currentTextChanged(const QString &song) +// Assign a MapHeader that the form will keep in sync with the UI. +void MapHeaderForm::setHeader(MapHeader *header) { + if (m_header == header) + return; + + if (m_header) { + m_header->disconnect(this); + } + + m_header = header; + + if (m_header) { + // If the MapHeader is changed externally (for example, with the scripting API) update the UI accordingly + connect(m_header, &MapHeader::songChanged, this, &MapHeaderForm::updateSong); + connect(m_header, &MapHeader::locationChanged, this, &MapHeaderForm::updateLocation); + connect(m_header, &MapHeader::requiresFlashChanged, this, &MapHeaderForm::updateRequiresFlash); + connect(m_header, &MapHeader::weatherChanged, this, &MapHeaderForm::updateWeather); + connect(m_header, &MapHeader::typeChanged, this, &MapHeaderForm::updateType); + connect(m_header, &MapHeader::battleSceneChanged, this, &MapHeaderForm::updateBattleScene); + connect(m_header, &MapHeader::showsLocationNameChanged, this, &MapHeaderForm::updateShowsLocationName); + connect(m_header, &MapHeader::allowsRunningChanged, this, &MapHeaderForm::updateAllowsRunning); + connect(m_header, &MapHeader::allowsBikingChanged, this, &MapHeaderForm::updateAllowsBiking); + connect(m_header, &MapHeader::allowsEscapingChanged, this, &MapHeaderForm::updateAllowsEscaping); + connect(m_header, &MapHeader::floorNumberChanged, this, &MapHeaderForm::updateFloorNumber); + } + + // Immediately update the UI to reflect the assigned MapHeader + updateUi(); +} + +void MapHeaderForm::clear() { + m_header = nullptr; + updateUi(); +} + +void MapHeaderForm::updateUi() { + updateSong(); + updateLocation(); + updateRequiresFlash(); + updateWeather(); + updateType(); + updateBattleScene(); + updateShowsLocationName(); + updateAllowsRunning(); + updateAllowsBiking(); + updateAllowsEscaping(); + updateFloorNumber(); + +} + +MapHeader MapHeaderForm::headerData() const { + if (m_header) + return *m_header; + + // Build header from UI + MapHeader header; + header.setSong(ui->comboBox_Song->currentText()); + header.setLocation(ui->comboBox_Location->currentText()); + header.setRequiresFlash(ui->checkBox_RequiresFlash->isChecked()); + header.setWeather(ui->comboBox_Weather->currentText()); + header.setType(ui->comboBox_Type->currentText()); + header.setBattleScene(ui->comboBox_BattleScene->currentText()); + header.setShowsLocationName(ui->checkBox_ShowLocationName->isChecked()); + header.setAllowsRunning(ui->checkBox_AllowRunning->isChecked()); + header.setAllowsBiking(ui->checkBox_AllowBiking->isChecked()); + header.setAllowsEscaping(ui->checkBox_AllowEscaping->isChecked()); + header.setFloorNumber(ui->spinBox_FloorNumber->value()); + return header; +} + +void MapHeaderForm::setLocationsDisabled(bool disabled) { + ui->label_Location->setDisabled(disabled); + ui->comboBox_Location->setDisabled(disabled); +} + +void MapHeaderForm::updateSong() { + const QSignalBlocker b(ui->comboBox_Song); + ui->comboBox_Song->setCurrentText(m_header ? m_header->song() : QString()); +} + +void MapHeaderForm::updateLocation() { + const QSignalBlocker b(ui->comboBox_Location); + ui->comboBox_Location->setCurrentText(m_header ? m_header->location() : QString()); +} + +void MapHeaderForm::updateRequiresFlash() { + const QSignalBlocker b(ui->checkBox_RequiresFlash); + ui->checkBox_RequiresFlash->setChecked(m_header ? m_header->requiresFlash() : false); +} + +void MapHeaderForm::updateWeather() { + const QSignalBlocker b(ui->comboBox_Weather); + ui->comboBox_Weather->setCurrentText(m_header ? m_header->weather() : QString()); +} + +void MapHeaderForm::updateType() { + const QSignalBlocker b(ui->comboBox_Type); + ui->comboBox_Type->setCurrentText(m_header ? m_header->type() : QString()); +} + +void MapHeaderForm::updateBattleScene() { + const QSignalBlocker b(ui->comboBox_BattleScene); + ui->comboBox_BattleScene->setCurrentText(m_header ? m_header->battleScene() : QString()); +} + +void MapHeaderForm::updateShowsLocationName() { + const QSignalBlocker b(ui->checkBox_ShowLocationName); + ui->checkBox_ShowLocationName->setChecked(m_header ? m_header->showsLocationName() : false); +} + +void MapHeaderForm::updateAllowsRunning() { + const QSignalBlocker b(ui->checkBox_AllowRunning); + ui->checkBox_AllowRunning->setChecked(m_header ? m_header->allowsRunning() : false); +} + +void MapHeaderForm::updateAllowsBiking() { + const QSignalBlocker b(ui->checkBox_AllowBiking); + ui->checkBox_AllowBiking->setChecked(m_header ? m_header->allowsBiking() : false); +} + +void MapHeaderForm::updateAllowsEscaping() { + const QSignalBlocker b(ui->checkBox_AllowEscaping); + ui->checkBox_AllowEscaping->setChecked(m_header ? m_header->allowsEscaping() : false); +} + +void MapHeaderForm::updateFloorNumber() { + const QSignalBlocker b(ui->spinBox_FloorNumber); + ui->spinBox_FloorNumber->setValue(m_header ? m_header->floorNumber() : 0); +} + +void MapHeaderForm::onSongUpdated(const QString &song) { - if (this->map) { - this->map->setSong(song); - this->map->modify(); - } + if (m_header) m_header->setSong(song); } -void MapHeaderForm::on_comboBox_Location_currentTextChanged(const QString &location) +void MapHeaderForm::onLocationChanged(const QString &location) { - if (this->map) { - this->map->setLocation(location); - this->map->modify(); - - // Update cached location name in the project - // TODO: This should be handled elsewhere now, connected to the map change signal - if (this->project) - this->project->mapNameToMapSectionName.insert(this->map->name(), this->map->location()); - } + if (m_header) m_header->setLocation(location); } -void MapHeaderForm::on_comboBox_Weather_currentTextChanged(const QString &weather) +void MapHeaderForm::onWeatherChanged(const QString &weather) { - if (this->map) { - this->map->setWeather(weather); - this->map->modify(); - } + if (m_header) m_header->setWeather(weather); } -void MapHeaderForm::on_comboBox_Type_currentTextChanged(const QString &type) +void MapHeaderForm::onTypeChanged(const QString &type) { - if (this->map) { - this->map->setType(type); - this->map->modify(); - } + if (m_header) m_header->setType(type); } -void MapHeaderForm::on_comboBox_BattleScene_currentTextChanged(const QString &battleScene) +void MapHeaderForm::onBattleSceneChanged(const QString &battleScene) { - if (this->map) { - this->map->setBattleScene(battleScene); - this->map->modify(); - } + if (m_header) m_header->setBattleScene(battleScene); } -void MapHeaderForm::on_checkBox_RequiresFlash_stateChanged(int selected) +void MapHeaderForm::onRequiresFlashChanged(int selected) { - if (this->map) { - this->map->setRequiresFlash(selected == Qt::Checked); - this->map->modify(); - } + if (m_header) m_header->setRequiresFlash(selected == Qt::Checked); } -void MapHeaderForm::on_checkBox_ShowLocationName_stateChanged(int selected) +void MapHeaderForm::onShowLocationNameChanged(int selected) { - if (this->map) { - this->map->setShowsLocationName(selected == Qt::Checked); - this->map->modify(); - } + if (m_header) m_header->setShowsLocationName(selected == Qt::Checked); } -void MapHeaderForm::on_checkBox_AllowRunning_stateChanged(int selected) +void MapHeaderForm::onAllowRunningChanged(int selected) { - if (this->map) { - this->map->setAllowsRunning(selected == Qt::Checked); - this->map->modify(); - } + if (m_header) m_header->setAllowsRunning(selected == Qt::Checked); } -void MapHeaderForm::on_checkBox_AllowBiking_stateChanged(int selected) +void MapHeaderForm::onAllowBikingChanged(int selected) { - if (this->map) { - this->map->setAllowsBiking(selected == Qt::Checked); - this->map->modify(); - } + if (m_header) m_header->setAllowsBiking(selected == Qt::Checked); } -void MapHeaderForm::on_checkBox_AllowEscaping_stateChanged(int selected) +void MapHeaderForm::onAllowEscapingChanged(int selected) { - if (this->map) { - this->map->setAllowsEscaping(selected == Qt::Checked); - this->map->modify(); - } + if (m_header) m_header->setAllowsEscaping(selected == Qt::Checked); } -void MapHeaderForm::on_spinBox_FloorNumber_valueChanged(int offset) +void MapHeaderForm::onFloorNumberChanged(int offset) { - if (this->map) { - this->map->setFloorNumber(offset); - this->map->modify(); - } + if (m_header) m_header->setFloorNumber(offset); } diff --git a/src/ui/newlayoutform.cpp b/src/ui/newlayoutform.cpp new file mode 100644 index 00000000..ed217fcb --- /dev/null +++ b/src/ui/newlayoutform.cpp @@ -0,0 +1,123 @@ +#include "newlayoutform.h" +#include "ui_newlayoutform.h" +#include "project.h" + +NewLayoutForm::NewLayoutForm(QWidget *parent) + : QWidget(parent) + , ui(new Ui::NewLayoutForm) +{ + ui->setupUi(this); + + // TODO: Read from project? + ui->spinBox_BorderWidth->setMaximum(MAX_BORDER_WIDTH); + ui->spinBox_BorderHeight->setMaximum(MAX_BORDER_HEIGHT); + + connect(ui->spinBox_MapWidth, QOverload::of(&QSpinBox::valueChanged), [=](int){validateMapDimensions();}); + connect(ui->spinBox_MapHeight, QOverload::of(&QSpinBox::valueChanged), [=](int){validateMapDimensions();}); +} + +NewLayoutForm::~NewLayoutForm() +{ + delete ui; +} + +void NewLayoutForm::initUi(Project *project) { + m_project = project; + + ui->comboBox_PrimaryTileset->clear(); + ui->comboBox_SecondaryTileset->clear(); + + if (m_project) { + ui->comboBox_PrimaryTileset->addItems(m_project->primaryTilesetLabels); + ui->comboBox_SecondaryTileset->addItems(m_project->secondaryTilesetLabels); + + ui->spinBox_MapWidth->setMaximum(m_project->getMaxMapWidth()); + ui->spinBox_MapHeight->setMaximum(m_project->getMaxMapHeight()); + } + + ui->groupBox_BorderDimensions->setVisible(projectConfig.useCustomBorderSize); +} + +void NewLayoutForm::setDisabled(bool disabled) { + ui->groupBox_MapDimensions->setDisabled(disabled); + ui->groupBox_BorderDimensions->setDisabled(disabled); + ui->groupBox_Tilesets->setDisabled(disabled); +} + +void NewLayoutForm::setSettings(const Settings &settings) { + ui->spinBox_MapWidth->setValue(settings.width); + ui->spinBox_MapHeight->setValue(settings.height); + ui->spinBox_BorderWidth->setValue(settings.borderWidth); + ui->spinBox_BorderHeight->setValue(settings.borderHeight); + ui->comboBox_PrimaryTileset->setTextItem(settings.primaryTilesetLabel); + ui->comboBox_SecondaryTileset->setTextItem(settings.secondaryTilesetLabel); +} + +NewLayoutForm::Settings NewLayoutForm::settings() const { + NewLayoutForm::Settings settings; + settings.width = ui->spinBox_MapWidth->value(); + settings.height = ui->spinBox_MapHeight->value(); + settings.borderWidth = ui->spinBox_BorderWidth->value(); + settings.borderHeight = ui->spinBox_BorderHeight->value(); + settings.primaryTilesetLabel = ui->comboBox_PrimaryTileset->currentText(); + settings.secondaryTilesetLabel = ui->comboBox_SecondaryTileset->currentText(); + return settings; +} + +bool NewLayoutForm::validate() { + // Make sure to call each validation function so that all errors are shown at once. + bool valid = true; + if (!validateMapDimensions()) valid = false; + if (!validateTilesets()) valid = false; + return valid; +} + +bool NewLayoutForm::validateMapDimensions() { + int size = m_project->getMapDataSize(ui->spinBox_MapWidth->value(), ui->spinBox_MapHeight->value()); + int maxSize = m_project->getMaxMapDataSize(); + + QString errorText; + if (size > maxSize) { + errorText = QString("The specified width and height are too large.\n" + "The maximum map width and height is the following: (width + 15) * (height + 14) <= %1\n" + "The specified map width and height was: (%2 + 15) * (%3 + 14) = %4") + .arg(maxSize) + .arg(ui->spinBox_MapWidth->value()) + .arg(ui->spinBox_MapHeight->value()) + .arg(size); + } + + bool isValid = errorText.isEmpty(); + ui->label_MapDimensionsError->setText(errorText); + ui->label_MapDimensionsError->setVisible(!isValid); + return isValid; +} + +bool NewLayoutForm::validateTilesets() { + QString primaryTileset = ui->comboBox_PrimaryTileset->currentText(); + QString secondaryTileset = ui->comboBox_SecondaryTileset->currentText(); + + QString primaryErrorText; + if (primaryTileset.isEmpty()) { + primaryErrorText = QString("The primary tileset cannot be empty."); + } else if (ui->comboBox_PrimaryTileset->findText(primaryTileset) < 0) { + primaryErrorText = QString("The specified primary tileset '%1' does not exist.").arg(primaryTileset); + } + + QString secondaryErrorText; + if (secondaryTileset.isEmpty()) { + secondaryErrorText = QString("The secondary tileset cannot be empty."); + } else if (ui->comboBox_SecondaryTileset->findText(secondaryTileset) < 0) { + secondaryErrorText = QString("The specified secondary tileset '%2' does not exist.").arg(secondaryTileset); + } + + QString errorText = QString("%1%2%3") + .arg(primaryErrorText) + .arg(!primaryErrorText.isEmpty() ? "\n" : "") + .arg(secondaryErrorText); + + bool isValid = errorText.isEmpty(); + ui->label_TilesetsError->setText(errorText); + ui->label_TilesetsError->setVisible(!isValid); + return isValid; +} diff --git a/src/ui/newmapdialog.cpp b/src/ui/newmapdialog.cpp index da10c26a..9f0a9f18 100644 --- a/src/ui/newmapdialog.cpp +++ b/src/ui/newmapdialog.cpp @@ -16,30 +16,33 @@ NewMapDialog::NewMapDialog(QWidget *parent, Project *project) : QDialog(parent), ui(new Ui::NewMapDialog) { - this->setAttribute(Qt::WA_DeleteOnClose); + setAttribute(Qt::WA_DeleteOnClose); + setModal(true); ui->setupUi(this); this->project = project; - this->existingLayout = false; + this->existingLayout = false; // TODO: Replace, we can determine this from the Layout ID combo box this->importedMap = false; + ui->newLayoutForm->initUi(project); + + ui->comboBox_Group->addItems(project->groupNames); + // Map names and IDs can only contain word characters, and cannot start with a digit. static const QRegularExpression re("[A-Za-z_]+[\\w]*"); auto validator = new QRegularExpressionValidator(re, this); ui->lineEdit_Name->setValidator(validator); - ui->lineEdit_ID->setValidator(validator); + ui->lineEdit_MapID->setValidator(validator); // Create a collapsible section that has all the map header data. - this->headerData = new MapHeaderForm(); + this->headerForm = new MapHeaderForm(); + this->headerForm->init(project); auto sectionLayout = new QVBoxLayout(); - sectionLayout->addWidget(this->headerData); + sectionLayout->addWidget(this->headerForm); this->headerSection = new CollapsibleSection("Header Data", porymapConfig.newMapHeaderSectionExpanded, 150, this); this->headerSection->setContentLayout(sectionLayout); ui->layout_HeaderData->addWidget(this->headerSection); ui->layout_HeaderData->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::Expanding)); - - connect(ui->spinBox_MapWidth, QOverload::of(&QSpinBox::valueChanged), [=](int){validateMapDimensions();}); - connect(ui->spinBox_MapHeight, QOverload::of(&QSpinBox::valueChanged), [=](int){validateMapDimensions();}); } NewMapDialog::~NewMapDialog() @@ -49,57 +52,25 @@ NewMapDialog::~NewMapDialog() } void NewMapDialog::init() { - // Populate combo boxes - ui->comboBox_PrimaryTileset->addItems(project->primaryTilesetLabels); - ui->comboBox_SecondaryTileset->addItems(project->secondaryTilesetLabels); - ui->comboBox_Group->addItems(project->groupNames); - this->headerData->setProject(project); - - // Set spin box limits - ui->spinBox_MapWidth->setMaximum(project->getMaxMapWidth()); - ui->spinBox_MapHeight->setMaximum(project->getMaxMapHeight()); - ui->spinBox_BorderWidth->setMaximum(MAX_BORDER_WIDTH); - ui->spinBox_BorderHeight->setMaximum(MAX_BORDER_HEIGHT); - - ui->groupBox_BorderDimensions->setVisible(projectConfig.useCustomBorderSize); - - // Restore previous settings - ui->lineEdit_Name->setText(project->getNewMapName()); ui->comboBox_Group->setTextItem(settings.group); - ui->spinBox_MapWidth->setValue(settings.width); - ui->spinBox_MapHeight->setValue(settings.height); - ui->spinBox_BorderWidth->setValue(settings.borderWidth); - ui->spinBox_BorderHeight->setValue(settings.borderHeight); - ui->comboBox_PrimaryTileset->setTextItem(settings.primaryTilesetLabel); - ui->comboBox_SecondaryTileset->setTextItem(settings.secondaryTilesetLabel); - this->headerData->ui->comboBox_Song->setTextItem(settings.song); - this->headerData->ui->comboBox_Location->setTextItem(settings.location); - this->headerData->ui->checkBox_RequiresFlash->setChecked(settings.requiresFlash); - this->headerData->ui->comboBox_Weather->setTextItem(settings.weather); - this->headerData->ui->comboBox_Type->setTextItem(settings.type); - this->headerData->ui->comboBox_BattleScene->setTextItem(settings.battleScene); - this->headerData->ui->checkBox_ShowLocationName->setChecked(settings.showLocationName); - this->headerData->ui->checkBox_AllowRunning->setChecked(settings.allowRunning); - this->headerData->ui->checkBox_AllowBiking->setChecked(settings.allowBiking); - this->headerData->ui->checkBox_AllowEscaping->setChecked(settings.allowEscaping); - this->headerData->ui->spinBox_FloorNumber->setValue(settings.floorNumber); ui->checkBox_CanFlyTo->setChecked(settings.canFlyTo); + ui->newLayoutForm->setSettings(settings.layout); + this->headerForm->setHeader(&settings.header); + ui->lineEdit_Name->setText(project->getNewMapName()); } // Creating new map by right-clicking in the map list void NewMapDialog::init(int tabIndex, QString fieldName) { - //initUi(); switch (tabIndex) { case MapListTab::Groups: settings.group = fieldName; - //ui->label_Group->setDisabled(true); - //ui->comboBox_Group->setDisabled(true); + ui->label_Group->setDisabled(true); + ui->comboBox_Group->setDisabled(true); break; case MapListTab::Areas: - settings.location = fieldName; - //ui->label_Location->setDisabled(true); - //ui->comboBox_Location->setDisabled(true); + settings.header.setLocation(fieldName); + this->headerForm->setLocationsDisabled(true); break; case MapListTab::Layouts: useLayout(fieldName); @@ -109,6 +80,7 @@ void NewMapDialog::init(int tabIndex, QString fieldName) { } // Creating new map from AdvanceMap import +// TODO: Re-use for a "Duplicate Map/Layout" option? void NewMapDialog::init(Layout *layout) { this->importedMap = true; useLayoutSettings(layout); @@ -126,91 +98,54 @@ void NewMapDialog::init(Layout *layout) { void NewMapDialog::setDefaultSettings(Project *project) { settings.group = project->groupNames.at(0); - settings.width = project->getDefaultMapDimension(); - settings.height = project->getDefaultMapDimension(); - settings.borderWidth = DEFAULT_BORDER_WIDTH; - settings.borderHeight = DEFAULT_BORDER_HEIGHT; - settings.primaryTilesetLabel = project->getDefaultPrimaryTilesetLabel(); - settings.secondaryTilesetLabel = project->getDefaultSecondaryTilesetLabel(); - settings.song = project->defaultSong; - settings.location = project->mapSectionIdNames.value(0, "0"); - settings.requiresFlash = false; - settings.weather = project->weatherNames.value(0, "0"); - settings.type = project->mapTypes.value(0, "0"); - settings.battleScene = project->mapBattleScenes.value(0, "0"); - settings.showLocationName = true; - settings.allowRunning = false; - settings.allowBiking = false; - settings.allowEscaping = false; - settings.floorNumber = 0; settings.canFlyTo = false; + settings.layout.width = project->getDefaultMapDimension(); + settings.layout.height = project->getDefaultMapDimension(); + settings.layout.borderWidth = DEFAULT_BORDER_WIDTH; + settings.layout.borderHeight = DEFAULT_BORDER_HEIGHT; + settings.layout.primaryTilesetLabel = project->getDefaultPrimaryTilesetLabel(); + settings.layout.secondaryTilesetLabel = project->getDefaultSecondaryTilesetLabel(); + settings.header.setSong(project->defaultSong); + settings.header.setLocation(project->mapSectionIdNames.value(0, "0")); + settings.header.setRequiresFlash(false); + settings.header.setWeather(project->weatherNames.value(0, "0")); + settings.header.setType(project->mapTypes.value(0, "0")); + settings.header.setBattleScene(project->mapBattleScenes.value(0, "0")); + settings.header.setShowsLocationName(true); + settings.header.setAllowsRunning(false); + settings.header.setAllowsBiking(false); + settings.header.setAllowsEscaping(false); + settings.header.setFloorNumber(0); } void NewMapDialog::saveSettings() { settings.group = ui->comboBox_Group->currentText(); - settings.width = ui->spinBox_MapWidth->value(); - settings.height = ui->spinBox_MapHeight->value(); - settings.borderWidth = ui->spinBox_BorderWidth->value(); - settings.borderHeight = ui->spinBox_BorderHeight->value(); - settings.primaryTilesetLabel = ui->comboBox_PrimaryTileset->currentText(); - settings.secondaryTilesetLabel = ui->comboBox_SecondaryTileset->currentText(); - settings.song = this->headerData->ui->comboBox_Song->currentText(); - settings.location = this->headerData->ui->comboBox_Location->currentText(); - settings.requiresFlash = this->headerData->ui->checkBox_RequiresFlash->isChecked(); - settings.weather = this->headerData->ui->comboBox_Weather->currentText(); - settings.type = this->headerData->ui->comboBox_Type->currentText(); - settings.battleScene = this->headerData->ui->comboBox_BattleScene->currentText(); - settings.showLocationName = this->headerData->ui->checkBox_ShowLocationName->isChecked(); - settings.allowRunning = this->headerData->ui->checkBox_AllowRunning->isChecked(); - settings.allowBiking = this->headerData->ui->checkBox_AllowBiking->isChecked(); - settings.allowEscaping = this->headerData->ui->checkBox_AllowEscaping->isChecked(); - settings.floorNumber = this->headerData->ui->spinBox_FloorNumber->value(); settings.canFlyTo = ui->checkBox_CanFlyTo->isChecked(); + settings.layout = ui->newLayoutForm->settings(); + settings.header = this->headerForm->headerData(); porymapConfig.newMapHeaderSectionExpanded = this->headerSection->isExpanded(); } void NewMapDialog::useLayoutSettings(Layout *layout) { if (!layout) return; - settings.width = layout->width; - settings.height = layout->height; - settings.borderWidth = layout->border_width; - settings.borderHeight = layout->border_height; - settings.primaryTilesetLabel = layout->tileset_primary_label; - settings.secondaryTilesetLabel = layout->tileset_secondary_label; + settings.layout.width = layout->width; + settings.layout.height = layout->height; + settings.layout.borderWidth = layout->border_width; + settings.layout.borderHeight = layout->border_height; + settings.layout.primaryTilesetLabel = layout->tileset_primary_label; + settings.layout.secondaryTilesetLabel = layout->tileset_secondary_label; + + // Don't allow changes to the layout settings + ui->newLayoutForm->setDisabled(true); } void NewMapDialog::useLayout(QString layoutId) { this->existingLayout = true; this->layoutId = layoutId; - useLayoutSettings(project->mapLayouts.value(this->layoutId)); - - // Dimensions and tilesets can't be changed for new maps using an existing layout - ui->groupBox_MapDimensions->setDisabled(true); - ui->groupBox_BorderDimensions->setDisabled(true); - ui->groupBox_Tilesets->setDisabled(true); -} - -bool NewMapDialog::validateMapDimensions() { - int size = project->getMapDataSize(ui->spinBox_MapWidth->value(), ui->spinBox_MapHeight->value()); - int maxSize = project->getMaxMapDataSize(); - - QString errorText; - if (size > maxSize) { - errorText = QString("The specified width and height are too large.\n" - "The maximum map width and height is the following: (width + 15) * (height + 14) <= %1\n" - "The specified map width and height was: (%2 + 15) * (%3 + 14) = %4") - .arg(maxSize) - .arg(ui->spinBox_MapWidth->value()) - .arg(ui->spinBox_MapHeight->value()) - .arg(size); - } - - bool isValid = errorText.isEmpty(); - ui->label_MapDimensionsError->setText(errorText); - ui->label_MapDimensionsError->setVisible(!isValid); - return isValid; + useLayoutSettings(project->mapLayouts.value(this->layoutId)); } +// TODO: Create the map group if it doesn't exist bool NewMapDialog::validateMapGroup() { this->group = project->groupNames.indexOf(ui->comboBox_Group->currentText()); @@ -226,37 +161,8 @@ bool NewMapDialog::validateMapGroup() { return isValid; } -bool NewMapDialog::validateTilesets() { - QString primaryTileset = ui->comboBox_PrimaryTileset->currentText(); - QString secondaryTileset = ui->comboBox_SecondaryTileset->currentText(); - - QString primaryErrorText; - if (primaryTileset.isEmpty()) { - primaryErrorText = QString("The primary tileset cannot be empty."); - } else if (ui->comboBox_PrimaryTileset->findText(primaryTileset) < 0) { - primaryErrorText = QString("The specified primary tileset '%1' does not exist.").arg(primaryTileset); - } - - QString secondaryErrorText; - if (secondaryTileset.isEmpty()) { - secondaryErrorText = QString("The secondary tileset cannot be empty."); - } else if (ui->comboBox_SecondaryTileset->findText(secondaryTileset) < 0) { - secondaryErrorText = QString("The specified secondary tileset '%2' does not exist.").arg(secondaryTileset); - } - - QString errorText = QString("%1%2%3") - .arg(primaryErrorText) - .arg(!primaryErrorText.isEmpty() ? "\n" : "") - .arg(secondaryErrorText); - - bool isValid = errorText.isEmpty(); - ui->label_TilesetsError->setText(errorText); - ui->label_TilesetsError->setVisible(!isValid); - return isValid; -} - bool NewMapDialog::validateID() { - QString id = ui->lineEdit_ID->text(); + QString id = ui->lineEdit_MapID->text(); QString errorText; QString expectedPrefix = projectConfig.getIdentifier(ProjectIdentifier::define_map_prefix); @@ -272,13 +178,13 @@ bool NewMapDialog::validateID() { } bool isValid = errorText.isEmpty(); - ui->label_IDError->setText(errorText); - ui->label_IDError->setVisible(!isValid); - ui->lineEdit_ID->setStyleSheet(!isValid ? lineEdit_ErrorStylesheet : ""); + ui->label_MapIDError->setText(errorText); + ui->label_MapIDError->setVisible(!isValid); + ui->lineEdit_MapID->setStyleSheet(!isValid ? lineEdit_ErrorStylesheet : ""); return isValid; } -void NewMapDialog::on_lineEdit_ID_textChanged(const QString &) { +void NewMapDialog::on_lineEdit_MapID_textChanged(const QString &) { validateID(); } @@ -299,22 +205,23 @@ bool NewMapDialog::validateName() { void NewMapDialog::on_lineEdit_Name_textChanged(const QString &text) { validateName(); - ui->lineEdit_ID->setText(Map::mapConstantFromName(text)); + ui->lineEdit_MapID->setText(Map::mapConstantFromName(text)); } void NewMapDialog::on_pushButton_Accept_clicked() { + saveSettings(); + // Make sure to call each validation function so that all errors are shown at once. bool success = true; - if (!validateMapDimensions()) success = false; + if (!ui->newLayoutForm->validate()) success = false; if (!validateMapGroup()) success = false; - if (!validateTilesets()) success = false; if (!validateID()) success = false; if (!validateName()) success = false; if (!success) return; - // We check if the map name is empty separately from the validation above because it's likely - // that users will clear the name text box while editing, and we don't want to flash errors at them for this. + // We check if the map name is empty separately from validateName, because validateName is also used during editing. + // It's likely that users will clear the name text box while editing, and we don't want to flash errors at them for this. if (ui->lineEdit_Name->text().isEmpty()) { ui->label_NameError->setText("The specified map name cannot be empty."); ui->label_NameError->setVisible(true); @@ -324,23 +231,9 @@ void NewMapDialog::on_pushButton_Accept_clicked() { Map *newMap = new Map; newMap->setName(ui->lineEdit_Name->text()); - newMap->setConstantName(ui->lineEdit_ID->text()); - newMap->setSong(this->headerData->ui->comboBox_Song->currentText()); - newMap->setLocation(this->headerData->ui->comboBox_Location->currentText()); - newMap->setRequiresFlash(this->headerData->ui->checkBox_RequiresFlash->isChecked()); - newMap->setWeather(this->headerData->ui->comboBox_Weather->currentText()); - newMap->setType(this->headerData->ui->comboBox_Type->currentText()); - newMap->setBattleScene(this->headerData->ui->comboBox_BattleScene->currentText()); - newMap->setShowsLocationName(this->headerData->ui->checkBox_ShowLocationName->isChecked()); - if (projectConfig.mapAllowFlagsEnabled) { - newMap->setAllowsRunning(this->headerData->ui->checkBox_AllowRunning->isChecked()); - newMap->setAllowsBiking(this->headerData->ui->checkBox_AllowBiking->isChecked()); - newMap->setAllowsEscaping(this->headerData->ui->checkBox_AllowEscaping->isChecked()); - } - if (projectConfig.floorNumberEnabled) { - newMap->setFloorNumber(this->headerData->ui->spinBox_FloorNumber->value()); - } - newMap->setNeedsHealLocation(ui->checkBox_CanFlyTo->isChecked()); + newMap->setConstantName(ui->lineEdit_MapID->text()); + newMap->setHeader(this->headerForm->headerData()); + newMap->setNeedsHealLocation(settings.canFlyTo); Layout *layout; if (this->existingLayout) { @@ -350,17 +243,17 @@ void NewMapDialog::on_pushButton_Accept_clicked() { layout = new Layout; layout->id = Layout::layoutConstantFromName(newMap->name()); layout->name = QString("%1_Layout").arg(newMap->name()); - layout->width = ui->spinBox_MapWidth->value(); - layout->height = ui->spinBox_MapHeight->value(); + layout->width = settings.layout.width; + layout->height = settings.layout.height; if (projectConfig.useCustomBorderSize) { - layout->border_width = ui->spinBox_BorderWidth->value(); - layout->border_height = ui->spinBox_BorderHeight->value(); + layout->border_width = settings.layout.borderWidth; + layout->border_height = settings.layout.borderHeight; } else { layout->border_width = DEFAULT_BORDER_WIDTH; layout->border_height = DEFAULT_BORDER_HEIGHT; } - layout->tileset_primary_label = ui->comboBox_PrimaryTileset->currentText(); - layout->tileset_secondary_label = ui->comboBox_SecondaryTileset->currentText(); + layout->tileset_primary_label = settings.layout.primaryTilesetLabel; + layout->tileset_secondary_label = settings.layout.secondaryTilesetLabel; QString basePath = projectConfig.getFilePath(ProjectFilePath::data_layouts_folders); layout->border_path = QString("%1%2/border.bin").arg(basePath, newMap->name()); layout->blockdata_path = QString("%1%2/map.bin").arg(basePath, newMap->name());