mirror of
https://github.com/huderlem/porymap.git
synced 2026-03-21 17:45:44 -05:00
Merge branch 'dev' into update-scripts
This commit is contained in:
commit
5c9cf80a03
|
|
@ -21,10 +21,12 @@ The **"Breaking Changes"** listed below are changes that have been made in the d
|
|||
- Add an input field to the Tileset Editor for editing the full metatile attributes value directly, including unused bits.
|
||||
- An alert will be displayed when attempting to open a seemingly invalid project.
|
||||
- Add support for defining project values with `enum` where `#define` was expected.
|
||||
- Add support for referring to object events and warps with named IDs, rather than referring to them with their index number.
|
||||
- Add a setting to specify the tile values to use for the unused metatile layer.
|
||||
- Add a setting to specify the maximum number of events in a group. A warning will be shown if too many events are added.
|
||||
- Add a setting to customize the size and position of the player view distance.
|
||||
- Add `onLayoutOpened` to the scripting API.
|
||||
- Add a splash loading screen for project openings.
|
||||
|
||||
### Changed
|
||||
- `Change Dimensions` now has an interactive resizing rectangle.
|
||||
|
|
@ -67,9 +69,13 @@ The **"Breaking Changes"** listed below are changes that have been made in the d
|
|||
- Fix config files being written before the project is opened successfully.
|
||||
- Fix the map and other project info still displaying if a new project fails to open.
|
||||
- Fix unsaved changes being ignored when quitting (such as with Cmd+Q on macOS).
|
||||
- Fix selections with multiple Events not always clearing when making a new selection.
|
||||
- Fix selections with multiple events not always clearing when making a new selection.
|
||||
- Fix the new event button not updating correctly when selecting object events.
|
||||
- Fix duplicated `Hidden Item` events not copying the `Requires Itemfinder` field.
|
||||
- Fix event sprites disappearing in certain areas outside the map boundaries.
|
||||
- Fix deselecting an event still allowing you to drag the event around.
|
||||
- Fix events rendering on top of the ruler at very high y values.
|
||||
- Fix new map names not appearing in event dropdowns that have already been populated.
|
||||
- Fix `About porymap` opening a new window each time it's activated.
|
||||
- Fix the `Edit History` window not raising to the front when reactivated.
|
||||
- New maps are now always inserted in map dropdowns at the correct position, rather than at the bottom of the list until the project is reloaded.
|
||||
|
|
@ -97,6 +103,7 @@ The **"Breaking Changes"** listed below are changes that have been made in the d
|
|||
- Fix exporting a timelapse sometimes altering the state of the current map's edit history.
|
||||
- Stop sliders in the Palette Editor from creating a bunch of edit history when used.
|
||||
- Fix scrolling on some containers locking up when the mouse stops over a spin box or combo box.
|
||||
- Fix the selection index for some combo boxes differing from their displayed text.
|
||||
- Fix some file dialogs returning to an incorrect window when closed.
|
||||
- Fix bug where reloading a layout would overwrite all unsaved changes.
|
||||
- Fix bug where layout json and blockdata could be saved separately leading to inconsistent data.
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ Callbacks
|
|||
|
||||
Called when the mouse exits the map.
|
||||
|
||||
.. js:function:: onMapResized(oldWidth, oldHeight, newWidth, newHeight)
|
||||
.. js:function:: onMapResized(oldWidth, oldHeight, delta)
|
||||
|
||||
Called when the dimensions of the map are changed.
|
||||
|
||||
|
|
@ -212,10 +212,8 @@ Callbacks
|
|||
:type oldWidth: number
|
||||
:param oldHeight: the height of the map before the change
|
||||
:type oldHeight: number
|
||||
:param newWidth: the width of the map after the change
|
||||
:type newWidth: number
|
||||
:param newHeight: the height of the map after the change
|
||||
:type newHeight: number
|
||||
:param delta: the amount the map size changed in each direction. The object's shape is ``{left, right, top, bottom}``
|
||||
:type prevBlock: delta
|
||||
|
||||
.. js:function:: onBorderResized(oldWidth, oldHeight, newWidth, newHeight)
|
||||
|
||||
|
|
|
|||
157
forms/loadingscreen.ui
Normal file
157
forms/loadingscreen.ui
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>LoadingScreen</class>
|
||||
<widget class="QWidget" name="LoadingScreen">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::WindowModality::ApplicationModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>366</width>
|
||||
<height>255</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>BusyCursor</cursorShape>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::ContextMenuPolicy::NoContextMenu</enum>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="labelPorymap">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>20</pointsize>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>porymap</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="labelVersion">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Version X.x.x</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_2">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="labelPixmap">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>64</width>
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>IMAGE</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="labelText">
|
||||
<property name="text">
|
||||
<string>Loading....</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -2733,7 +2733,10 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboBox_EncounterGroupLabel">
|
||||
<widget class="NoScrollComboBox" name="comboBox_EncounterGroupLabel">
|
||||
<property name="editable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::SizeAdjustPolicy::AdjustToContents</enum>
|
||||
</property>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@
|
|||
<height>380</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::FocusPolicy::ClickFocus</enum>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
|
|
|
|||
89
forms/newdefinedialog.ui
Normal file
89
forms/newdefinedialog.ui
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>NewDefineDialog</class>
|
||||
<widget class="QDialog" name="NewDefineDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>252</width>
|
||||
<height>124</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QFrame" name="form">
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_Name">
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_Name">
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_NameError">
|
||||
<property name="visible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: rgb(255, 0, 0)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_Value"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_Value">
|
||||
<property name="text">
|
||||
<string>Value</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
|
||||
</property>
|
||||
<property name="centerButtons">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -1582,19 +1582,21 @@
|
|||
<height>499</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_10">
|
||||
<item>
|
||||
<widget class="QToolButton" name="button_HelpFiles">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
<layout class="QGridLayout" name="gridLayout_10" rowstretch="1,2,8">
|
||||
<item row="0" column="1">
|
||||
<spacer name="horizontalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/help.ico</normaloff>:/icons/help.ico</iconset>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<item row="2" column="0" colspan="3">
|
||||
<widget class="QWidget" name="widget_ProjectPaths" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<property name="spacing">
|
||||
|
|
@ -1626,7 +1628,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>544</width>
|
||||
<height>437</height>
|
||||
<height>338</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="layout_ProjectPaths">
|
||||
|
|
@ -1646,6 +1648,34 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="button_AddGlobalConstantsFile">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Add additional C files containing #defines or enums. These will be used to resolve unknown symbols during project launch.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add Global Constants File...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/add.ico</normaloff>:/icons/add.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QToolButton" name="button_HelpFiles">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/help.ico</normaloff>:/icons/help.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="3">
|
||||
<layout class="QGridLayout" name="gridLayout_GlobalConstantsFiles"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
|
|
@ -1671,8 +1701,8 @@
|
|||
<height>499</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_19">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_11">
|
||||
<item row="0" column="0">
|
||||
<widget class="QToolButton" name="button_HelpIdentifiers">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
|
|
@ -1683,7 +1713,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item row="2" column="0" colspan="3">
|
||||
<widget class="QWidget" name="widget_Identifiers" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_20">
|
||||
<property name="spacing">
|
||||
|
|
@ -1715,7 +1745,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>544</width>
|
||||
<height>437</height>
|
||||
<height>421</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="layout_Identifiers">
|
||||
|
|
@ -1735,6 +1765,36 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="button_AddGlobalConstant">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Add an additional #define name and expression. This may be used to evaluate other #defines during project launch.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add Global Constant...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/add.ico</normaloff>:/icons/add.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<spacer name="horizontalSpacer_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="3">
|
||||
<layout class="QGridLayout" name="gridLayout_GlobalConstants"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="comboBox_Species">
|
||||
<widget class="NoScrollComboBox" name="comboBox_Species">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
|
|
@ -237,6 +237,11 @@
|
|||
<extends>QGraphicsView</extends>
|
||||
<header>QtCharts</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>NoScrollComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>noscrollcombobox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../resources/images.qrc"/>
|
||||
|
|
|
|||
|
|
@ -345,6 +345,8 @@ public:
|
|||
this->unusedTileCovered = 0x0000;
|
||||
this->unusedTileSplit = 0x0000;
|
||||
this->maxEventsPerGroup = 255;
|
||||
this->globalConstantsFilepaths.clear();
|
||||
this->globalConstants.clear();
|
||||
this->identifiers.clear();
|
||||
this->readKeys.clear();
|
||||
}
|
||||
|
|
@ -417,6 +419,8 @@ public:
|
|||
QMargins playerViewDistance;
|
||||
QList<uint32_t> warpBehaviors;
|
||||
int maxEventsPerGroup;
|
||||
QStringList globalConstantsFilepaths;
|
||||
QMap<QString,QString> globalConstants;
|
||||
|
||||
protected:
|
||||
virtual QString getConfigFilepath() override;
|
||||
|
|
|
|||
|
|
@ -107,8 +107,8 @@ public:
|
|||
void setBlock(int x, int y, Block block, bool enableScriptCallback = false);
|
||||
void setBlockdata(Blockdata blockdata, bool enableScriptCallback = false);
|
||||
|
||||
void adjustDimensions(QMargins margins, bool setNewBlockdata = true);
|
||||
void setDimensions(int newWidth, int newHeight, bool setNewBlockdata = true, bool enableScriptCallback = false);
|
||||
void adjustDimensions(const QMargins &margins, bool setNewBlockdata = true);
|
||||
void setDimensions(int newWidth, int newHeight, bool setNewBlockdata = true);
|
||||
void setBorderDimensions(int newWidth, int newHeight, bool setNewBlockdata = true, bool enableScriptCallback = false);
|
||||
|
||||
void cacheBlockdata();
|
||||
|
|
|
|||
|
|
@ -43,8 +43,13 @@ class ParseUtil
|
|||
{
|
||||
public:
|
||||
ParseUtil();
|
||||
void set_root(const QString &dir);
|
||||
|
||||
void setRoot(const QString &dir) { this->root = dir; }
|
||||
void setUpdatesSplashScreen(bool updates) { this->updatesSplashScreen = updates; }
|
||||
|
||||
static QString readTextFile(const QString &path, QString *error = nullptr);
|
||||
QString loadTextFile(const QString &path, QString *error = nullptr);
|
||||
|
||||
bool cacheFile(const QString &path, QString *error = nullptr);
|
||||
void clearFileCache() { this->fileCache.clear(); }
|
||||
static int textFileLineCount(const QString &path);
|
||||
|
|
@ -55,9 +60,13 @@ public:
|
|||
QString readCIncbin(const QString &text, const QString &label);
|
||||
QMap<QString, QString> readCIncbinMulti(const QString &filepath);
|
||||
QStringList readCIncbinArray(const QString &filename, const QString &label);
|
||||
QMap<QString, int> readCDefinesByRegex(const QString &filename, const QSet<QString> ®exList, QString *error = nullptr);
|
||||
QMap<QString, int> readCDefinesByName(const QString &filename, const QSet<QString> &names, QString *error = nullptr);
|
||||
QHash<QString, int> readCDefinesByRegex(const QString &filename, const QSet<QString> ®exList, QString *error = nullptr);
|
||||
QHash<QString, int> readCDefinesByName(const QString &filename, const QSet<QString> &names, QString *error = nullptr);
|
||||
QStringList readCDefineNames(const QString &filename, const QSet<QString> ®exList, QString *error = nullptr);
|
||||
void loadGlobalCDefinesFromFile(const QString &filename, QString *error = nullptr);
|
||||
void loadGlobalCDefines(const QMap<QString,QString> &defines);
|
||||
void loadGlobalCDefines(const QHash<QString,QString> &defines);
|
||||
void resetCDefines();
|
||||
OrderedMap<QString, QHash<QString, QString>> readCStructs(const QString &, const QString & = "", const QHash<int, QString>& = {});
|
||||
QList<QStringList> getLabelMacros(const QList<QStringList>&, const QString&);
|
||||
QStringList getLabelValues(const QList<QStringList>&, const QString&);
|
||||
|
|
@ -90,24 +99,38 @@ private:
|
|||
QString curDefine;
|
||||
QHash<QString, QString> fileCache;
|
||||
QHash<QString, QStringList> errorMap;
|
||||
int evaluateDefine(const QString&, const QString &, QMap<QString, int>*, QMap<QString, QString>*);
|
||||
QList<Token> tokenizeExpression(QString, QMap<QString, int>*, QMap<QString, QString>*);
|
||||
|
||||
// The maps of define names to values/expressions that are available while parsing C defines.
|
||||
// As the parser reads and evaluates more defines it will update these maps accordingly.
|
||||
QHash<QString, int> knownDefineValues;
|
||||
QHash<QString, QString> knownDefineExpressions;
|
||||
|
||||
// Maps of special define names to values/expressions that take precedence over defines encountered while parsing.
|
||||
// Some (like 'TRUE'/'FALSE') are always present in these maps, others may be specified by the user with 'loadGlobalCDefines' / 'loadGlobalCDefinesFromFile'.
|
||||
QHash<QString, int> globalDefineValues;
|
||||
QHash<QString, QString> globalDefineExpressions;
|
||||
|
||||
bool updatesSplashScreen = false;
|
||||
|
||||
int evaluateDefine(const QString &identifier, bool *ok = nullptr);
|
||||
int evaluateExpression(const QString &expression);
|
||||
QList<Token> tokenizeExpression(QString expression);
|
||||
QList<Token> generatePostfix(const QList<Token> &tokens);
|
||||
int evaluatePostfix(const QList<Token> &postfix);
|
||||
void recordError(const QString &message);
|
||||
void recordErrors(const QStringList &errors);
|
||||
void logRecordedErrors();
|
||||
QString createErrorMessage(const QString &message, const QString &expression);
|
||||
void updateSplashScreen(QString path);
|
||||
|
||||
struct ParsedDefines {
|
||||
QMap<QString,QString> expressions; // Map of all define names encountered to their expressions
|
||||
QHash<QString,QString> expressions; // Map of all define names encountered to their expressions
|
||||
QStringList filteredNames; // List of define names that matched the search text, in the order that they were encountered
|
||||
};
|
||||
ParsedDefines readCDefines(const QString &filename, const QSet<QString> &filterList, bool useRegex, QString *error);
|
||||
QMap<QString, int> evaluateCDefines(const QString &filename, const QSet<QString> &filterList, bool useRegex, QString *error);
|
||||
QHash<QString, int> evaluateCDefines(const QString &filename, const QSet<QString> &filterList, bool useRegex, QString *error);
|
||||
bool defineNameMatchesFilter(const QString &name, const QSet<QString> &filterList) const;
|
||||
bool defineNameMatchesFilter(const QString &name, const QSet<QRegularExpression> &filterList) const;
|
||||
QString loadTextFile(const QString &path, QString *error = nullptr);
|
||||
QString pathWithRoot(const QString &path);
|
||||
|
||||
static const QRegularExpression re_incScriptLabel;
|
||||
|
|
|
|||
|
|
@ -67,9 +67,9 @@ public:
|
|||
bool saveTilesImage();
|
||||
bool savePalettes();
|
||||
|
||||
bool appendToHeaders(QString root, QString friendlyName, bool usingAsm);
|
||||
bool appendToGraphics(QString root, QString friendlyName, bool usingAsm);
|
||||
bool appendToMetatiles(QString root, QString friendlyName, bool usingAsm);
|
||||
bool appendToHeaders(const QString &filepath, const QString &friendlyName, bool usingAsm);
|
||||
bool appendToGraphics(const QString &filepath, const QString &friendlyName, bool usingAsm);
|
||||
bool appendToMetatiles(const QString &filepath, const QString &friendlyName, bool usingAsm);
|
||||
|
||||
void setTilesImage(const QImage &image);
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ public:
|
|||
MainWindow(const MainWindow &) = delete;
|
||||
MainWindow & operator = (const MainWindow &) = delete;
|
||||
|
||||
void initialize();
|
||||
|
||||
// Scripting API
|
||||
Q_INVOKABLE QJSValue getBlock(int x, int y);
|
||||
void tryRedrawMapArea(bool forceRedraw);
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ public:
|
|||
int maxEncounterRate;
|
||||
bool wildEncountersLoaded;
|
||||
|
||||
void set_root(QString);
|
||||
void setRoot(const QString&);
|
||||
|
||||
void clearMaps();
|
||||
void clearTilesetCache();
|
||||
|
|
@ -203,6 +203,7 @@ public:
|
|||
bool readEventGraphics();
|
||||
bool readFieldmapProperties();
|
||||
bool readFieldmapMasks();
|
||||
bool readGlobalConstants();
|
||||
QMap<QString, QMap<QString, QString>> readObjEventGfxInfo();
|
||||
|
||||
QPixmap getEventPixmap(const QString &gfxName, const QString &movementName);
|
||||
|
|
@ -307,7 +308,10 @@ private:
|
|||
void setNewLayoutBlockdata(Layout *layout);
|
||||
void setNewLayoutBorder(Layout *layout);
|
||||
|
||||
void ignoreWatchedFileTemporarily(QString filepath);
|
||||
void watchFile(const QString &filename);
|
||||
void watchFiles(const QStringList &filenames);
|
||||
void ignoreWatchedFileTemporarily(const QString &filepath);
|
||||
void ignoreWatchedFilesTemporarily(const QStringList &filepaths);
|
||||
void recordFileChange(const QString &filepath);
|
||||
void resetFileCache();
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ public:
|
|||
static void populateGlobalObject(MainWindow *mainWindow);
|
||||
static QJSEngine *getEngine();
|
||||
static void invokeAction(int actionIndex);
|
||||
|
||||
static void cb_ProjectOpened(QString projectPath);
|
||||
static void cb_ProjectClosed(QString projectPath);
|
||||
static void cb_MetatileChanged(int x, int y, Block prevBlock, Block newBlock);
|
||||
|
|
@ -47,18 +48,20 @@ public:
|
|||
static void cb_BlockHoverCleared();
|
||||
static void cb_MapOpened(QString mapName);
|
||||
static void cb_LayoutOpened(QString layoutName);
|
||||
static void cb_MapResized(int oldWidth, int oldHeight, int newWidth, int newHeight);
|
||||
static void cb_MapResized(int oldWidth, int oldHeight, const QMargins &delta);
|
||||
static void cb_BorderResized(int oldWidth, int oldHeight, int newWidth, int newHeight);
|
||||
static void cb_MapShifted(int xDelta, int yDelta);
|
||||
static void cb_TilesetUpdated(QString tilesetName);
|
||||
static void cb_MainTabChanged(int oldTab, int newTab);
|
||||
static void cb_MapViewTabChanged(int oldTab, int newTab);
|
||||
static void cb_BorderVisibilityToggled(bool visible);
|
||||
|
||||
static bool tryErrorJS(QJSValue js);
|
||||
static QJSValue fromBlock(Block block);
|
||||
static QJSValue fromTile(Tile tile);
|
||||
static Tile toTile(QJSValue obj);
|
||||
static QJSValue dimensions(int width, int height);
|
||||
static QJSValue margins(const QMargins &margins);
|
||||
static QJSValue position(int x, int y);
|
||||
static const QImage * getImage(const QString &filepath, bool useCache);
|
||||
static QJSValue dialogInput(QJSValue input, bool selectedOk);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ class AboutPorymap : public QDialog
|
|||
public:
|
||||
explicit AboutPorymap(QWidget *parent = nullptr);
|
||||
~AboutPorymap();
|
||||
|
||||
static QString getVersionString();
|
||||
private:
|
||||
Ui::AboutPorymap *ui;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#define DIVINGMAPPIXMAPITEM_H
|
||||
|
||||
#include "mapconnection.h"
|
||||
#include "noscrollcombobox.h"
|
||||
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QPointer>
|
||||
|
|
@ -10,7 +11,7 @@
|
|||
class DivingMapPixmapItem : public QObject, public QGraphicsPixmapItem {
|
||||
Q_OBJECT
|
||||
public:
|
||||
DivingMapPixmapItem(MapConnection *connection, QComboBox *combo);
|
||||
DivingMapPixmapItem(MapConnection *connection, NoScrollComboBox *combo);
|
||||
~DivingMapPixmapItem();
|
||||
|
||||
MapConnection* connection() const { return m_connection; }
|
||||
|
|
@ -18,7 +19,7 @@ public:
|
|||
|
||||
private:
|
||||
QPointer<MapConnection> m_connection;
|
||||
QPointer<QComboBox> m_combo;
|
||||
QPointer<NoScrollComboBox> m_combo;
|
||||
|
||||
void setComboText(const QString &text);
|
||||
static QPixmap getBasePixmap(MapConnection* connection);
|
||||
|
|
|
|||
43
include/ui/loadingscreen.h
Normal file
43
include/ui/loadingscreen.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#include "qgifimage.h"
|
||||
|
||||
#include <QSplashScreen>
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
|
||||
|
||||
namespace Ui {
|
||||
class LoadingScreen;
|
||||
}
|
||||
|
||||
class PorymapLoadingScreen : public QWidget {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PorymapLoadingScreen(QWidget *parent = nullptr);
|
||||
~PorymapLoadingScreen();
|
||||
|
||||
void setPixmap(const QPixmap &pixmap);
|
||||
void showMessage(const QString &text);
|
||||
void showMessage(const QString &prefix, const QString &text);
|
||||
void showLoadingMessage(const QString &text);
|
||||
|
||||
void start();
|
||||
void stop ();
|
||||
|
||||
private:
|
||||
void setupUi();
|
||||
|
||||
public slots:
|
||||
void updateFrame();
|
||||
|
||||
private:
|
||||
Ui::LoadingScreen *ui;
|
||||
|
||||
QGifImage splashImage;
|
||||
int frame = 0;
|
||||
QTimer timer;
|
||||
};
|
||||
|
||||
extern PorymapLoadingScreen *porysplash;
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "mapheader.h"
|
||||
#include "project.h"
|
||||
#include "noscrollcombobox.h"
|
||||
|
||||
namespace Ui {
|
||||
class MapHeaderForm;
|
||||
|
|
@ -64,7 +65,7 @@ private:
|
|||
QPointer<Project> m_project = nullptr;
|
||||
bool m_allowProjectChanges = true;
|
||||
|
||||
void setText(QComboBox *combo, const QString &text) const;
|
||||
void setText(NoScrollComboBox *combo, const QString &text) const;
|
||||
void setText(QLineEdit *lineEdit, const QString &text) const;
|
||||
void setLocations(const QStringList &locations);
|
||||
void updateLocationName();
|
||||
|
|
|
|||
|
|
@ -24,21 +24,21 @@ public:
|
|||
class ErrorMessage : public Message {
|
||||
public:
|
||||
ErrorMessage(const QString &message, QWidget *parent);
|
||||
static int show(const QString &message, QWidget *parent);
|
||||
static void show(const QString &message, QWidget *parent);
|
||||
};
|
||||
|
||||
// Basic warning message with an 'Ok' button.
|
||||
class WarningMessage : public Message {
|
||||
public:
|
||||
WarningMessage(const QString &message, QWidget *parent);
|
||||
static int show(const QString &message, QWidget *parent);
|
||||
static void show(const QString &message, QWidget *parent);
|
||||
};
|
||||
|
||||
// Basic informational message with a 'Close' button.
|
||||
class InfoMessage : public Message {
|
||||
public:
|
||||
InfoMessage(const QString &message, QWidget *parent);
|
||||
static int show(const QString &message, QWidget *parent);
|
||||
static void show(const QString &message, QWidget *parent);
|
||||
};
|
||||
|
||||
// Basic question message with a 'Yes' and 'No' button.
|
||||
|
|
@ -53,7 +53,7 @@ public:
|
|||
class RecentErrorMessage : public ErrorMessage {
|
||||
public:
|
||||
RecentErrorMessage(const QString &message, QWidget *parent);
|
||||
static int show(const QString &message, QWidget *parent);
|
||||
static void show(const QString &message, QWidget *parent);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public:
|
|||
}
|
||||
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) override {
|
||||
if (!(*enabled)) return;
|
||||
if (!isVisible()) return;
|
||||
painter->setPen(this->color);
|
||||
painter->drawRect(this->rect() + QMargins(1,1,1,1)); // Fill
|
||||
painter->setPen(Qt::black);
|
||||
|
|
@ -28,11 +28,17 @@ public:
|
|||
painter->drawRect(this->rect()); // Inner border
|
||||
}
|
||||
void updateLocation(int x, int y);
|
||||
bool *enabled;
|
||||
|
||||
void setActive(bool active);
|
||||
bool getActive() const { return this->active; }
|
||||
|
||||
protected:
|
||||
bool *enabled = nullptr;
|
||||
bool active = true;
|
||||
QRectF baseRect;
|
||||
QRgb color;
|
||||
|
||||
void updateVisibility();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
32
include/ui/newdefinedialog.h
Normal file
32
include/ui/newdefinedialog.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef NEWDEFINEDIALOG_H
|
||||
#define NEWDEFINEDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QAbstractButton>
|
||||
|
||||
namespace Ui {
|
||||
class NewDefineDialog;
|
||||
}
|
||||
|
||||
class NewDefineDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit NewDefineDialog(QWidget *parent = nullptr);
|
||||
~NewDefineDialog();
|
||||
|
||||
virtual void accept() override;
|
||||
|
||||
signals:
|
||||
void createdDefine(const QString &name, const QString &expression);
|
||||
|
||||
private:
|
||||
Ui::NewDefineDialog *ui;
|
||||
|
||||
bool validateName(bool allowEmpty = false);
|
||||
void onNameChanged(const QString &name);
|
||||
void dialogButtonClicked(QAbstractButton *button);
|
||||
};
|
||||
|
||||
#endif // NEWDEFINEDIALOG_H
|
||||
|
|
@ -67,6 +67,12 @@ private:
|
|||
void setWarpBehaviorsList(QStringList list);
|
||||
void openFilesHelp();
|
||||
void openIdentifiersHelp();
|
||||
void addNewGlobalConstantsFilepath();
|
||||
void addGlobalConstantsFilepath(const QString &filepath);
|
||||
QStringList getGlobalConstantsFilepaths();
|
||||
void addNewGlobalConstant();
|
||||
void addGlobalConstant(const QString &name, const QString &expression);
|
||||
QMap<QString,QString> getGlobalConstants();
|
||||
|
||||
private slots:
|
||||
void dialogButtonClicked(QAbstractButton *button);
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ SOURCES += src/core/advancemapparser.cpp \
|
|||
src/ui/metatileselector.cpp \
|
||||
src/ui/movablerect.cpp \
|
||||
src/ui/movementpermissionsselector.cpp \
|
||||
src/ui/newdefinedialog.cpp \
|
||||
src/ui/neweventtoolbutton.cpp \
|
||||
src/ui/newlayoutdialog.cpp \
|
||||
src/ui/newlayoutform.cpp \
|
||||
|
|
@ -133,6 +134,7 @@ SOURCES += src/core/advancemapparser.cpp \
|
|||
src/ui/preferenceeditor.cpp \
|
||||
src/ui/regionmappropertiesdialog.cpp \
|
||||
src/ui/colorpicker.cpp \
|
||||
src/ui/loadingscreen.cpp \
|
||||
src/config.cpp \
|
||||
src/editor.cpp \
|
||||
src/main.cpp \
|
||||
|
|
@ -216,6 +218,7 @@ HEADERS += include/core/advancemapparser.h \
|
|||
include/ui/metatileselector.h \
|
||||
include/ui/movablerect.h \
|
||||
include/ui/movementpermissionsselector.h \
|
||||
include/ui/newdefinedialog.h \
|
||||
include/ui/neweventtoolbutton.h \
|
||||
include/ui/newlayoutdialog.h \
|
||||
include/ui/newlayoutform.h \
|
||||
|
|
@ -248,6 +251,7 @@ HEADERS += include/core/advancemapparser.h \
|
|||
include/ui/preferenceeditor.h \
|
||||
include/ui/regionmappropertiesdialog.h \
|
||||
include/ui/colorpicker.h \
|
||||
include/ui/loadingscreen.h \
|
||||
include/config.h \
|
||||
include/editor.h \
|
||||
include/mainwindow.h \
|
||||
|
|
@ -267,8 +271,10 @@ FORMS += forms/mainwindow.ui \
|
|||
forms/connectionslistitem.ui \
|
||||
forms/customattributesframe.ui \
|
||||
forms/gridsettingsdialog.ui \
|
||||
forms/loadingscreen.ui \
|
||||
forms/mapheaderform.ui \
|
||||
forms/maplisttoolbar.ui \
|
||||
forms/newdefinedialog.ui \
|
||||
forms/newlayoutdialog.ui \
|
||||
forms/newlayoutform.ui \
|
||||
forms/newlocationdialog.ui \
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@
|
|||
<file>images/collisions_unknown.png</file>
|
||||
<file>images/Entities_16x16.png</file>
|
||||
<file>images/pokemon_icon_placeholder.png</file>
|
||||
<file>images/porysplash.gif</file>
|
||||
<file>icons/clipboard.ico</file>
|
||||
<file>icons/map_go.ico</file>
|
||||
</qresource>
|
||||
|
|
|
|||
BIN
resources/images/porysplash.gif
Normal file
BIN
resources/images/porysplash.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
|
|
@ -39,7 +39,7 @@ export function onBlockHoverCleared() {
|
|||
}
|
||||
|
||||
// Called when the dimensions of the map are changed.
|
||||
export function onMapResized(oldWidth, oldHeight, newWidth, newHeight) {
|
||||
export function onMapResized(oldWidth, oldHeight, delta) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@ void KeyValueConfigBase::load() {
|
|||
continue;
|
||||
}
|
||||
|
||||
this->parseConfigKeyValue(match.captured("key").trimmed().toLower(), match.captured("value").trimmed());
|
||||
this->parseConfigKeyValue(match.captured("key").trimmed(), match.captured("value").trimmed());
|
||||
}
|
||||
this->setUnreadKeys();
|
||||
|
||||
|
|
@ -840,6 +840,10 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
|
|||
} else {
|
||||
logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->getConfigFilepath()).arg(key));
|
||||
}
|
||||
} else if (key.startsWith("global_constant/")) {
|
||||
this->globalConstants.insert(key.mid(QStringLiteral("global_constant/").length()), value);
|
||||
} else if (key == "global_constants_filepaths") {
|
||||
this->globalConstantsFilepaths = value.split(",", Qt::SkipEmptyParts);
|
||||
} else if (key == "prefabs_filepath") {
|
||||
this->prefabFilepath = value;
|
||||
} else if (key == "prefabs_import_prompted") {
|
||||
|
|
@ -863,7 +867,7 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
|
|||
} else if (key == "event_icon_path_heal") {
|
||||
this->eventIconPaths[Event::Group::Heal] = value;
|
||||
} else if (key.startsWith("pokemon_icon_path/")) {
|
||||
this->pokemonIconPaths.insert(key.mid(QStringLiteral("pokemon_icon_path/").length()).toUpper(), value);
|
||||
this->pokemonIconPaths.insert(key.mid(QStringLiteral("pokemon_icon_path/").length()), value);
|
||||
} else if (key == "collision_sheet_path") {
|
||||
this->collisionSheetPath = value;
|
||||
} else if (key == "collision_sheet_width") {
|
||||
|
|
@ -970,12 +974,16 @@ QMap<QString, QString> ProjectConfig::getKeyValueMap() {
|
|||
map.insert("event_icon_path_coord", this->eventIconPaths[Event::Group::Coord]);
|
||||
map.insert("event_icon_path_bg", this->eventIconPaths[Event::Group::Bg]);
|
||||
map.insert("event_icon_path_heal", this->eventIconPaths[Event::Group::Heal]);
|
||||
for (auto i = this->pokemonIconPaths.cbegin(), end = this->pokemonIconPaths.cend(); i != end; i++){
|
||||
const QString path = i.value();
|
||||
if (!path.isEmpty()) map.insert("pokemon_icon_path/" + i.key(), path);
|
||||
for (auto it = this->pokemonIconPaths.constBegin(); it != this->pokemonIconPaths.constEnd(); it++) {
|
||||
const QString path = it.value();
|
||||
if (!path.isEmpty()) map.insert("pokemon_icon_path/" + it.key(), path);
|
||||
}
|
||||
for (auto i = this->identifiers.cbegin(), end = this->identifiers.cend(); i != end; i++) {
|
||||
map.insert("ident/"+defaultIdentifiers.value(i.key()).first, i.value());
|
||||
for (auto it = this->globalConstants.constBegin(); it != this->globalConstants.constEnd(); it++) {
|
||||
map.insert("global_constant/" + it.key(), it.value());
|
||||
}
|
||||
map.insert("global_constants_filepaths", this->globalConstantsFilepaths.join(","));
|
||||
for (auto it = this->identifiers.constBegin(); it != this->identifiers.constEnd(); it++) {
|
||||
map.insert("ident/"+defaultIdentifiers.value(it.key()).first, it.value());
|
||||
}
|
||||
map.insert("collision_sheet_path", this->collisionSheetPath);
|
||||
map.insert("collision_sheet_width", QString::number(this->collisionSheetSize.width()));
|
||||
|
|
|
|||
|
|
@ -189,46 +189,38 @@ void Layout::setBorderBlockData(Blockdata newBlockdata, bool enableScriptCallbac
|
|||
}
|
||||
}
|
||||
|
||||
void Layout::setDimensions(int newWidth, int newHeight, bool setNewBlockdata, bool enableScriptCallback) {
|
||||
void Layout::setDimensions(int newWidth, int newHeight, bool setNewBlockdata) {
|
||||
if (setNewBlockdata) {
|
||||
setNewDimensionsBlockdata(newWidth, newHeight);
|
||||
}
|
||||
|
||||
int oldWidth = this->width;
|
||||
int oldHeight = this->height;
|
||||
this->width = newWidth;
|
||||
this->height = newHeight;
|
||||
|
||||
if (enableScriptCallback && (oldWidth != newWidth || oldHeight != newHeight)) {
|
||||
Scripting::cb_MapResized(oldWidth, oldHeight, newWidth, newHeight);
|
||||
}
|
||||
|
||||
emit dimensionsChanged(QSize(getWidth(), getHeight()));
|
||||
emit dimensionsChanged(QSize(this->width, this->height));
|
||||
}
|
||||
|
||||
void Layout::adjustDimensions(QMargins margins, bool setNewBlockdata) {
|
||||
int newWidth = this->width + margins.left() + margins.right();
|
||||
int newHeight = this->height + margins.top() + margins.bottom();
|
||||
void Layout::adjustDimensions(const QMargins &margins, bool setNewBlockdata) {
|
||||
int oldWidth = this->width;
|
||||
int oldHeight = this->height;
|
||||
this->width = oldWidth + margins.left() + margins.right();
|
||||
this->height = oldHeight + margins.top() + margins.bottom();
|
||||
|
||||
if (setNewBlockdata) {
|
||||
// Fill new blockdata
|
||||
Blockdata newBlockdata;
|
||||
for (int y = 0; y < newHeight; y++)
|
||||
for (int x = 0; x < newWidth; x++) {
|
||||
if ((x < margins.left()) || (x >= newWidth - margins.right()) || (y < margins.top()) || (y >= newHeight - margins.bottom())) {
|
||||
for (int y = 0; y < this->height; y++)
|
||||
for (int x = 0; x < this->width; x++) {
|
||||
if ((x < margins.left()) || (x >= this->width - margins.right()) || (y < margins.top()) || (y >= this->height - margins.bottom())) {
|
||||
newBlockdata.append(0);
|
||||
} else {
|
||||
int index = (y - margins.top()) * this->width + (x - margins.left());
|
||||
int index = (y - margins.top()) * oldWidth + (x - margins.left());
|
||||
newBlockdata.append(this->blockdata.value(index));
|
||||
}
|
||||
}
|
||||
this->blockdata = newBlockdata;
|
||||
}
|
||||
|
||||
this->width = newWidth;
|
||||
this->height = newHeight;
|
||||
|
||||
emit dimensionsChanged(QSize(getWidth(), getHeight()));
|
||||
Scripting::cb_MapResized(oldWidth, oldHeight, margins);
|
||||
emit dimensionsChanged(QSize(this->width, this->height));
|
||||
}
|
||||
|
||||
void Layout::setBorderDimensions(int newWidth, int newHeight, bool setNewBlockdata, bool enableScriptCallback) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "log.h"
|
||||
#include "parseutil.h"
|
||||
#include "loadingscreen.h"
|
||||
|
||||
#include <QRegularExpression>
|
||||
#include <QJsonDocument>
|
||||
|
|
@ -15,26 +16,8 @@ const QRegularExpression ParseUtil::re_poryScriptLabel("\\b(script)(\\((global|l
|
|||
const QRegularExpression ParseUtil::re_globalPoryScriptLabel("\\b(script)(\\((global)\\))?\\s*\\b(?<label>[\\w_][\\w\\d_]*)");
|
||||
const QRegularExpression ParseUtil::re_poryRawSection("\\b(raw)\\s*`(?<raw_script>[^`]*)");
|
||||
|
||||
static const QMap<QString, int> globalDefineValues = {
|
||||
{"FALSE", 0},
|
||||
{"TRUE", 1},
|
||||
{"SCHAR_MIN", SCHAR_MIN},
|
||||
{"SCHAR_MAX", SCHAR_MAX},
|
||||
{"CHAR_MIN", CHAR_MIN},
|
||||
{"CHAR_MAX", CHAR_MAX},
|
||||
{"UCHAR_MAX", UCHAR_MAX},
|
||||
{"SHRT_MIN", SHRT_MIN},
|
||||
{"SHRT_MAX", SHRT_MAX},
|
||||
{"USHRT_MAX", USHRT_MAX},
|
||||
{"INT_MIN", INT_MIN},
|
||||
{"INT_MAX", INT_MAX},
|
||||
{"UINT_MAX", UINT_MAX},
|
||||
};
|
||||
|
||||
ParseUtil::ParseUtil() { }
|
||||
|
||||
void ParseUtil::set_root(const QString &dir) {
|
||||
this->root = dir;
|
||||
ParseUtil::ParseUtil() {
|
||||
resetCDefines();
|
||||
}
|
||||
|
||||
QString ParseUtil::pathWithRoot(const QString &path) {
|
||||
|
|
@ -73,6 +56,16 @@ QString ParseUtil::createErrorMessage(const QString &message, const QString &exp
|
|||
return QString("%1:%2:%3: %4").arg(this->file).arg(lineNum).arg(colNum).arg(message);
|
||||
}
|
||||
|
||||
void ParseUtil::updateSplashScreen(QString path) {
|
||||
if (!this->updatesSplashScreen)
|
||||
return;
|
||||
|
||||
if (path.startsWith(this->root)) {
|
||||
path.remove(0, this->root.length());
|
||||
}
|
||||
porysplash->showLoadingMessage(path);
|
||||
}
|
||||
|
||||
QString ParseUtil::readTextFile(const QString &path, QString *error) {
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
|
|
@ -95,6 +88,8 @@ QString ParseUtil::readTextFile(const QString &path, QString *error) {
|
|||
// Note that this doesn't insert any parsed files into the file cache, and we don't
|
||||
// want it to (we read a lot of files only once, storing them all is a waste of memory).
|
||||
QString ParseUtil::loadTextFile(const QString &path, QString *error) {
|
||||
updateSplashScreen(path);
|
||||
|
||||
auto it = this->fileCache.constFind(path);
|
||||
if (it != this->fileCache.constEnd()) {
|
||||
// Load text file from cache
|
||||
|
|
@ -104,6 +99,8 @@ QString ParseUtil::loadTextFile(const QString &path, QString *error) {
|
|||
}
|
||||
|
||||
bool ParseUtil::cacheFile(const QString &path, QString *error) {
|
||||
updateSplashScreen(path);
|
||||
|
||||
this->fileCache.insert(path, readTextFile(pathWithRoot(path), error));
|
||||
return !error || error->isEmpty();
|
||||
}
|
||||
|
|
@ -143,28 +140,48 @@ QList<QStringList> ParseUtil::parseAsm(const QString &filename) {
|
|||
return parsed;
|
||||
}
|
||||
|
||||
// 'identifier' is the name of the #define to evaluate, e.g. 'FOO' in '#define FOO (BAR+1)'
|
||||
// 'expression' is the text of the #define to evaluate, e.g. '(BAR+1)' in '#define FOO (BAR+1)'
|
||||
// 'knownValues' is a pointer to a map of identifier->values for defines that have already been evaluated.
|
||||
// 'unevaluatedExpressions' is a pointer to a map of identifier->expressions for defines that have not been evaluated. If this map contains any
|
||||
// identifiers found in 'expression' then this function will be called recursively to evaluate that define first.
|
||||
// This function will maintain the passed maps appropriately as new #defines are evaluated.
|
||||
int ParseUtil::evaluateDefine(const QString &identifier, const QString &expression, QMap<QString, int> *knownValues, QMap<QString, QString> *unevaluatedExpressions) {
|
||||
if (unevaluatedExpressions->contains(identifier))
|
||||
unevaluatedExpressions->remove(identifier);
|
||||
// Try to evaluate the given #define/enum 'identifier' name using the information the parser has.
|
||||
// If it recognizes the name as an identifier it's aware of (either from having parsed it or having been told about
|
||||
// it using 'loadGlobalCDefines') it will evaluate it if necessary then return the resulting value and set 'ok' to true.
|
||||
// Evaluated identifiers are cached, and will only be re-evaluated if the parser encounters a new expression for that identifier.
|
||||
// If it doesn't recognize it, 'ok' will be set to false and it will return 0.
|
||||
int ParseUtil::evaluateDefine(const QString &identifier, bool *ok) {
|
||||
if (ok) *ok = true;
|
||||
|
||||
if (knownValues->contains(identifier))
|
||||
return knownValues->value(identifier);
|
||||
// Global defines take precedence
|
||||
if (this->globalDefineExpressions.contains(identifier)) {
|
||||
int value = evaluateExpression(this->globalDefineExpressions.take(identifier));
|
||||
this->globalDefineValues.insert(identifier, value);
|
||||
return value;
|
||||
}
|
||||
auto it = this->globalDefineValues.constFind(identifier);
|
||||
if (it != this->globalDefineValues.constEnd()) {
|
||||
return it.value();
|
||||
}
|
||||
|
||||
QList<Token> tokens = tokenizeExpression(expression, knownValues, unevaluatedExpressions);
|
||||
QList<Token> postfixExpression = generatePostfix(tokens);
|
||||
int value = evaluatePostfix(postfixExpression);
|
||||
// Check known expressions before checking known values.
|
||||
// If an identifier is redefined then we'll receive a new expression for it, and we want to make sure we re-evaluate it.
|
||||
if (this->knownDefineExpressions.contains(identifier)) {
|
||||
int value = evaluateExpression(this->knownDefineExpressions.take(identifier));
|
||||
this->knownDefineValues.insert(identifier, value);
|
||||
return value;
|
||||
}
|
||||
it = this->knownDefineValues.constFind(identifier);
|
||||
if (it != this->knownDefineValues.constEnd()) {
|
||||
return it.value();
|
||||
}
|
||||
|
||||
knownValues->insert(identifier, value);
|
||||
return value;
|
||||
if (ok) *ok = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
QList<Token> ParseUtil::tokenizeExpression(QString expression, QMap<QString, int> *knownValues, QMap<QString, QString> *unevaluatedExpressions) {
|
||||
int ParseUtil::evaluateExpression(const QString &expression) {
|
||||
QList<Token> tokens = tokenizeExpression(expression);
|
||||
QList<Token> postfixExpression = generatePostfix(tokens);
|
||||
return evaluatePostfix(postfixExpression);
|
||||
}
|
||||
|
||||
QList<Token> ParseUtil::tokenizeExpression(QString expression) {
|
||||
QList<Token> tokens;
|
||||
|
||||
static const QStringList tokenTypes = {"hex", "decimal", "identifier", "operator", "leftparen", "rightparen"};
|
||||
|
|
@ -181,14 +198,14 @@ QList<Token> ParseUtil::tokenizeExpression(QString expression, QMap<QString, int
|
|||
QString token = match.captured(tokenType);
|
||||
if (!token.isEmpty()) {
|
||||
if (tokenType == "identifier") {
|
||||
if (unevaluatedExpressions->contains(token)) {
|
||||
// This expression depends on a define we know of but haven't evaluated. Evaluate it now
|
||||
evaluateDefine(token, unevaluatedExpressions->value(token), knownValues, unevaluatedExpressions);
|
||||
}
|
||||
if (knownValues->contains(token)) {
|
||||
bool ok;
|
||||
int tokenValue = evaluateDefine(token, &ok);
|
||||
if (ok) {
|
||||
// Any errors encountered when this identifier was evaluated should be recorded for this expression as well.
|
||||
recordErrors(this->errorMap.value(token));
|
||||
QString actualToken = QString("%1").arg(knownValues->value(token));
|
||||
|
||||
// Replace token with evaluated expression
|
||||
QString actualToken = QString::number(tokenValue);
|
||||
expression = expression.replace(0, token.length(), actualToken);
|
||||
token = actualToken;
|
||||
tokenType = "decimal";
|
||||
|
|
@ -481,23 +498,27 @@ ParseUtil::ParsedDefines ParseUtil::readCDefines(const QString &filename, const
|
|||
result.filteredNames.append(name);
|
||||
}
|
||||
}
|
||||
// QHash::insert(const QHash<K, V> &other) was introduced in 5.15.
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
this->knownDefineExpressions.insert(result.expressions);
|
||||
#else
|
||||
for (auto it = result.expressions.constBegin(); it != result.expressions.constEnd(); it++) {
|
||||
this->knownDefineExpressions.insert(it.key(), it.value());
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
// Read all the define names and their expressions in the specified file, then evaluate the ones matching the search text (and any they depend on).
|
||||
QMap<QString, int> ParseUtil::evaluateCDefines(const QString &filename, const QSet<QString> &filterList, bool useRegex, QString *error) {
|
||||
QHash<QString, int> ParseUtil::evaluateCDefines(const QString &filename, const QSet<QString> &filterList, bool useRegex, QString *error) {
|
||||
ParsedDefines defines = readCDefines(filename, filterList, useRegex, error);
|
||||
|
||||
// Evaluate defines
|
||||
QMap<QString, int> filteredValues;
|
||||
QMap<QString, int> allValues = globalDefineValues;
|
||||
QHash<QString, int> filteredValues;
|
||||
this->errorMap.clear();
|
||||
while (!defines.filteredNames.isEmpty()) {
|
||||
const QString name = defines.filteredNames.takeFirst();
|
||||
const QString expression = defines.expressions.take(name);
|
||||
if (expression == " ") continue;
|
||||
this->curDefine = name;
|
||||
filteredValues.insert(name, evaluateDefine(name, expression, &allValues, &defines.expressions));
|
||||
this->curDefine = defines.filteredNames.takeFirst();
|
||||
filteredValues.insert(this->curDefine, evaluateDefine(this->curDefine));
|
||||
logRecordedErrors(); // Only log errors for defines that Porymap is looking for
|
||||
}
|
||||
|
||||
|
|
@ -505,12 +526,12 @@ QMap<QString, int> ParseUtil::evaluateCDefines(const QString &filename, const QS
|
|||
}
|
||||
|
||||
// Find and evaluate a specific set of defines with known names.
|
||||
QMap<QString, int> ParseUtil::readCDefinesByName(const QString &filename, const QSet<QString> &names, QString *error) {
|
||||
QHash<QString, int> ParseUtil::readCDefinesByName(const QString &filename, const QSet<QString> &names, QString *error) {
|
||||
return evaluateCDefines(filename, names, false, error);
|
||||
}
|
||||
|
||||
// Find and evaluate an unknown list of defines with a known name pattern.
|
||||
QMap<QString, int> ParseUtil::readCDefinesByRegex(const QString &filename, const QSet<QString> ®exList, QString *error) {
|
||||
QHash<QString, int> ParseUtil::readCDefinesByRegex(const QString &filename, const QSet<QString> ®exList, QString *error) {
|
||||
return evaluateCDefines(filename, regexList, true, error);
|
||||
}
|
||||
|
||||
|
|
@ -521,6 +542,50 @@ QStringList ParseUtil::readCDefineNames(const QString &filename, const QSet<QStr
|
|||
return readCDefines(filename, regexList, true, error).filteredNames;
|
||||
}
|
||||
|
||||
// Find any defines in the specified file and save their expressions.
|
||||
// If any of these defines are encountered later by other define parsing functions then they'll be recognized and evaluated.
|
||||
void ParseUtil::loadGlobalCDefinesFromFile(const QString &filename, QString *error) {
|
||||
loadGlobalCDefines(readCDefines(filename, {}, false, error).expressions);
|
||||
}
|
||||
|
||||
void ParseUtil::loadGlobalCDefines(const QHash<QString,QString> &defines) {
|
||||
// QHash::insert(const QHash<K, V> &other) was introduced in 5.15.
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
this->globalDefineExpressions.insert(defines);
|
||||
#else
|
||||
for (auto it = defines.constBegin(); it != defines.constEnd(); it++) {
|
||||
this->globalDefineExpressions.insert(it.key(), it.value());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ParseUtil::loadGlobalCDefines(const QMap<QString,QString> &defines) {
|
||||
for (auto it = defines.constBegin(); it != defines.constEnd(); it++)
|
||||
this->globalDefineExpressions.insert(it.key(), it.value());
|
||||
}
|
||||
|
||||
void ParseUtil::resetCDefines() {
|
||||
static const QHash<QString, int> defaultDefineValues = {
|
||||
{"FALSE", 0},
|
||||
{"TRUE", 1},
|
||||
{"SCHAR_MIN", SCHAR_MIN},
|
||||
{"SCHAR_MAX", SCHAR_MAX},
|
||||
{"CHAR_MIN", CHAR_MIN},
|
||||
{"CHAR_MAX", CHAR_MAX},
|
||||
{"UCHAR_MAX", UCHAR_MAX},
|
||||
{"SHRT_MIN", SHRT_MIN},
|
||||
{"SHRT_MAX", SHRT_MAX},
|
||||
{"USHRT_MAX", USHRT_MAX},
|
||||
{"INT_MIN", INT_MIN},
|
||||
{"INT_MAX", INT_MAX},
|
||||
{"UINT_MAX", UINT_MAX},
|
||||
};
|
||||
this->globalDefineValues = defaultDefineValues;
|
||||
this->globalDefineExpressions.clear();
|
||||
this->knownDefineValues.clear();
|
||||
this->knownDefineExpressions.clear();
|
||||
}
|
||||
|
||||
QStringList ParseUtil::readCArray(const QString &filename, const QString &label) {
|
||||
QStringList list;
|
||||
|
||||
|
|
@ -679,6 +744,8 @@ QStringList ParseUtil::getLabelValues(const QList<QStringList> &list, const QStr
|
|||
}
|
||||
|
||||
bool ParseUtil::tryParseJsonFile(QJsonDocument *out, const QString &filepath, QString *error) {
|
||||
updateSplashScreen(filepath);
|
||||
|
||||
QFile file(pathWithRoot(filepath));
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
if (error) *error = file.errorString();
|
||||
|
|
|
|||
|
|
@ -249,12 +249,10 @@ QList<QRgb> Tileset::getPalette(int paletteId, Tileset *primaryTileset, Tileset
|
|||
return paletteTable;
|
||||
}
|
||||
|
||||
bool Tileset::appendToHeaders(QString root, QString friendlyName, bool usingAsm) {
|
||||
QString headersFile = root + "/" + (usingAsm ? projectConfig.getFilePath(ProjectFilePath::tilesets_headers_asm)
|
||||
: projectConfig.getFilePath(ProjectFilePath::tilesets_headers));
|
||||
QFile file(headersFile);
|
||||
bool Tileset::appendToHeaders(const QString &filepath, const QString &friendlyName, bool usingAsm) {
|
||||
QFile file(filepath);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Append)) {
|
||||
logError(QString("Could not write to file \"%1\"").arg(headersFile));
|
||||
logError(QString("Could not write to file \"%1\"").arg(filepath));
|
||||
return false;
|
||||
}
|
||||
QString isSecondaryStr = this->is_secondary ? "TRUE" : "FALSE";
|
||||
|
|
@ -294,12 +292,10 @@ bool Tileset::appendToHeaders(QString root, QString friendlyName, bool usingAsm)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Tileset::appendToGraphics(QString root, QString friendlyName, bool usingAsm) {
|
||||
QString graphicsFile = root + "/" + (usingAsm ? projectConfig.getFilePath(ProjectFilePath::tilesets_graphics_asm)
|
||||
: projectConfig.getFilePath(ProjectFilePath::tilesets_graphics));
|
||||
QFile file(graphicsFile);
|
||||
bool Tileset::appendToGraphics(const QString &filepath, const QString &friendlyName, bool usingAsm) {
|
||||
QFile file(filepath);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Append)) {
|
||||
logError(QString("Could not write to file \"%1\"").arg(graphicsFile));
|
||||
logError(QString("Could not write to file \"%1\"").arg(filepath));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -332,12 +328,10 @@ bool Tileset::appendToGraphics(QString root, QString friendlyName, bool usingAsm
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Tileset::appendToMetatiles(QString root, QString friendlyName, bool usingAsm) {
|
||||
QString metatileFile = root + "/" + (usingAsm ? projectConfig.getFilePath(ProjectFilePath::tilesets_metatiles_asm)
|
||||
: projectConfig.getFilePath(ProjectFilePath::tilesets_metatiles));
|
||||
QFile file(metatileFile);
|
||||
bool Tileset::appendToMetatiles(const QString &filepath, const QString &friendlyName, bool usingAsm) {
|
||||
QFile file(filepath);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Append)) {
|
||||
logError(QString("Could not write to file \"%1\"").arg(metatileFile));
|
||||
logError(QString("Could not write to file \"%1\"").arg(filepath));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -170,6 +170,7 @@ void Editor::setEditMode(EditMode editMode) {
|
|||
}
|
||||
this->cursorMapTileRect->setSingleTileMode();
|
||||
this->cursorMapTileRect->setActive(editingLayout);
|
||||
this->playerViewRect->setActive(editingLayout);
|
||||
this->editGroup.setActiveStack(editStack);
|
||||
setMapEditingButtonsEnabled(editingLayout);
|
||||
|
||||
|
|
@ -237,7 +238,7 @@ void Editor::displayWildMonTables() {
|
|||
|
||||
labelComboStrings.sort();
|
||||
labelCombo->addItems(labelComboStrings);
|
||||
labelCombo->setCurrentText(labelCombo->itemText(0));
|
||||
labelCombo->setCurrentIndex(0);
|
||||
|
||||
QStackedWidget *stack = ui->stackedWidget_WildMons;
|
||||
int labelIndex = 0;
|
||||
|
|
@ -494,7 +495,9 @@ void Editor::configureEncounterJSON(QWidget *window) {
|
|||
QFrame *slotChoiceFrame = new QFrame;
|
||||
QVBoxLayout *slotChoiceLayout = new QVBoxLayout;
|
||||
if (useGroups) {
|
||||
QComboBox *groupCombo = new QComboBox;
|
||||
auto groupCombo = new NoScrollComboBox;
|
||||
groupCombo->setEditable(false);
|
||||
groupCombo->setMinimumContentsLength(10);
|
||||
connect(groupCombo, QOverload<const QString &>::of(&QComboBox::textActivated), [&tempFields, ¤tField, &updateTotal, index](QString newGroupName) {
|
||||
for (EncounterField &field : tempFields) {
|
||||
if (field.name == currentField.name) {
|
||||
|
|
@ -525,7 +528,7 @@ void Editor::configureEncounterJSON(QWidget *window) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
groupCombo->setCurrentText(currentGroupName);
|
||||
groupCombo->setTextItem(currentGroupName);
|
||||
slotChoiceLayout->addWidget(groupCombo);
|
||||
}
|
||||
slotChoiceLayout->addWidget(chanceSpinner);
|
||||
|
|
@ -981,7 +984,7 @@ QString Editor::getDivingMapName(const QString &direction) const {
|
|||
void Editor::onDivingMapEditingFinished(NoScrollComboBox *combo, const QString &direction) {
|
||||
if (!setDivingMapName(combo->currentText(), direction)) {
|
||||
// If user input was invalid, restore the combo to the previously-valid text.
|
||||
combo->setCurrentText(getDivingMapName(direction));
|
||||
combo->setTextItem(getDivingMapName(direction));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1111,6 +1114,7 @@ void Editor::scaleMapView(int s) {
|
|||
void Editor::setPlayerViewRect(const QRectF &rect) {
|
||||
delete this->playerViewRect;
|
||||
this->playerViewRect = new MovableRect(&this->settings->playerViewRectEnabled, rect, qRgb(255, 255, 255));
|
||||
this->playerViewRect->setActive(getEditingLayout());
|
||||
if (ui->graphicsView_Map->scene())
|
||||
ui->graphicsView_Map->scene()->update();
|
||||
}
|
||||
|
|
@ -1279,8 +1283,8 @@ bool Editor::setLayout(QString layoutId) {
|
|||
|
||||
ui->comboBox_PrimaryTileset->blockSignals(true);
|
||||
ui->comboBox_SecondaryTileset->blockSignals(true);
|
||||
ui->comboBox_PrimaryTileset->setCurrentText(this->layout->tileset_primary_label);
|
||||
ui->comboBox_SecondaryTileset->setCurrentText(this->layout->tileset_secondary_label);
|
||||
ui->comboBox_PrimaryTileset->setTextItem(this->layout->tileset_primary_label);
|
||||
ui->comboBox_SecondaryTileset->setTextItem(this->layout->tileset_secondary_label);
|
||||
ui->comboBox_PrimaryTileset->blockSignals(false);
|
||||
ui->comboBox_SecondaryTileset->blockSignals(false);
|
||||
|
||||
|
|
@ -1751,6 +1755,7 @@ EventPixmapItem *Editor::addEventPixmapItem(Event *event) {
|
|||
connect(item, &EventPixmapItem::selected, this, &Editor::selectMapEvent);
|
||||
connect(item, &EventPixmapItem::posChanged, [this, event] { updateWarpEventWarning(event); });
|
||||
connect(item, &EventPixmapItem::yChanged, [this, item] { updateEventPixmapItemZValue(item); });
|
||||
updateWarpEventWarning(event);
|
||||
redrawEventPixmapItem(item);
|
||||
this->events_group->addToGroup(item);
|
||||
return item;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
#include "mainwindow.h"
|
||||
#include "loadingscreen.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
|
@ -6,8 +8,13 @@ int main(int argc, char *argv[])
|
|||
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Round);
|
||||
QApplication a(argc, argv);
|
||||
a.setStyle("fusion");
|
||||
|
||||
porysplash = new PorymapLoadingScreen;
|
||||
|
||||
QObject::connect(&a, &QCoreApplication::aboutToQuit, [=]() { delete porysplash; });
|
||||
|
||||
MainWindow w(nullptr);
|
||||
w.show();
|
||||
w.initialize();
|
||||
|
||||
return a.exec();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "newmapgroupdialog.h"
|
||||
#include "newlocationdialog.h"
|
||||
#include "message.h"
|
||||
#include "loadingscreen.h"
|
||||
|
||||
#include <QClipboard>
|
||||
#include <QDirIterator>
|
||||
|
|
@ -75,10 +76,13 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
|
||||
cleanupLargeLog();
|
||||
logInfo(QString("Launching Porymap v%1").arg(QCoreApplication::applicationVersion()));
|
||||
}
|
||||
|
||||
void MainWindow::initialize() {
|
||||
this->initWindow();
|
||||
if (porymapConfig.reopenOnLaunch && !porymapConfig.projectManuallyClosed && this->openProject(porymapConfig.getRecentProject(), true))
|
||||
if (porymapConfig.reopenOnLaunch && !porymapConfig.projectManuallyClosed && this->openProject(porymapConfig.getRecentProject(), true)) {
|
||||
on_toolButton_Paint_clicked();
|
||||
}
|
||||
|
||||
// there is a bug affecting macOS users, where the trackpad deilveres a bad touch-release gesture
|
||||
// the warning is a bit annoying, so it is disabled here
|
||||
|
|
@ -86,6 +90,9 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
|
||||
if (porymapConfig.checkForUpdates)
|
||||
this->checkForUpdates(false);
|
||||
|
||||
this->restoreWindowState();
|
||||
this->show();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
|
|
@ -142,7 +149,6 @@ void MainWindow::initWindow() {
|
|||
this->initMiscHeapObjects();
|
||||
this->initMapList();
|
||||
this->initShortcuts();
|
||||
this->restoreWindowState();
|
||||
|
||||
#ifndef RELEASE_PLATFORM
|
||||
ui->actionCheck_for_Updates->setVisible(false);
|
||||
|
|
@ -153,7 +159,6 @@ void MainWindow::initWindow() {
|
|||
#endif
|
||||
|
||||
setWindowDisabled(true);
|
||||
show();
|
||||
}
|
||||
|
||||
void MainWindow::initShortcuts() {
|
||||
|
|
@ -652,16 +657,20 @@ bool MainWindow::openProject(QString dir, bool initial) {
|
|||
this->statusBar()->showMessage(openMessage);
|
||||
logInfo(openMessage);
|
||||
|
||||
porysplash->start();
|
||||
|
||||
porysplash->showLoadingMessage("config");
|
||||
userConfig.projectDir = dir;
|
||||
userConfig.load();
|
||||
projectConfig.projectDir = dir;
|
||||
projectConfig.load();
|
||||
|
||||
porysplash->showLoadingMessage("custom scripts");
|
||||
Scripting::init(this);
|
||||
|
||||
// Create the project
|
||||
auto project = new Project(editor);
|
||||
project->set_root(dir);
|
||||
project->setRoot(dir);
|
||||
connect(project, &Project::fileChanged, this, &MainWindow::showFileWatcherWarning);
|
||||
connect(project, &Project::mapLoaded, this, &MainWindow::onMapLoaded);
|
||||
connect(project, &Project::mapCreated, this, &MainWindow::onNewMapCreated);
|
||||
|
|
@ -674,8 +683,10 @@ bool MainWindow::openProject(QString dir, bool initial) {
|
|||
this->editor->setProject(project);
|
||||
|
||||
// Make sure project looks reasonable before attempting to load it
|
||||
porysplash->showMessage("Verifying project");
|
||||
if (!checkProjectSanity()) {
|
||||
delete this->editor->project;
|
||||
porysplash->stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -685,6 +696,7 @@ bool MainWindow::openProject(QString dir, bool initial) {
|
|||
showProjectOpenFailure();
|
||||
delete this->editor->project;
|
||||
// TODO: Allow changing project settings at this point
|
||||
porysplash->stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -705,10 +717,12 @@ bool MainWindow::openProject(QString dir, bool initial) {
|
|||
editor->layout);
|
||||
Scripting::cb_ProjectOpened(dir);
|
||||
setWindowDisabled(false);
|
||||
porysplash->stop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MainWindow::loadProjectData() {
|
||||
porysplash->showLoadingMessage("project");
|
||||
bool success = editor->project->load();
|
||||
Scripting::populateGlobalObject(this);
|
||||
return success;
|
||||
|
|
@ -720,7 +734,7 @@ bool MainWindow::checkProjectSanity() {
|
|||
|
||||
logWarn(QString("The directory '%1' failed the project sanity check.").arg(editor->project->root));
|
||||
|
||||
ErrorMessage msgBox(QStringLiteral("The selected directory appears to be invalid."), this);
|
||||
ErrorMessage msgBox(QStringLiteral("The selected directory appears to be invalid."), porysplash);
|
||||
msgBox.setInformativeText(QString("The directory '%1' is missing key files.\n\n"
|
||||
"Make sure you selected the correct project directory "
|
||||
"(the one used to make your .gba file, e.g. 'pokeemerald').").arg(editor->project->root));
|
||||
|
|
@ -735,19 +749,26 @@ bool MainWindow::checkProjectSanity() {
|
|||
}
|
||||
|
||||
void MainWindow::showProjectOpenFailure() {
|
||||
if (!this->isVisible()){
|
||||
// The main window is not visible during the initial project open; the splash screen is busy providing visual feedback.
|
||||
// If project opening fails we can immediately display the empty main window (which we need anyway to parent messages to).
|
||||
restoreWindowState();
|
||||
show();
|
||||
}
|
||||
RecentErrorMessage::show(QStringLiteral("There was an error opening the project."), this);
|
||||
}
|
||||
|
||||
// Alert the user that one or more maps have been excluded while loading the project.
|
||||
void MainWindow::showMapsExcludedAlert(const QStringList &excludedMapNames) {
|
||||
RecentErrorMessage msgBox("", this);
|
||||
auto msgBox = new RecentErrorMessage("", this);
|
||||
msgBox->setAttribute(Qt::WA_DeleteOnClose);
|
||||
if (excludedMapNames.length() == 1) {
|
||||
msgBox.setText(QString("Failed to load map '%1'. Saving will exclude this map from your project.").arg(excludedMapNames.first()));
|
||||
msgBox->setText(QString("Failed to load map '%1'. Saving will exclude this map from your project.").arg(excludedMapNames.first()));
|
||||
} else {
|
||||
msgBox.setText(QStringLiteral("Failed to load the maps listed below. Saving will exclude these maps from your project."));
|
||||
msgBox.setDetailedText(excludedMapNames.join("\n")); // Overwrites error details text, user will need to check the log.
|
||||
msgBox->setText(QStringLiteral("Failed to load the maps listed below. Saving will exclude these maps from your project."));
|
||||
msgBox->setDetailedText(excludedMapNames.join("\n")); // Overwrites error details text, user will need to check the log.
|
||||
}
|
||||
msgBox.exec();
|
||||
msgBox->open();
|
||||
}
|
||||
|
||||
bool MainWindow::isProjectOpen() {
|
||||
|
|
@ -755,6 +776,8 @@ bool MainWindow::isProjectOpen() {
|
|||
}
|
||||
|
||||
bool MainWindow::setInitialMap() {
|
||||
porysplash->showMessage("Opening initial map");
|
||||
|
||||
const QString recent = userConfig.recentMapOrLayout;
|
||||
if (editor->project->mapNames.contains(recent)) {
|
||||
// User recently had a map open that still exists.
|
||||
|
|
@ -857,28 +880,28 @@ void MainWindow::showFileWatcherWarning() {
|
|||
path.remove(root);
|
||||
}
|
||||
|
||||
QuestionMessage msgBox("", this);
|
||||
QPointer msgBox = new QuestionMessage("", this);
|
||||
if (modifiedFiles.count() == 1) {
|
||||
msgBox.setText(QString("The file %1 has changed on disk. Would you like to reload the project?").arg(modifiedFiles.first()));
|
||||
msgBox->setText(QString("The file %1 has changed on disk. Would you like to reload the project?").arg(modifiedFiles.first()));
|
||||
} else {
|
||||
msgBox.setText(QStringLiteral("Some project files have changed on disk. Would you like to reload the project?"));
|
||||
msgBox.setDetailedText(QStringLiteral("The following files have changed:\n") + modifiedFiles.join("\n"));
|
||||
msgBox->setText(QStringLiteral("Some project files have changed on disk. Would you like to reload the project?"));
|
||||
msgBox->setDetailedText(QStringLiteral("The following files have changed:\n") + modifiedFiles.join("\n"));
|
||||
}
|
||||
msgBox->setCheckBox(new QCheckBox("Do not ask again."));
|
||||
|
||||
QCheckBox showAgainCheck("Do not ask again.");
|
||||
msgBox.setCheckBox(&showAgainCheck);
|
||||
|
||||
auto reply = msgBox.exec();
|
||||
if (reply == QMessageBox::Yes) {
|
||||
on_action_Reload_Project_triggered();
|
||||
} else if (reply == QMessageBox::No) {
|
||||
if (showAgainCheck.isChecked()) {
|
||||
porymapConfig.monitorFiles = false;
|
||||
if (this->preferenceEditor)
|
||||
this->preferenceEditor->updateFields();
|
||||
connect(msgBox, &QuestionMessage::accepted, this, &MainWindow::on_action_Reload_Project_triggered);
|
||||
connect(msgBox, &QuestionMessage::finished, [this, msgBox] {
|
||||
if (msgBox) {
|
||||
if (msgBox->checkBox() && msgBox->checkBox()->isChecked()) {
|
||||
porymapConfig.monitorFiles = false;
|
||||
if (this->preferenceEditor)
|
||||
this->preferenceEditor->updateFields();
|
||||
}
|
||||
msgBox->deleteLater();
|
||||
}
|
||||
}
|
||||
showing = false;
|
||||
showing = false;
|
||||
});
|
||||
msgBox->open();
|
||||
}
|
||||
|
||||
QString MainWindow::getExistingDirectory(QString dir) {
|
||||
|
|
@ -893,7 +916,8 @@ void MainWindow::on_action_Open_Project_triggered()
|
|||
}
|
||||
|
||||
void MainWindow::on_action_Reload_Project_triggered() {
|
||||
openProject(editor->project->root);
|
||||
if (this->editor && this->editor->project)
|
||||
openProject(this->editor->project->root);
|
||||
}
|
||||
|
||||
void MainWindow::on_action_Close_Project_triggered() {
|
||||
|
|
@ -918,9 +942,10 @@ bool MainWindow::userSetMap(QString map_name) {
|
|||
}
|
||||
|
||||
if (map_name == editor->project->getDynamicMapName()) {
|
||||
WarningMessage msgBox(QString("Cannot open map '%1'.").arg(map_name), this);
|
||||
msgBox.setInformativeText(QStringLiteral("This map name is a placeholder to indicate that the warp's map will be set programmatically."));
|
||||
msgBox.exec();
|
||||
auto msgBox = new WarningMessage(QString("Cannot open map '%1'.").arg(map_name), this);
|
||||
msgBox->setAttribute(Qt::WA_DeleteOnClose);
|
||||
msgBox->setInformativeText(QStringLiteral("This map name is a placeholder to indicate that the warp's map will be set programmatically."));
|
||||
msgBox->open();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1128,8 +1153,8 @@ void MainWindow::displayMapProperties() {
|
|||
|
||||
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);
|
||||
ui->comboBox_PrimaryTileset->setTextItem(editor->map->layout()->tileset_primary_label);
|
||||
ui->comboBox_SecondaryTileset->setTextItem(editor->map->layout()->tileset_secondary_label);
|
||||
|
||||
ui->mapCustomAttributesFrame->table()->setAttributes(editor->map->customAttributes());
|
||||
}
|
||||
|
|
@ -1149,7 +1174,7 @@ void MainWindow::on_comboBox_LayoutSelector_currentTextChanged(const QString &te
|
|||
|
||||
// New layout failed to load, restore previous layout
|
||||
const QSignalBlocker b(ui->comboBox_LayoutSelector);
|
||||
ui->comboBox_LayoutSelector->setCurrentText(this->editor->map->layout()->id);
|
||||
ui->comboBox_LayoutSelector->setTextItem(this->editor->map->layout()->id);
|
||||
return;
|
||||
}
|
||||
this->editor->map->setLayout(layout);
|
||||
|
|
@ -1165,12 +1190,14 @@ void MainWindow::onLayoutSelectorEditingFinished() {
|
|||
const QString text = ui->comboBox_LayoutSelector->currentText();
|
||||
if (!this->editor->project->mapLayouts.contains(text)) {
|
||||
const QSignalBlocker b(ui->comboBox_LayoutSelector);
|
||||
ui->comboBox_LayoutSelector->setCurrentText(this->editor->layout->id);
|
||||
ui->comboBox_LayoutSelector->setTextItem(this->editor->layout->id);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the UI using information we've read from the user's project files.
|
||||
bool MainWindow::setProjectUI() {
|
||||
porysplash->showLoadingMessage("project UI");
|
||||
|
||||
Project *project = editor->project;
|
||||
|
||||
this->mapHeaderForm->setProject(project);
|
||||
|
|
@ -1696,6 +1723,13 @@ void MainWindow::duplicate() {
|
|||
void MainWindow::copy() {
|
||||
auto focused = QApplication::focusWidget();
|
||||
if (focused) {
|
||||
// Allow copying text from selectable QLabels.
|
||||
auto label = dynamic_cast<QLabel*>(focused);
|
||||
if (label && !label->selectedText().isEmpty()) {
|
||||
setClipboardData(label->selectedText());
|
||||
return;
|
||||
}
|
||||
|
||||
QString objectName = focused->objectName();
|
||||
if (objectName == "graphicsView_currentMetatileSelection") {
|
||||
// copy the current metatile selection as json data
|
||||
|
|
@ -1992,7 +2026,7 @@ void MainWindow::on_actionPlayer_View_Rectangle_triggered()
|
|||
this->editor->settings->playerViewRectEnabled = enabled;
|
||||
if ((this->editor->map_item && this->editor->map_item->has_mouse)
|
||||
|| (this->editor->collision_item && this->editor->collision_item->has_mouse)) {
|
||||
this->editor->playerViewRect->setVisible(enabled);
|
||||
this->editor->playerViewRect->setVisible(enabled && this->editor->playerViewRect->getActive());
|
||||
ui->graphicsView_Map->scene()->update();
|
||||
}
|
||||
}
|
||||
|
|
@ -2661,7 +2695,7 @@ void MainWindow::openWildMonTable(const QString &mapName, const QString &groupNa
|
|||
if (userSetMap(mapName)) {
|
||||
// Switch to the correct main tab, wild encounter group, and wild encounter type tab.
|
||||
on_mainTabBar_tabBarClicked(MainTab::WildPokemon);
|
||||
ui->comboBox_EncounterGroupLabel->setCurrentText(groupName);
|
||||
ui->comboBox_EncounterGroupLabel->setTextItem(groupName);
|
||||
QWidget *w = ui->stackedWidget_WildMons->currentWidget();
|
||||
if (w) static_cast<MonTabWidget *>(w)->setCurrentField(fieldName);
|
||||
}
|
||||
|
|
|
|||
194
src/project.cpp
194
src/project.cpp
|
|
@ -48,10 +48,10 @@ Project::~Project()
|
|||
QPixmapCache::clear();
|
||||
}
|
||||
|
||||
void Project::set_root(QString dir) {
|
||||
void Project::setRoot(const QString &dir) {
|
||||
this->root = dir;
|
||||
FileDialog::setDirectory(dir);
|
||||
this->parser.set_root(dir);
|
||||
this->parser.setRoot(dir);
|
||||
}
|
||||
|
||||
// Before attempting the initial project load we should check for a few notable files.
|
||||
|
|
@ -76,9 +76,11 @@ bool Project::sanityCheck() {
|
|||
}
|
||||
|
||||
bool Project::load() {
|
||||
this->parser.setUpdatesSplashScreen(true);
|
||||
resetFileCache();
|
||||
this->disabledSettingsNames.clear();
|
||||
bool success = readMapLayouts()
|
||||
bool success = readGlobalConstants()
|
||||
&& readMapLayouts()
|
||||
&& readRegionMapSections()
|
||||
&& readItemNames()
|
||||
&& readFlagNames()
|
||||
|
|
@ -115,6 +117,7 @@ bool Project::load() {
|
|||
initNewMapSettings();
|
||||
applyParsedLimits();
|
||||
}
|
||||
this->parser.setUpdatesSplashScreen(false);
|
||||
return success;
|
||||
}
|
||||
|
||||
|
|
@ -135,7 +138,9 @@ void Project::resetFileCache() {
|
|||
projectConfig.getFilePath(ProjectFilePath::global_fieldmap),
|
||||
};
|
||||
for (const auto &path : filepaths) {
|
||||
this->parser.cacheFile(path);
|
||||
if (this->parser.cacheFile(path)) {
|
||||
watchFile(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -215,6 +220,7 @@ QSet<QString> Project::getTopLevelMapFields() const {
|
|||
|
||||
bool Project::readMapJson(const QString &mapName, QJsonDocument * out) {
|
||||
const QString mapFilepath = QString("%1%2/map.json").arg(projectConfig.getFilePath(ProjectFilePath::data_map_folders)).arg(mapName);
|
||||
watchFile(mapFilepath);
|
||||
QString error;
|
||||
if (!parser.tryParseJsonFile(out, mapFilepath, &error)) {
|
||||
logError(QString("Failed to read map data from '%1': %2").arg(mapFilepath).arg(error));
|
||||
|
|
@ -485,7 +491,7 @@ bool Project::readMapLayouts() {
|
|||
clearMapLayouts();
|
||||
|
||||
const QString layoutsFilepath = projectConfig.getFilePath(ProjectFilePath::json_layouts);
|
||||
fileWatcher.addPath(QString("%1/%2").arg(this->root).arg(layoutsFilepath));
|
||||
watchFile(layoutsFilepath);
|
||||
QJsonDocument layoutsDoc;
|
||||
QString error;
|
||||
if (!parser.tryParseJsonFile(&layoutsDoc, layoutsFilepath, &error)) {
|
||||
|
|
@ -639,11 +645,26 @@ bool Project::saveMapLayouts() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void Project::ignoreWatchedFileTemporarily(QString filepath) {
|
||||
void Project::watchFile(const QString &filename) {
|
||||
this->fileWatcher.addPath(QString("%1/%2").arg(this->root).arg(filename));
|
||||
}
|
||||
|
||||
void Project::watchFiles(const QStringList &filenames) {
|
||||
for (const auto &filename : filenames)
|
||||
watchFile(filename);
|
||||
}
|
||||
|
||||
void Project::ignoreWatchedFileTemporarily(const QString &filepath) {
|
||||
// Ignore any file-change events for this filepath for the next 5 seconds.
|
||||
this->modifiedFileTimestamps.insert(filepath, QDateTime::currentMSecsSinceEpoch() + 5000);
|
||||
}
|
||||
|
||||
void Project::ignoreWatchedFilesTemporarily(const QStringList &filepaths) {
|
||||
for (const auto &filepath : filepaths) {
|
||||
ignoreWatchedFileTemporarily(filepath);
|
||||
}
|
||||
}
|
||||
|
||||
void Project::recordFileChange(const QString &filepath) {
|
||||
if (this->modifiedFiles.contains(filepath)) {
|
||||
// We already recorded a change to this file
|
||||
|
|
@ -1254,6 +1275,8 @@ bool Project::saveMap(Map *map, bool skipLayout) {
|
|||
// Custom header fields.
|
||||
OrderedJson::append(&mapObj, map->customAttributes());
|
||||
|
||||
ignoreWatchedFileTemporarily(mapFilepath);
|
||||
|
||||
OrderedJson mapJson(mapObj);
|
||||
OrderedJsonDoc jsonDoc(&mapJson);
|
||||
jsonDoc.dump(&mapFile);
|
||||
|
|
@ -1453,12 +1476,25 @@ Tileset *Project::createNewTileset(QString name, bool secondary, bool checkerboa
|
|||
labelList->insert(i, tileset->name);
|
||||
this->tilesetLabelsOrdered.append(tileset->name);
|
||||
|
||||
// Append to tileset specific files.
|
||||
// TODO: Ideally we wouldn't save new Tilesets immediately
|
||||
// Append to tileset specific files. Strip prefix from name to get base name for use in other symbols.
|
||||
name.remove(0, prefix.length());
|
||||
tileset->appendToHeaders(this->root, name, this->usingAsmTilesets);
|
||||
tileset->appendToGraphics(this->root, name, this->usingAsmTilesets);
|
||||
tileset->appendToMetatiles(this->root, name, this->usingAsmTilesets);
|
||||
QString headersFilepath = this->root + "/";
|
||||
QString graphicsFilepath = this->root + "/";
|
||||
QString metatilesFilepath = this->root + "/";
|
||||
if (this->usingAsmTilesets) {
|
||||
headersFilepath.append(projectConfig.getFilePath(ProjectFilePath::tilesets_headers_asm));
|
||||
graphicsFilepath.append(projectConfig.getFilePath(ProjectFilePath::tilesets_graphics_asm));
|
||||
metatilesFilepath.append(projectConfig.getFilePath(ProjectFilePath::tilesets_metatiles_asm));
|
||||
} else {
|
||||
headersFilepath.append(projectConfig.getFilePath(ProjectFilePath::tilesets_headers));
|
||||
graphicsFilepath.append(projectConfig.getFilePath(ProjectFilePath::tilesets_graphics));
|
||||
metatilesFilepath.append(projectConfig.getFilePath(ProjectFilePath::tilesets_metatiles));
|
||||
}
|
||||
ignoreWatchedFilesTemporarily({headersFilepath, graphicsFilepath, metatilesFilepath});
|
||||
name.remove(0, prefix.length()); // Strip prefix from name to get base name for use in other symbols.
|
||||
tileset->appendToHeaders(headersFilepath, name, this->usingAsmTilesets);
|
||||
tileset->appendToGraphics(graphicsFilepath, name, this->usingAsmTilesets);
|
||||
tileset->appendToMetatiles(metatilesFilepath, name, this->usingAsmTilesets);
|
||||
|
||||
tileset->save();
|
||||
|
||||
|
|
@ -1482,10 +1518,10 @@ bool Project::readTilesetMetatileLabels() {
|
|||
unusedMetatileLabels.clear();
|
||||
|
||||
QString metatileLabelsFilename = projectConfig.getFilePath(ProjectFilePath::constants_metatile_labels);
|
||||
fileWatcher.addPath(root + "/" + metatileLabelsFilename);
|
||||
watchFile(metatileLabelsFilename);
|
||||
|
||||
const QSet<QString> regexList = {QString("\\b%1").arg(projectConfig.getIdentifier(ProjectIdentifier::define_metatile_label_prefix))};
|
||||
const QMap<QString, int> defines = parser.readCDefinesByRegex(metatileLabelsFilename, regexList);
|
||||
const auto defines = parser.readCDefinesByRegex(metatileLabelsFilename, regexList);
|
||||
for (auto i = defines.constBegin(); i != defines.constEnd(); i++) {
|
||||
QString label = i.key();
|
||||
uint32_t metatileId = i.value();
|
||||
|
|
@ -1590,7 +1626,7 @@ bool Project::readWildMonData() {
|
|||
const QString encounterRateFile = projectConfig.getFilePath(ProjectFilePath::wild_encounter);
|
||||
const QString maxEncounterRateName = projectConfig.getIdentifier(ProjectIdentifier::define_max_encounter_rate);
|
||||
|
||||
fileWatcher.addPath(QString("%1/%2").arg(root).arg(encounterRateFile));
|
||||
watchFile(encounterRateFile);
|
||||
auto defines = parser.readCDefinesByName(encounterRateFile, {maxEncounterRateName});
|
||||
if (defines.contains(maxEncounterRateName))
|
||||
this->maxEncounterRate = defines.value(maxEncounterRateName)/16;
|
||||
|
|
@ -1599,8 +1635,7 @@ bool Project::readWildMonData() {
|
|||
const QString levelRangeFile = projectConfig.getFilePath(ProjectFilePath::constants_pokemon);
|
||||
const QString minLevelName = projectConfig.getIdentifier(ProjectIdentifier::define_min_level);
|
||||
const QString maxLevelName = projectConfig.getIdentifier(ProjectIdentifier::define_max_level);
|
||||
|
||||
fileWatcher.addPath(QString("%1/%2").arg(root).arg(levelRangeFile));
|
||||
watchFile(levelRangeFile);
|
||||
defines = parser.readCDefinesByName(levelRangeFile, {minLevelName, maxLevelName});
|
||||
if (defines.contains(minLevelName))
|
||||
this->pokemonMinLevel = defines.value(minLevelName);
|
||||
|
|
@ -1612,7 +1647,7 @@ bool Project::readWildMonData() {
|
|||
|
||||
// Read encounter data
|
||||
const QString wildMonJsonFilepath = projectConfig.getFilePath(ProjectFilePath::json_wild_encounters);
|
||||
fileWatcher.addPath(QString("%1/%2").arg(this->root).arg(wildMonJsonFilepath));
|
||||
watchFile(wildMonJsonFilepath);
|
||||
|
||||
OrderedJson::object wildMonObj;
|
||||
QString error;
|
||||
|
|
@ -1769,7 +1804,7 @@ bool Project::readMapGroups() {
|
|||
this->customMapGroupsData = QJsonObject();
|
||||
|
||||
const QString filepath = projectConfig.getFilePath(ProjectFilePath::json_map_groups);
|
||||
fileWatcher.addPath(root + "/" + filepath);
|
||||
watchFile(filepath);
|
||||
QJsonDocument mapGroupsDoc;
|
||||
QString error;
|
||||
if (!parser.tryParseJsonFile(&mapGroupsDoc, filepath, &error)) {
|
||||
|
|
@ -2072,7 +2107,7 @@ bool Project::readTilesetLabels() {
|
|||
// If the tileset headers file is missing, the user may still have the old assembly format.
|
||||
this->usingAsmTilesets = true;
|
||||
QString asm_filename = projectConfig.getFilePath(ProjectFilePath::tilesets_headers_asm);
|
||||
QString text = parser.readTextFile(this->root + "/" + asm_filename);
|
||||
QString text = parser.loadTextFile(asm_filename);
|
||||
if (text.isEmpty()) {
|
||||
logError(QString("Failed to read tileset labels from '%1' or '%2'.").arg(filename).arg(asm_filename));
|
||||
return false;
|
||||
|
|
@ -2119,17 +2154,16 @@ bool Project::readFieldmapProperties() {
|
|||
const QString mapOffsetHeightName = projectConfig.getIdentifier(ProjectIdentifier::define_map_offset_height);
|
||||
|
||||
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_fieldmap);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
const QMap<QString, int> defines = parser.readCDefinesByName(filename, {
|
||||
numTilesPrimaryName,
|
||||
numTilesTotalName,
|
||||
numMetatilesPrimaryName,
|
||||
numPalsPrimaryName,
|
||||
numPalsTotalName,
|
||||
maxMapSizeName,
|
||||
numTilesPerMetatileName,
|
||||
mapOffsetWidthName,
|
||||
mapOffsetHeightName,
|
||||
watchFile(filename);
|
||||
const auto defines = parser.readCDefinesByName(filename, { numTilesPrimaryName,
|
||||
numTilesTotalName,
|
||||
numMetatilesPrimaryName,
|
||||
numPalsPrimaryName,
|
||||
numPalsTotalName,
|
||||
maxMapSizeName,
|
||||
numTilesPerMetatileName,
|
||||
mapOffsetWidthName,
|
||||
mapOffsetHeightName,
|
||||
});
|
||||
|
||||
auto loadDefine = [defines](const QString name, int * dest, int min, int max) {
|
||||
|
|
@ -2223,16 +2257,14 @@ bool Project::readFieldmapMasks() {
|
|||
const QString elevationMaskName = projectConfig.getIdentifier(ProjectIdentifier::define_mask_elevation);
|
||||
const QString behaviorMaskName = projectConfig.getIdentifier(ProjectIdentifier::define_mask_behavior);
|
||||
const QString layerTypeMaskName = projectConfig.getIdentifier(ProjectIdentifier::define_mask_layer);
|
||||
const QSet<QString> searchNames = {
|
||||
metatileIdMaskName,
|
||||
collisionMaskName,
|
||||
elevationMaskName,
|
||||
behaviorMaskName,
|
||||
layerTypeMaskName,
|
||||
};
|
||||
const QString globalFieldmap = projectConfig.getFilePath(ProjectFilePath::global_fieldmap);
|
||||
fileWatcher.addPath(root + "/" + globalFieldmap);
|
||||
QMap<QString, int> defines = parser.readCDefinesByName(globalFieldmap, searchNames);
|
||||
|
||||
const QString globalFieldmap = projectConfig.getFilePath(ProjectFilePath::global_fieldmap); // File already being watched
|
||||
const auto defines = parser.readCDefinesByName(globalFieldmap, { metatileIdMaskName,
|
||||
collisionMaskName,
|
||||
elevationMaskName,
|
||||
behaviorMaskName,
|
||||
layerTypeMaskName,
|
||||
});
|
||||
|
||||
// These mask values are accessible via the settings editor for users who don't have these defines.
|
||||
// If users do have the defines we disable them in the settings editor and direct them to their project files.
|
||||
|
|
@ -2243,8 +2275,8 @@ bool Project::readFieldmapMasks() {
|
|||
|
||||
// Read Block masks
|
||||
auto readBlockMask = [defines](const QString name, uint16_t *value) {
|
||||
auto it = defines.find(name);
|
||||
if (it == defines.end())
|
||||
auto it = defines.constFind(name);
|
||||
if (it == defines.constEnd())
|
||||
return false;
|
||||
*value = static_cast<uint16_t>(it.value());
|
||||
if (*value != it.value()){
|
||||
|
|
@ -2281,7 +2313,7 @@ bool Project::readFieldmapMasks() {
|
|||
const QString layerTypeTableName = projectConfig.getIdentifier(ProjectIdentifier::define_attribute_layer);
|
||||
const QString encounterTypeTableName = projectConfig.getIdentifier(ProjectIdentifier::define_attribute_encounter);
|
||||
const QString terrainTypeTableName = projectConfig.getIdentifier(ProjectIdentifier::define_attribute_terrain);
|
||||
fileWatcher.addPath(root + "/" + srcFieldmap);
|
||||
watchFile(srcFieldmap);
|
||||
|
||||
bool ok;
|
||||
// Read terrain type mask
|
||||
|
|
@ -2318,7 +2350,7 @@ bool Project::readFieldmapMasks() {
|
|||
// Read #defines for encounter and terrain types to populate in the Tileset Editor dropdowns (if necessary)
|
||||
QString error;
|
||||
if (projectConfig.metatileEncounterTypeMask) {
|
||||
QMap<QString, int> defines = parser.readCDefinesByRegex(globalFieldmap, {projectConfig.getIdentifier(ProjectIdentifier::regex_encounter_types)}, &error);
|
||||
const auto defines = parser.readCDefinesByRegex(globalFieldmap, {projectConfig.getIdentifier(ProjectIdentifier::regex_encounter_types)}, &error);
|
||||
if (!error.isEmpty()) {
|
||||
logWarn(QString("Failed to read encounter type constants from '%1': %2").arg(globalFieldmap).arg(error));
|
||||
error = QString();
|
||||
|
|
@ -2329,7 +2361,7 @@ bool Project::readFieldmapMasks() {
|
|||
}
|
||||
}
|
||||
if (projectConfig.metatileTerrainTypeMask) {
|
||||
QMap<QString, int> defines = parser.readCDefinesByRegex(globalFieldmap, {projectConfig.getIdentifier(ProjectIdentifier::regex_terrain_types)}, &error);
|
||||
const auto defines = parser.readCDefinesByRegex(globalFieldmap, {projectConfig.getIdentifier(ProjectIdentifier::regex_terrain_types)}, &error);
|
||||
if (!error.isEmpty()) {
|
||||
logWarn(QString("Failed to read terrain type constants from '%1': %2").arg(globalFieldmap).arg(error));
|
||||
error = QString();
|
||||
|
|
@ -2359,7 +2391,7 @@ bool Project::readRegionMapSections() {
|
|||
logError(QString("Failed to read region map sections from '%1': %2").arg(filepath).arg(error));
|
||||
return false;
|
||||
}
|
||||
fileWatcher.addPath(QString("%1/%2").arg(this->root).arg(filepath));
|
||||
watchFile(filepath);
|
||||
|
||||
QJsonObject mapSectionsGlobalObj = doc.object();
|
||||
QJsonArray mapSections = mapSectionsGlobalObj.take("map_sections").toArray();
|
||||
|
|
@ -2523,7 +2555,7 @@ bool Project::readHealLocations() {
|
|||
logError(QString("Failed to read heal locations from '%1': %2").arg(filepath).arg(error));
|
||||
return false;
|
||||
}
|
||||
fileWatcher.addPath(QString("%1/%2").arg(this->root).arg(filepath));
|
||||
watchFile(filepath);
|
||||
|
||||
QJsonObject healLocationsObj = doc.object();
|
||||
QJsonArray healLocations = healLocationsObj.take("heal_locations").toArray();
|
||||
|
|
@ -2546,7 +2578,7 @@ bool Project::readHealLocations() {
|
|||
|
||||
bool Project::readItemNames() {
|
||||
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_items);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
watchFile(filename);
|
||||
QString error;
|
||||
this->itemNames = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_items)}, &error);
|
||||
if (!error.isEmpty())
|
||||
|
|
@ -2556,7 +2588,7 @@ bool Project::readItemNames() {
|
|||
|
||||
bool Project::readFlagNames() {
|
||||
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_flags);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
watchFile(filename);
|
||||
QString error;
|
||||
this->flagNames = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_flags)}, &error);
|
||||
if (!error.isEmpty())
|
||||
|
|
@ -2566,7 +2598,7 @@ bool Project::readFlagNames() {
|
|||
|
||||
bool Project::readVarNames() {
|
||||
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_vars);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
watchFile(filename);
|
||||
QString error;
|
||||
this->varNames = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_vars)}, &error);
|
||||
if (!error.isEmpty())
|
||||
|
|
@ -2576,7 +2608,7 @@ bool Project::readVarNames() {
|
|||
|
||||
bool Project::readMovementTypes() {
|
||||
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_obj_event_movement);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
watchFile(filename);
|
||||
QString error;
|
||||
this->movementTypes = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_movement_types)}, &error);
|
||||
if (!error.isEmpty())
|
||||
|
|
@ -2586,7 +2618,7 @@ bool Project::readMovementTypes() {
|
|||
|
||||
bool Project::readInitialFacingDirections() {
|
||||
QString filename = projectConfig.getFilePath(ProjectFilePath::initial_facing_table);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
watchFile(filename);
|
||||
QString error;
|
||||
this->facingDirections = parser.readNamedIndexCArray(filename, projectConfig.getIdentifier(ProjectIdentifier::symbol_facing_directions), &error);
|
||||
if (!error.isEmpty())
|
||||
|
|
@ -2596,7 +2628,7 @@ bool Project::readInitialFacingDirections() {
|
|||
|
||||
bool Project::readMapTypes() {
|
||||
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_map_types);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
// File already being watched
|
||||
QString error;
|
||||
this->mapTypes = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_map_types)}, &error);
|
||||
if (!error.isEmpty())
|
||||
|
|
@ -2606,7 +2638,7 @@ bool Project::readMapTypes() {
|
|||
|
||||
bool Project::readMapBattleScenes() {
|
||||
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_map_types);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
// File already being watched
|
||||
QString error;
|
||||
this->mapBattleScenes = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_battle_scenes)}, &error);
|
||||
if (!error.isEmpty())
|
||||
|
|
@ -2616,7 +2648,7 @@ bool Project::readMapBattleScenes() {
|
|||
|
||||
bool Project::readWeatherNames() {
|
||||
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_weather);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
watchFile(filename);
|
||||
QString error;
|
||||
this->weatherNames = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_weather)}, &error);
|
||||
if (!error.isEmpty())
|
||||
|
|
@ -2629,7 +2661,7 @@ bool Project::readCoordEventWeatherNames() {
|
|||
return true;
|
||||
|
||||
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_weather);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
watchFile(filename);
|
||||
QString error;
|
||||
this->coordEventWeatherNames = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_coord_event_weather)}, &error);
|
||||
if (!error.isEmpty())
|
||||
|
|
@ -2642,7 +2674,7 @@ bool Project::readSecretBaseIds() {
|
|||
return true;
|
||||
|
||||
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_secret_bases);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
watchFile(filename);
|
||||
QString error;
|
||||
this->secretBaseIds = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_secret_bases)}, &error);
|
||||
if (!error.isEmpty())
|
||||
|
|
@ -2652,7 +2684,7 @@ bool Project::readSecretBaseIds() {
|
|||
|
||||
bool Project::readBgEventFacingDirections() {
|
||||
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_event_bg);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
watchFile(filename);
|
||||
QString error;
|
||||
this->bgEventFacingDirections = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_sign_facing_directions)}, &error);
|
||||
if (!error.isEmpty())
|
||||
|
|
@ -2662,7 +2694,7 @@ bool Project::readBgEventFacingDirections() {
|
|||
|
||||
bool Project::readTrainerTypes() {
|
||||
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_trainer_types);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
watchFile(filename);
|
||||
QString error;
|
||||
this->trainerTypes = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_trainer_types)}, &error);
|
||||
if (!error.isEmpty())
|
||||
|
|
@ -2675,9 +2707,9 @@ bool Project::readMetatileBehaviors() {
|
|||
this->metatileBehaviorMapInverse.clear();
|
||||
|
||||
QString filename = projectConfig.getFilePath(ProjectFilePath::constants_metatile_behaviors);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
watchFile(filename);
|
||||
QString error;
|
||||
QMap<QString, int> defines = parser.readCDefinesByRegex(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_behaviors)}, &error);
|
||||
const auto defines = parser.readCDefinesByRegex(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_behaviors)}, &error);
|
||||
if (defines.isEmpty() && projectConfig.metatileBehaviorMask) {
|
||||
// Not having any metatile behavior names is ok (their values will be displayed instead)
|
||||
// but if the user's metatiles can have nonzero values then warn them, as they likely want names.
|
||||
|
|
@ -2697,7 +2729,7 @@ bool Project::readMetatileBehaviors() {
|
|||
|
||||
bool Project::readSongNames() {
|
||||
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_songs);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
watchFile(filename);
|
||||
QString error;
|
||||
this->songNames = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_music)}, &error);
|
||||
if (!error.isEmpty())
|
||||
|
|
@ -2712,19 +2744,24 @@ bool Project::readSongNames() {
|
|||
|
||||
bool Project::readObjEventGfxConstants() {
|
||||
QString filename = projectConfig.getFilePath(ProjectFilePath::constants_obj_events);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
watchFile(filename);
|
||||
QString error;
|
||||
this->gfxDefines = parser.readCDefinesByRegex(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_obj_event_gfx)}, &error);
|
||||
const auto defines = parser.readCDefinesByRegex(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_obj_event_gfx)}, &error);
|
||||
if (!error.isEmpty())
|
||||
logWarn(QString("Failed to read object event graphics constants from '%1': %2").arg(filename).arg(error));
|
||||
|
||||
this->gfxDefines.clear();
|
||||
for (auto it = defines.constBegin(); it != defines.constEnd(); it++)
|
||||
this->gfxDefines.insert(it.key(), it.value());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Project::readMiscellaneousConstants() {
|
||||
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_global);
|
||||
const QString maxObjectEventsName = projectConfig.getIdentifier(ProjectIdentifier::define_obj_event_count);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
QMap<QString, int> defines = parser.readCDefinesByName(filename, {maxObjectEventsName});
|
||||
watchFile(filename);
|
||||
const auto defines = parser.readCDefinesByName(filename, {maxObjectEventsName});
|
||||
|
||||
this->maxObjectEvents = 64; // Default value
|
||||
auto it = defines.find(maxObjectEventsName);
|
||||
|
|
@ -2747,6 +2784,19 @@ bool Project::readMiscellaneousConstants() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Project::readGlobalConstants() {
|
||||
this->parser.resetCDefines();
|
||||
for (const auto &path : projectConfig.globalConstantsFilepaths) {
|
||||
QString error;
|
||||
this->parser.loadGlobalCDefinesFromFile(path, &error);
|
||||
if (!error.isEmpty()) {
|
||||
logWarn(QString("Failed to read global constants file '%1': %2").arg(path).arg(error));
|
||||
}
|
||||
}
|
||||
this->parser.loadGlobalCDefines(projectConfig.globalConstants);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Project::readEventScriptLabels() {
|
||||
this->globalScriptLabels.clear();
|
||||
|
||||
|
|
@ -2837,7 +2887,7 @@ bool Project::readEventGraphics() {
|
|||
const QString gfxInfoFilepath = projectConfig.getFilePath(ProjectFilePath::data_obj_event_gfx_info);
|
||||
const QString picTablesFilepath = projectConfig.getFilePath(ProjectFilePath::data_obj_event_pic_tables);
|
||||
const QString gfxFilepath = projectConfig.getFilePath(ProjectFilePath::data_obj_event_gfx);
|
||||
fileWatcher.addPaths({pointersFilepath, gfxInfoFilepath, picTablesFilepath, gfxFilepath});
|
||||
watchFiles({pointersFilepath, gfxInfoFilepath, picTablesFilepath, gfxFilepath});
|
||||
|
||||
// Read the table mapping OBJ_EVENT_GFX constants to the names of pointers to data about their graphics.
|
||||
const QString pointersName = projectConfig.getIdentifier(ProjectIdentifier::symbol_obj_event_gfx_pointers);
|
||||
|
|
@ -2944,9 +2994,7 @@ QPixmap Project::getEventPixmap(const QString &gfxName, int frame, bool hFlip) {
|
|||
// Invalid gfx constant. If this is a number, try to use that instead.
|
||||
bool ok;
|
||||
int gfxNum = ParseUtil::gameStringToInt(gfxName, &ok);
|
||||
if (ok && gfxNum < this->gfxDefines.count()) {
|
||||
gfx = this->eventGraphicsMap.value(this->gfxDefines.key(gfxNum, "NULL"), nullptr);
|
||||
}
|
||||
if (ok) gfx = this->eventGraphicsMap.value(this->gfxDefines.key(gfxNum, "NULL"), nullptr);
|
||||
}
|
||||
if (gfx && !gfx->loaded) {
|
||||
// This is the first request for this event's sprite. We'll attempt to load it now.
|
||||
|
|
@ -3040,14 +3088,14 @@ bool Project::readSpeciesIconPaths() {
|
|||
|
||||
// Read map of species constants to icon names
|
||||
const QString srcfilename = projectConfig.getFilePath(ProjectFilePath::pokemon_icon_table);
|
||||
fileWatcher.addPath(this->root + "/" + srcfilename);
|
||||
watchFile(srcfilename);
|
||||
const QString tableName = projectConfig.getIdentifier(ProjectIdentifier::symbol_pokemon_icon_table);
|
||||
const QMap<QString, QString> monIconNames = parser.readNamedIndexCArray(srcfilename, tableName);
|
||||
|
||||
// Read species constants. If this fails we can get them from the icon table (but we shouldn't rely on it).
|
||||
const QString speciesPrefix = projectConfig.getIdentifier(ProjectIdentifier::define_species_prefix);
|
||||
const QString constantsFilename = projectConfig.getFilePath(ProjectFilePath::constants_species);
|
||||
fileWatcher.addPath(this->root + "/" + constantsFilename);
|
||||
watchFile(constantsFilename);
|
||||
this->speciesNames = parser.readCDefineNames(constantsFilename, {QString("\\b%1").arg(speciesPrefix)});
|
||||
if (this->speciesNames.isEmpty()) {
|
||||
this->speciesNames = monIconNames.keys();
|
||||
|
|
@ -3060,7 +3108,7 @@ bool Project::readSpeciesIconPaths() {
|
|||
// do this on request in Project::getDefaultSpeciesIconPath.
|
||||
if (!monIconNames.isEmpty()) {
|
||||
const QString iconGraphicsFile = projectConfig.getFilePath(ProjectFilePath::data_pokemon_gfx);
|
||||
fileWatcher.addPath(this->root + "/" + iconGraphicsFile);
|
||||
watchFile(iconGraphicsFile);
|
||||
QMap<QString, QString> iconNameToFilepath = parser.readCIncbinMulti(iconGraphicsFile);
|
||||
|
||||
for (auto i = monIconNames.constBegin(); i != monIconNames.constEnd(); i++) {
|
||||
|
|
|
|||
|
|
@ -268,14 +268,13 @@ void Scripting::cb_LayoutOpened(QString layoutName) {
|
|||
instance->invokeCallback(OnLayoutOpened, args);
|
||||
}
|
||||
|
||||
void Scripting::cb_MapResized(int oldWidth, int oldHeight, int newWidth, int newHeight) {
|
||||
void Scripting::cb_MapResized(int oldWidth, int oldHeight, const QMargins &delta) {
|
||||
if (!instance) return;
|
||||
|
||||
QJSValueList args {
|
||||
oldWidth,
|
||||
oldHeight,
|
||||
newWidth,
|
||||
newHeight,
|
||||
Scripting::margins(delta),
|
||||
};
|
||||
instance->invokeCallback(OnMapResized, args);
|
||||
}
|
||||
|
|
@ -356,6 +355,15 @@ QJSValue Scripting::dimensions(int width, int height) {
|
|||
return obj;
|
||||
}
|
||||
|
||||
QJSValue Scripting::margins(const QMargins &margins) {
|
||||
QJSValue obj = instance->engine->newObject();
|
||||
obj.setProperty("left", margins.left());
|
||||
obj.setProperty("right", margins.right());
|
||||
obj.setProperty("top", margins.top());
|
||||
obj.setProperty("bottom", margins.bottom());
|
||||
return obj;
|
||||
}
|
||||
|
||||
QJSValue Scripting::position(int x, int y) {
|
||||
QJSValue obj = instance->engine->newObject();
|
||||
obj.setProperty("x", x);
|
||||
|
|
|
|||
|
|
@ -9,15 +9,19 @@ AboutPorymap::AboutPorymap(QWidget *parent) :
|
|||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
static const QString commitHash = PORYMAP_LATEST_COMMIT;
|
||||
this->ui->label_Version->setText(QString("Version %1%2\nQt %3 (%4)\n%5")
|
||||
this->ui->label_Version->setText(getVersionString());
|
||||
|
||||
layout()->setSizeConstraint(QLayout::SetFixedSize);
|
||||
}
|
||||
|
||||
QString AboutPorymap::getVersionString() {
|
||||
static const QString commitHash = PORYMAP_LATEST_COMMIT;
|
||||
return QString("Version %1%2\nQt %3 (%4)\n%5")
|
||||
.arg(QCoreApplication::applicationVersion())
|
||||
.arg(commitHash.isEmpty() ? "" : QString(" (%1)").arg(commitHash))
|
||||
.arg(QStringLiteral(QT_VERSION_STR))
|
||||
.arg(QSysInfo::buildCpuArchitecture())
|
||||
.arg(QStringLiteral(__DATE__))
|
||||
);
|
||||
|
||||
layout()->setSizeConstraint(QLayout::SetFixedSize);
|
||||
.arg(QStringLiteral(__DATE__));
|
||||
}
|
||||
|
||||
AboutPorymap::~AboutPorymap()
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ void ConnectionsListItem::commitDirection() {
|
|||
if (MapConnection::isDiving(direction)) {
|
||||
// Diving maps are displayed separately, no support right now for replacing a list item with a diving map.
|
||||
// For now just restore the original direction.
|
||||
ui->comboBox_Direction->setCurrentText(this->connection->direction());
|
||||
ui->comboBox_Direction->setTextItem(this->connection->direction());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include "divingmappixmapitem.h"
|
||||
#include "config.h"
|
||||
|
||||
DivingMapPixmapItem::DivingMapPixmapItem(MapConnection *connection, QComboBox *combo)
|
||||
DivingMapPixmapItem::DivingMapPixmapItem(MapConnection *connection, NoScrollComboBox *combo)
|
||||
: QGraphicsPixmapItem(getBasePixmap(connection))
|
||||
{
|
||||
m_connection = connection;
|
||||
|
|
@ -38,5 +38,5 @@ void DivingMapPixmapItem::onTargetMapChanged() {
|
|||
}
|
||||
|
||||
void DivingMapPixmapItem::setComboText(const QString &text) {
|
||||
if (m_combo) m_combo->setCurrentText(text);
|
||||
if (m_combo) m_combo->setTextItem(text);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ QWidget *SpeciesComboDelegate::createEditor(QWidget *parent, const QStyleOptionV
|
|||
void SpeciesComboDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const {
|
||||
QString species = index.data(Qt::EditRole).toString();
|
||||
NoScrollComboBox *combo = static_cast<NoScrollComboBox *>(editor);
|
||||
combo->setCurrentText(species);
|
||||
combo->setTextItem(species);
|
||||
}
|
||||
|
||||
void SpeciesComboDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const {
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ void EventFrame::populateDropdown(NoScrollComboBox * combo, const QStringList &i
|
|||
const QString savedText = combo->currentText();
|
||||
combo->clear();
|
||||
combo->addItems(items);
|
||||
combo->setCurrentText(savedText);
|
||||
combo->setTextItem(savedText);
|
||||
}
|
||||
|
||||
void EventFrame::populateScriptDropdown(NoScrollComboBox * combo, Project * project) {
|
||||
|
|
@ -436,7 +436,7 @@ void ObjectFrame::initialize() {
|
|||
this->spinner_radius_y->setValue(this->object->getRadiusY());
|
||||
|
||||
// script
|
||||
this->combo_script->setCurrentText(this->object->getScript());
|
||||
this->combo_script->setTextItem(this->object->getScript());
|
||||
if (porymapConfig.textEditorGotoLine.isEmpty())
|
||||
this->button_script->hide();
|
||||
|
||||
|
|
@ -447,7 +447,7 @@ void ObjectFrame::initialize() {
|
|||
this->combo_trainer_type->setTextItem(this->object->getTrainerType());
|
||||
|
||||
// sight berry
|
||||
this->combo_radius_treeid->setCurrentText(this->object->getSightRadiusBerryTreeID());
|
||||
this->combo_radius_treeid->setTextItem(this->object->getSightRadiusBerryTreeID());
|
||||
}
|
||||
|
||||
void ObjectFrame::populate(Project *project) {
|
||||
|
|
@ -531,7 +531,7 @@ void CloneObjectFrame::connectSignals(MainWindow *window) {
|
|||
connect(this->combo_target_map, &QComboBox::currentTextChanged, [this](const QString &mapName) {
|
||||
this->clone->setTargetMap(mapName);
|
||||
this->clone->getPixmapItem()->render(this->project);
|
||||
this->combo_sprite->setCurrentText(this->clone->getGfx());
|
||||
this->combo_sprite->setTextItem(this->clone->getGfx());
|
||||
this->clone->modify();
|
||||
populateIdNameDropdown(this->combo_target_id, this->project, mapName, Event::Group::Object);
|
||||
});
|
||||
|
|
@ -542,7 +542,7 @@ void CloneObjectFrame::connectSignals(MainWindow *window) {
|
|||
connect(this->combo_target_id, &QComboBox::currentTextChanged, [this](const QString &text) {
|
||||
this->clone->setTargetID(text);
|
||||
this->clone->getPixmapItem()->render(this->project);
|
||||
this->combo_sprite->setCurrentText(this->clone->getGfx());
|
||||
this->combo_sprite->setTextItem(this->clone->getGfx());
|
||||
this->clone->modify();
|
||||
});
|
||||
}
|
||||
|
|
@ -565,10 +565,10 @@ void CloneObjectFrame::initialize() {
|
|||
this->line_edit_local_id->setText(this->clone->getIdName());
|
||||
|
||||
// sprite
|
||||
this->combo_sprite->setCurrentText(this->clone->getGfx());
|
||||
this->combo_sprite->setTextItem(this->clone->getGfx());
|
||||
|
||||
// target id
|
||||
this->combo_target_id->setCurrentText(this->clone->getTargetID());
|
||||
this->combo_target_id->setTextItem(this->clone->getTargetID());
|
||||
|
||||
// target map
|
||||
this->combo_target_map->setTextItem(this->clone->getTargetMap());
|
||||
|
|
@ -681,7 +681,7 @@ void WarpFrame::initialize() {
|
|||
this->combo_dest_map->setTextItem(this->warp->getDestinationMap());
|
||||
|
||||
// dest id
|
||||
this->combo_dest_warp->setCurrentText(this->warp->getDestinationWarpID());
|
||||
this->combo_dest_warp->setTextItem(this->warp->getDestinationWarpID());
|
||||
}
|
||||
|
||||
void WarpFrame::populate(Project *project) {
|
||||
|
|
@ -762,13 +762,13 @@ void TriggerFrame::initialize() {
|
|||
EventFrame::initialize();
|
||||
|
||||
// script
|
||||
this->combo_script->setCurrentText(this->trigger->getScriptLabel());
|
||||
this->combo_script->setTextItem(this->trigger->getScriptLabel());
|
||||
|
||||
// var
|
||||
this->combo_var->setTextItem(this->trigger->getScriptVar());
|
||||
|
||||
// var value
|
||||
this->combo_var_value->setCurrentText(this->trigger->getScriptVarValue());
|
||||
this->combo_var_value->setTextItem(this->trigger->getScriptVarValue());
|
||||
}
|
||||
|
||||
void TriggerFrame::populate(Project *project) {
|
||||
|
|
@ -885,7 +885,7 @@ void SignFrame::initialize() {
|
|||
this->combo_facing_dir->setTextItem(this->sign->getFacingDirection());
|
||||
|
||||
// script
|
||||
this->combo_script->setCurrentText(this->sign->getScriptLabel());
|
||||
this->combo_script->setTextItem(this->sign->getScriptLabel());
|
||||
}
|
||||
|
||||
void SignFrame::populate(Project *project) {
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ void GridSettingsDialog::updateInput() {
|
|||
ui->colorInput->setColor(m_settings->color.rgb());
|
||||
|
||||
const QSignalBlocker b_Style(ui->comboBox_Style);
|
||||
ui->comboBox_Style->setCurrentText(GridSettings::getStyleName(m_settings->style));
|
||||
ui->comboBox_Style->setTextItem(GridSettings::getStyleName(m_settings->style));
|
||||
}
|
||||
|
||||
void GridSettingsDialog::setWidth(int value) {
|
||||
|
|
|
|||
82
src/ui/loadingscreen.cpp
Normal file
82
src/ui/loadingscreen.cpp
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
#include "loadingscreen.h"
|
||||
#include "aboutporymap.h"
|
||||
#include "ui_loadingscreen.h"
|
||||
#include "qgifimage.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
PorymapLoadingScreen *porysplash = nullptr;
|
||||
|
||||
|
||||
|
||||
PorymapLoadingScreen::~PorymapLoadingScreen() {
|
||||
delete ui;
|
||||
}
|
||||
|
||||
PorymapLoadingScreen::PorymapLoadingScreen(QWidget *parent) : QWidget(parent), ui(new Ui::LoadingScreen) {
|
||||
ui->setupUi(this);
|
||||
this->setWindowFlags(Qt::FramelessWindowHint);
|
||||
|
||||
this->splashImage.load(":/images/porysplash.gif");
|
||||
|
||||
connect(&this->timer, &QTimer::timeout, this, &PorymapLoadingScreen::updateFrame);
|
||||
}
|
||||
|
||||
void PorymapLoadingScreen::start() {
|
||||
static bool shownVersion = false;
|
||||
if (!shownVersion) {
|
||||
this->ui->labelVersion->setText(AboutPorymap::getVersionString());
|
||||
shownVersion = true;
|
||||
}
|
||||
|
||||
this->frame = 0;
|
||||
this->ui->labelPixmap->setPixmap(QPixmap::fromImage(this->splashImage.frame(this->frame)));
|
||||
|
||||
this->ui->labelText->setText("");
|
||||
|
||||
this->timer.start(120);
|
||||
this->show();
|
||||
}
|
||||
|
||||
void PorymapLoadingScreen::stop () {
|
||||
this->timer.stop();
|
||||
this->hide();
|
||||
}
|
||||
|
||||
void PorymapLoadingScreen::setPixmap(const QPixmap &pixmap) {
|
||||
if (!this->isVisible()) return;
|
||||
this->ui->labelPixmap->setPixmap(pixmap);
|
||||
}
|
||||
|
||||
// Displays the message 'prefixtext...'. The 'text' portion may be elided if it's too long.
|
||||
void PorymapLoadingScreen::showMessage(const QString &prefix, const QString &text) {
|
||||
if (!this->isVisible()) return;
|
||||
|
||||
// Limit text (excluding prefix) to avoid increasing the splash screen's width.
|
||||
static const QFontMetrics fontMetrics = this->ui->labelText->fontMetrics();
|
||||
static const int maxWidth = this->ui->labelText->width() + 1;
|
||||
int prefixWidth = fontMetrics.horizontalAdvance(prefix);
|
||||
QString message = fontMetrics.elidedText(text + QStringLiteral("..."), Qt::ElideLeft, qMax(maxWidth - prefixWidth, 0));
|
||||
message.prepend(prefix);
|
||||
|
||||
this->ui->labelText->setText(message);
|
||||
|
||||
QApplication::processEvents();
|
||||
}
|
||||
|
||||
// Displays the message 'text...'
|
||||
void PorymapLoadingScreen::showMessage(const QString &text) {
|
||||
showMessage("", text);
|
||||
}
|
||||
|
||||
// Displays the message 'Loading text...'
|
||||
void PorymapLoadingScreen::showLoadingMessage(const QString &text) {
|
||||
showMessage(QStringLiteral("Loading "), text);
|
||||
}
|
||||
|
||||
void PorymapLoadingScreen::updateFrame() {
|
||||
this->frame = (this->frame + 1) % this->splashImage.frameCount();
|
||||
this->setPixmap(QPixmap::fromImage(this->splashImage.frame(this->frame)));
|
||||
|
||||
QApplication::processEvents();
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
#include "mapheaderform.h"
|
||||
#include "ui_mapheaderform.h"
|
||||
#include "project.h"
|
||||
|
||||
MapHeaderForm::MapHeaderForm(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
|
|
@ -94,7 +93,7 @@ void MapHeaderForm::setLocations(const QStringList &locations) {
|
|||
const QString before = ui->comboBox_Location->currentText();
|
||||
ui->comboBox_Location->clear();
|
||||
ui->comboBox_Location->addItems(locations);
|
||||
ui->comboBox_Location->setCurrentText(before);
|
||||
ui->comboBox_Location->setTextItem(before);
|
||||
}
|
||||
|
||||
// Assign a MapHeader that the form will keep in sync with the UI.
|
||||
|
|
@ -187,10 +186,10 @@ void MapHeaderForm::setAllowsBiking(bool allowsBiking) { ui->checkBox_
|
|||
void MapHeaderForm::setAllowsEscaping(bool allowsEscaping) { ui->checkBox_AllowEscaping->setChecked(allowsEscaping); }
|
||||
void MapHeaderForm::setFloorNumber(int floorNumber) { ui->spinBox_FloorNumber->setValue(floorNumber); }
|
||||
|
||||
// If we always call setText / setCurrentText the user's cursor may move to the end of the text while they're typing.
|
||||
void MapHeaderForm::setText(QComboBox *combo, const QString &text) const {
|
||||
// If we always call setText / setTextItem the user's cursor may move to the end of the text while they're typing.
|
||||
void MapHeaderForm::setText(NoScrollComboBox *combo, const QString &text) const {
|
||||
if (combo->currentText() != text)
|
||||
combo->setCurrentText(text);
|
||||
combo->setTextItem(text);
|
||||
}
|
||||
void MapHeaderForm::setText(QLineEdit *lineEdit, const QString &text) const {
|
||||
if (lineEdit->text() != text)
|
||||
|
|
|
|||
|
|
@ -101,11 +101,11 @@ void MapImageExporter::setModeSpecificUi() {
|
|||
ui->comboBox_MapSelection->clear();
|
||||
if (m_map) {
|
||||
ui->comboBox_MapSelection->addItems(m_project->mapNames);
|
||||
ui->comboBox_MapSelection->setCurrentText(m_map->name());
|
||||
ui->comboBox_MapSelection->setTextItem(m_map->name());
|
||||
ui->label_MapSelection->setText(m_mode == ImageExporterMode::Stitch ? QStringLiteral("Starting Map") : QStringLiteral("Map"));
|
||||
} else if (m_layout) {
|
||||
ui->comboBox_MapSelection->addItems(m_project->layoutIds);
|
||||
ui->comboBox_MapSelection->setCurrentText(m_layout->id);
|
||||
ui->comboBox_MapSelection->setTextItem(m_layout->id);
|
||||
ui->label_MapSelection->setText(QStringLiteral("Layout"));
|
||||
}
|
||||
|
||||
|
|
@ -146,7 +146,7 @@ void MapImageExporter::setLayout(Layout *layout) {
|
|||
|
||||
void MapImageExporter::setSelectionText(const QString &text) {
|
||||
const QSignalBlocker b(ui->comboBox_MapSelection);
|
||||
ui->comboBox_MapSelection->setCurrentText(text);
|
||||
ui->comboBox_MapSelection->setTextItem(text);
|
||||
updateMapSelection();
|
||||
}
|
||||
|
||||
|
|
@ -171,7 +171,7 @@ void MapImageExporter::updateMapSelection() {
|
|||
|
||||
// Ensure text in the combo box remains valid
|
||||
const QSignalBlocker b(ui->comboBox_MapSelection);
|
||||
ui->comboBox_MapSelection->setCurrentText(m_map ? m_map->name() : m_layout->id);
|
||||
ui->comboBox_MapSelection->setTextItem(m_map ? m_map->name() : m_layout->id);
|
||||
|
||||
if (m_map != oldMap && (!m_map || !oldMap)) {
|
||||
// Switching to or from layout-only mode
|
||||
|
|
|
|||
|
|
@ -52,19 +52,22 @@ RecentErrorMessage::RecentErrorMessage(const QString &message, QWidget *parent)
|
|||
setDetailedText(getMostRecentError());
|
||||
}
|
||||
|
||||
int RecentErrorMessage::show(const QString &message, QWidget *parent) {
|
||||
RecentErrorMessage msgBox(message, parent);
|
||||
return msgBox.exec();
|
||||
void RecentErrorMessage::show(const QString &message, QWidget *parent) {
|
||||
auto msgBox = new RecentErrorMessage(message, parent);
|
||||
msgBox->setAttribute(Qt::WA_DeleteOnClose);
|
||||
msgBox->open();
|
||||
};
|
||||
|
||||
int ErrorMessage::show(const QString &message, QWidget *parent) {
|
||||
ErrorMessage msgBox(message, parent);
|
||||
return msgBox.exec();
|
||||
void ErrorMessage::show(const QString &message, QWidget *parent) {
|
||||
auto msgBox = new ErrorMessage(message, parent);
|
||||
msgBox->setAttribute(Qt::WA_DeleteOnClose);
|
||||
msgBox->open();
|
||||
};
|
||||
|
||||
int WarningMessage::show(const QString &message, QWidget *parent) {
|
||||
WarningMessage msgBox(message, parent);
|
||||
return msgBox.exec();
|
||||
void WarningMessage::show(const QString &message, QWidget *parent) {
|
||||
auto msgBox = new WarningMessage(message, parent);
|
||||
msgBox->setAttribute(Qt::WA_DeleteOnClose);
|
||||
msgBox->open();
|
||||
};
|
||||
|
||||
int QuestionMessage::show(const QString &message, QWidget *parent) {
|
||||
|
|
@ -72,7 +75,8 @@ int QuestionMessage::show(const QString &message, QWidget *parent) {
|
|||
return msgBox.exec();
|
||||
};
|
||||
|
||||
int InfoMessage::show(const QString &message, QWidget *parent) {
|
||||
InfoMessage msgBox(message, parent);
|
||||
return msgBox.exec();
|
||||
void InfoMessage::show(const QString &message, QWidget *parent) {
|
||||
auto msgBox = new InfoMessage(message, parent);
|
||||
msgBox->setAttribute(Qt::WA_DeleteOnClose);
|
||||
msgBox->open();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,16 +11,25 @@ MovableRect::MovableRect(bool *enabled, const QRectF &rect, const QRgb &color)
|
|||
baseRect(rect),
|
||||
color(color)
|
||||
{
|
||||
this->setVisible(*enabled);
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
/// Center rect on grid position (x, y)
|
||||
void MovableRect::updateLocation(int x, int y) {
|
||||
this->setRect(this->baseRect.x() + (x * 16),
|
||||
this->baseRect.y() + (y * 16),
|
||||
this->baseRect.width(),
|
||||
this->baseRect.height());
|
||||
this->setVisible(*this->enabled);
|
||||
setRect(this->baseRect.x() + (x * 16),
|
||||
this->baseRect.y() + (y * 16),
|
||||
this->baseRect.width(),
|
||||
this->baseRect.height());
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
void MovableRect::setActive(bool active) {
|
||||
this->active = active;
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
void MovableRect::updateVisibility() {
|
||||
setVisible(*this->enabled && this->active);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
|
|
|||
60
src/ui/newdefinedialog.cpp
Normal file
60
src/ui/newdefinedialog.cpp
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
#include "newdefinedialog.h"
|
||||
#include "ui_newdefinedialog.h"
|
||||
#include "validator.h"
|
||||
|
||||
const QString lineEdit_ErrorStylesheet = "QLineEdit { background-color: rgba(255, 0, 0, 25%) }";
|
||||
|
||||
NewDefineDialog::NewDefineDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::NewDefineDialog)
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->lineEdit_Name->setValidator(new IdentifierValidator(this));
|
||||
|
||||
connect(ui->lineEdit_Name, &QLineEdit::textChanged, this, &NewDefineDialog::onNameChanged);
|
||||
connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &NewDefineDialog::dialogButtonClicked);
|
||||
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
NewDefineDialog::~NewDefineDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void NewDefineDialog::onNameChanged(const QString &) {
|
||||
validateName(true);
|
||||
}
|
||||
|
||||
bool NewDefineDialog::validateName(bool allowEmpty) {
|
||||
const QString name = ui->lineEdit_Name->text();
|
||||
|
||||
QString errorText;
|
||||
if (name.isEmpty() && !allowEmpty) {
|
||||
errorText = QString("%1 cannot be empty.").arg(ui->label_Name->text());
|
||||
}
|
||||
|
||||
bool isValid = errorText.isEmpty();
|
||||
ui->label_NameError->setText(errorText);
|
||||
ui->label_NameError->setVisible(!isValid);
|
||||
ui->lineEdit_Name->setStyleSheet(!isValid ? lineEdit_ErrorStylesheet : "");
|
||||
return isValid;
|
||||
}
|
||||
|
||||
void NewDefineDialog::dialogButtonClicked(QAbstractButton *button) {
|
||||
auto role = ui->buttonBox->buttonRole(button);
|
||||
if (role == QDialogButtonBox::RejectRole){
|
||||
reject();
|
||||
} else if (role == QDialogButtonBox::AcceptRole) {
|
||||
accept();
|
||||
}
|
||||
}
|
||||
|
||||
void NewDefineDialog::accept() {
|
||||
if (!validateName())
|
||||
return;
|
||||
emit createdDefine(ui->lineEdit_Name->text(), ui->lineEdit_Value->text());
|
||||
QDialog::accept();
|
||||
}
|
||||
|
|
@ -167,7 +167,7 @@ void NewMapDialog::on_lineEdit_Name_textChanged(const QString &text) {
|
|||
|
||||
// Changing the map name updates the layout ID field to match.
|
||||
if (ui->comboBox_LayoutID->isEnabled()) {
|
||||
ui->comboBox_LayoutID->setCurrentText(Layout::layoutConstantFromName(text));
|
||||
ui->comboBox_LayoutID->setTextItem(Layout::layoutConstantFromName(text));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ void PreferenceEditor::initFields() {
|
|||
}
|
||||
|
||||
void PreferenceEditor::updateFields() {
|
||||
themeSelector->setCurrentText(porymapConfig.theme);
|
||||
themeSelector->setTextItem(porymapConfig.theme);
|
||||
if (porymapConfig.eventSelectionShapeMode == QGraphicsPixmapItem::MaskShape) {
|
||||
ui->radioButton_OnSprite->setChecked(true);
|
||||
} else if (porymapConfig.eventSelectionShapeMode == QGraphicsPixmapItem::BoundingRectShape) {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "noscrollcombobox.h"
|
||||
#include "prefab.h"
|
||||
#include "filedialog.h"
|
||||
#include "newdefinedialog.h"
|
||||
#include "utility.h"
|
||||
|
||||
#include <QAbstractButton>
|
||||
|
|
@ -54,6 +55,9 @@ void ProjectSettingsEditor::connectSignals() {
|
|||
connect(ui->button_AddWarpBehavior, &QAbstractButton::clicked, [this](bool) { this->updateWarpBehaviorsList(true); });
|
||||
connect(ui->button_RemoveWarpBehavior, &QAbstractButton::clicked, [this](bool) { this->updateWarpBehaviorsList(false); });
|
||||
|
||||
connect(ui->button_AddGlobalConstantsFile, &QAbstractButton::clicked, this, &ProjectSettingsEditor::addNewGlobalConstantsFilepath);
|
||||
connect(ui->button_AddGlobalConstant, &QAbstractButton::clicked, this, &ProjectSettingsEditor::addNewGlobalConstant);
|
||||
|
||||
// Connect file selection buttons
|
||||
connect(ui->button_ChoosePrefabs, &QAbstractButton::clicked, [this](bool) { this->choosePrefabsFile(); });
|
||||
connect(ui->button_CollisionGraphics, &QAbstractButton::clicked, [this](bool) { this->chooseImageFile(ui->lineEdit_CollisionGraphics); });
|
||||
|
|
@ -501,6 +505,12 @@ void ProjectSettingsEditor::refresh() {
|
|||
lineEdit->setText(projectConfig.getCustomFilePath(lineEdit->objectName()));
|
||||
for (auto lineEdit : ui->scrollAreaContents_Identifiers->findChildren<QLineEdit*>())
|
||||
lineEdit->setText(projectConfig.getCustomIdentifier(lineEdit->objectName()));
|
||||
for (const auto &path : projectConfig.globalConstantsFilepaths) {
|
||||
addGlobalConstantsFilepath(path);
|
||||
}
|
||||
for (auto it = projectConfig.globalConstants.constBegin(); it != projectConfig.globalConstants.constEnd(); it++) {
|
||||
addGlobalConstant(it.key(), it.value());
|
||||
}
|
||||
|
||||
// Set warp behaviors
|
||||
QStringList behaviorNames;
|
||||
|
|
@ -548,7 +558,7 @@ void ProjectSettingsEditor::save() {
|
|||
projectConfig.defaultCollision = ui->spinBox_Collision->value();
|
||||
projectConfig.defaultMetatileId = ui->spinBox_FillMetatile->value();
|
||||
projectConfig.defaultMapSize = QSize(ui->spinBox_MapWidth->value(), ui->spinBox_MapHeight->value());
|
||||
projectConfig.collisionSheetSize = QSize(ui->spinBox_MaxElevation->value() + 1, ui->spinBox_MaxCollision->value() + 1);
|
||||
projectConfig.collisionSheetSize = QSize(ui->spinBox_MaxCollision->value() + 1, ui->spinBox_MaxElevation->value() + 1);
|
||||
projectConfig.metatileBehaviorMask = ui->spinBox_BehaviorMask->value();
|
||||
projectConfig.metatileTerrainTypeMask = ui->spinBox_TerrainTypeMask->value();
|
||||
projectConfig.metatileEncounterTypeMask = ui->spinBox_EncounterTypeMask->value();
|
||||
|
|
@ -578,6 +588,10 @@ void ProjectSettingsEditor::save() {
|
|||
for (auto lineEdit : ui->scrollAreaContents_Identifiers->findChildren<QLineEdit*>())
|
||||
projectConfig.setIdentifier(lineEdit->objectName(), lineEdit->text());
|
||||
|
||||
// Save global constants
|
||||
projectConfig.globalConstantsFilepaths = getGlobalConstantsFilepaths();
|
||||
projectConfig.globalConstants = getGlobalConstants();
|
||||
|
||||
// Save warp behaviors
|
||||
projectConfig.warpBehaviors.clear();
|
||||
const QStringList behaviorNames = this->getWarpBehaviorsList();
|
||||
|
|
@ -624,6 +638,97 @@ void ProjectSettingsEditor::chooseFile(QLineEdit * filepathEdit, const QString &
|
|||
this->hasUnsavedChanges = true;
|
||||
}
|
||||
|
||||
void ProjectSettingsEditor::addNewGlobalConstantsFilepath() {
|
||||
QString filepath = stripProjectDir(FileDialog::getOpenFileName(this, "Choose Global Constants File"));
|
||||
if (filepath.isEmpty() || getGlobalConstantsFilepaths().contains(filepath))
|
||||
return;
|
||||
|
||||
addGlobalConstantsFilepath(filepath);
|
||||
this->hasUnsavedChanges = true;
|
||||
}
|
||||
|
||||
void ProjectSettingsEditor::addGlobalConstantsFilepath(const QString &filepath) {
|
||||
auto filepathLabel = new QLabel(filepath, this);
|
||||
filepathLabel->setFrameStyle(QFrame::Panel | QFrame::Raised);
|
||||
filepathLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||
|
||||
int newRow = ui->gridLayout_GlobalConstantsFiles->rowCount();
|
||||
ui->gridLayout_GlobalConstantsFiles->addWidget(filepathLabel, newRow, 0);
|
||||
|
||||
auto deleteButton = new QToolButton();
|
||||
deleteButton->setIcon(QIcon(":/icons/delete.ico"));
|
||||
connect(deleteButton, &QAbstractButton::clicked, [this, filepathLabel, deleteButton](bool) {
|
||||
ui->gridLayout_GlobalConstantsFiles->removeWidget(filepathLabel);
|
||||
ui->gridLayout_GlobalConstantsFiles->removeWidget(deleteButton);
|
||||
delete filepathLabel;
|
||||
delete deleteButton;
|
||||
this->hasUnsavedChanges = true;
|
||||
});
|
||||
ui->gridLayout_GlobalConstantsFiles->addWidget(deleteButton, newRow, 1);
|
||||
}
|
||||
|
||||
QStringList ProjectSettingsEditor::getGlobalConstantsFilepaths() {
|
||||
QStringList paths;
|
||||
for (int row = 1; row < ui->gridLayout_GlobalConstantsFiles->rowCount(); row++) {
|
||||
auto item = ui->gridLayout_GlobalConstantsFiles->itemAtPosition(row, 0);
|
||||
if (!item) continue;
|
||||
auto pathLabel = dynamic_cast<QLabel*>(item->widget());
|
||||
if (!pathLabel) continue;
|
||||
paths.append(pathLabel->text());
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
void ProjectSettingsEditor::addNewGlobalConstant() {
|
||||
auto dialog = new NewDefineDialog(this);
|
||||
connect(dialog, &NewDefineDialog::createdDefine, [this](const QString &name, const QString &expression) {
|
||||
if (!getGlobalConstants().contains(name)) {
|
||||
addGlobalConstant(name, expression);
|
||||
this->hasUnsavedChanges = true;
|
||||
}
|
||||
});
|
||||
dialog->open();
|
||||
}
|
||||
|
||||
void ProjectSettingsEditor::addGlobalConstant(const QString &name, const QString &expression) {
|
||||
auto nameLabel = new QLabel(name, this);
|
||||
nameLabel->setFrameStyle(QFrame::Panel | QFrame::Raised);
|
||||
nameLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||
|
||||
auto expressionLineEdit = new QLineEdit(expression, this);
|
||||
|
||||
int newRow = ui->gridLayout_GlobalConstants->rowCount();
|
||||
ui->gridLayout_GlobalConstants->addWidget(nameLabel, newRow, 0);
|
||||
ui->gridLayout_GlobalConstants->addWidget(expressionLineEdit, newRow, 1);
|
||||
|
||||
auto deleteButton = new QToolButton();
|
||||
deleteButton->setIcon(QIcon(":/icons/delete.ico"));
|
||||
connect(deleteButton, &QAbstractButton::clicked, [this, nameLabel, expressionLineEdit, deleteButton](bool) {
|
||||
ui->gridLayout_GlobalConstants->removeWidget(nameLabel);
|
||||
ui->gridLayout_GlobalConstants->removeWidget(expressionLineEdit);
|
||||
ui->gridLayout_GlobalConstants->removeWidget(deleteButton);
|
||||
delete nameLabel;
|
||||
delete expressionLineEdit;
|
||||
delete deleteButton;
|
||||
this->hasUnsavedChanges = true;
|
||||
});
|
||||
ui->gridLayout_GlobalConstants->addWidget(deleteButton, newRow, 2);
|
||||
}
|
||||
|
||||
QMap<QString,QString> ProjectSettingsEditor::getGlobalConstants() {
|
||||
QMap<QString,QString> constants;
|
||||
for (int row = 1; row < ui->gridLayout_GlobalConstants->rowCount(); row++) {
|
||||
auto nameItem = ui->gridLayout_GlobalConstants->itemAtPosition(row, 0);
|
||||
auto expressionItem = ui->gridLayout_GlobalConstants->itemAtPosition(row, 1);
|
||||
if (!nameItem || !expressionItem) continue;
|
||||
auto nameLabel = dynamic_cast<QLabel*>(nameItem->widget());
|
||||
auto expressionLineEdit = dynamic_cast<QLineEdit*>(expressionItem->widget());
|
||||
if (!nameLabel || !expressionLineEdit) continue;
|
||||
constants.insert(nameLabel->text(), expressionLineEdit->text());
|
||||
}
|
||||
return constants;
|
||||
}
|
||||
|
||||
// Display relative path if this file is in the project folder
|
||||
QString ProjectSettingsEditor::stripProjectDir(QString s) {
|
||||
if (s.startsWith(this->baseDir))
|
||||
|
|
|
|||
|
|
@ -657,7 +657,7 @@ void RegionMapEditor::displayRegionMapLayoutOptions() {
|
|||
|
||||
void RegionMapEditor::updateRegionMapLayoutOptions(int index) {
|
||||
const QSignalBlocker b_ConnectedMap(ui->comboBox_RM_ConnectedMap);
|
||||
this->ui->comboBox_RM_ConnectedMap->setCurrentText(this->region_map->squareMapSection(index));
|
||||
this->ui->comboBox_RM_ConnectedMap->setTextItem(this->region_map->squareMapSection(index));
|
||||
|
||||
this->ui->pushButton_RM_Options_delete->setEnabled(this->region_map->squareHasMap(index));
|
||||
|
||||
|
|
@ -736,7 +736,7 @@ void RegionMapEditor::updateRegionMapEntryOptions(QString section) {
|
|||
this->ui->pushButton_entryActivate->setEnabled(section != this->region_map->default_map_section);
|
||||
this->ui->pushButton_entryActivate->setText(enabled ? "Remove" : "Add");
|
||||
|
||||
this->ui->comboBox_RM_Entry_MapSection->setCurrentText(section);
|
||||
this->ui->comboBox_RM_Entry_MapSection->setTextItem(section);
|
||||
this->activeEntry = section;
|
||||
this->region_map_entries_item->currentSection = section;
|
||||
MapSectionEntry entry = enabled ? this->region_map_entries[section] : MapSectionEntry();
|
||||
|
|
@ -1296,11 +1296,11 @@ void RegionMapEditor::setLocations(const QStringList &locations) {
|
|||
auto before = ui->comboBox_RM_ConnectedMap->currentText();
|
||||
ui->comboBox_RM_ConnectedMap->clear();
|
||||
ui->comboBox_RM_ConnectedMap->addItems(locations);
|
||||
ui->comboBox_RM_ConnectedMap->setCurrentText(before);
|
||||
ui->comboBox_RM_ConnectedMap->setTextItem(before);
|
||||
|
||||
const QSignalBlocker b_MapSection(ui->comboBox_RM_Entry_MapSection);
|
||||
before = ui->comboBox_RM_Entry_MapSection->currentText();
|
||||
ui->comboBox_RM_Entry_MapSection->clear();
|
||||
ui->comboBox_RM_Entry_MapSection->addItems(locations);
|
||||
ui->comboBox_RM_Entry_MapSection->setCurrentText(before);
|
||||
ui->comboBox_RM_Entry_MapSection->setTextItem(before);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,19 +92,22 @@ QPoint SelectablePixmapItem::getCellPos(QPointF pos)
|
|||
|
||||
void SelectablePixmapItem::drawSelection()
|
||||
{
|
||||
QPixmap pixmap = this->pixmap();
|
||||
QPainter painter(&pixmap);
|
||||
QPoint origin = this->getSelectionStart();
|
||||
QPoint dimensions = this->getSelectionDimensions();
|
||||
QRect selectionRect(origin.x() * this->cellWidth, origin.y() * this->cellHeight, dimensions.x() * this->cellWidth, dimensions.y() * this->cellHeight);
|
||||
|
||||
int rectWidth = dimensions.x() * this->cellWidth;
|
||||
int rectHeight = dimensions.y() * this->cellHeight;
|
||||
// If a selection is fully outside the bounds of the selectable area, don't draw anything.
|
||||
// This prevents the border of the selection rectangle potentially being visible on an otherwise invisible selection.
|
||||
QPixmap pixmap = this->pixmap();
|
||||
if (!selectionRect.intersects(pixmap.rect()))
|
||||
return;
|
||||
|
||||
QPainter painter(&pixmap);
|
||||
painter.setPen(QColor(0xff, 0xff, 0xff));
|
||||
painter.drawRect(origin.x() * this->cellWidth, origin.y() * this->cellHeight, rectWidth - 1, rectHeight -1);
|
||||
painter.drawRect(selectionRect.x(), selectionRect.y(), selectionRect.width() - 1, selectionRect.height() - 1);
|
||||
painter.setPen(QColor(0, 0, 0));
|
||||
painter.drawRect(origin.x() * this->cellWidth - 1, origin.y() * this->cellHeight - 1, rectWidth + 1, rectHeight + 1);
|
||||
painter.drawRect(origin.x() * this->cellWidth + 1, origin.y() * this->cellHeight + 1, rectWidth - 3, rectHeight - 3);
|
||||
painter.drawRect(selectionRect.x() - 1, selectionRect.y() - 1, selectionRect.width() + 1, selectionRect.height() + 1);
|
||||
painter.drawRect(selectionRect.x() + 1, selectionRect.y() + 1, selectionRect.width() - 3, selectionRect.height() - 3);
|
||||
|
||||
this->setPixmap(pixmap);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -312,7 +312,7 @@ QBarSet* WildMonChart::createLevelDistributionBarSet(const QString &species, con
|
|||
const QSignalBlocker blocker1(ui->groupBox_Species);
|
||||
const QSignalBlocker blocker2(ui->comboBox_Species);
|
||||
ui->groupBox_Species->setChecked(true);
|
||||
ui->comboBox_Species->setCurrentText(species);
|
||||
ui->comboBox_Species->setTextItem(species);
|
||||
refreshLevelDistributionChart();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user