mirror of
https://github.com/huderlem/porymap.git
synced 2026-09-30 03:46:35 -05:00
Merge branch 'dev' into soften-map-loading
This commit is contained in:
@@ -57,6 +57,7 @@ The **"Breaking Changes"** listed below are changes that have been made in the d
|
||||
- `MAP_OFFSET_W` and `MAP_OFFSET_H` (used to limit the maximum map size) are now read from the project.
|
||||
- The rendered area of the map border is now limited to the maximum player view distance (prior to this it included two extra rows on the top and bottom).
|
||||
- An error message will now be shown when Porymap is unable to save changes (e.g. if Porymap doesn't have write permissions for your project).
|
||||
- Error and warning logs are now displayed in the status bar. This can be changed with a new setting.
|
||||
- A project may now be opened even if it has no maps or map groups. A minimum of one map layout is required.
|
||||
- The file extensions that are expected for `.png` and `.pal` data files and the extensions outputted when creating a new tileset can now be customized.
|
||||
- Miscellaneous performance improvements, especially for opening projects.
|
||||
@@ -123,6 +124,7 @@ The **"Breaking Changes"** listed below are changes that have been made in the d
|
||||
- The Metatile / Tile usage counts in the Tileset Editor now update to reflect changes.
|
||||
- Fix regression that stopped the map zoom from centering on the cursor.
|
||||
- Fix `Open Map Scripts` not working on maps with a `shared_scripts_map` field.
|
||||
- Fix the main window sometimes exceeding the screen size on first launch.
|
||||
|
||||
## [5.4.1] - 2024-03-21
|
||||
### Fixed
|
||||
|
||||
@@ -2867,6 +2867,13 @@
|
||||
<addaction name="action_Save"/>
|
||||
<addaction name="action_Save_Project"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_NewMap"/>
|
||||
<addaction name="action_NewLayout"/>
|
||||
<addaction name="actionNew_Tileset"/>
|
||||
<addaction name="actionDuplicate_Current_Map_Layout"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionImport_Map_from_Advance_Map_1_92"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_Export_Map_Image"/>
|
||||
<addaction name="actionExport_Stitched_Map_Image"/>
|
||||
<addaction name="actionExport_Map_Timelapse_Image"/>
|
||||
@@ -2909,16 +2916,9 @@
|
||||
<addaction name="actionMove"/>
|
||||
<addaction name="actionMap_Shift"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_NewMap"/>
|
||||
<addaction name="action_NewLayout"/>
|
||||
<addaction name="actionNew_Tileset"/>
|
||||
<addaction name="actionDuplicate_Current_Map_Layout"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionTileset_Editor"/>
|
||||
<addaction name="actionRegion_Map_Editor"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionImport_Map_from_Advance_Map_1_92"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionOpen_Project_in_Text_Editor"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuHelp">
|
||||
|
||||
@@ -120,6 +120,12 @@
|
||||
<height>37</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="actionImport_Palette"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuEdit">
|
||||
<property name="title">
|
||||
<string>Edit</string>
|
||||
@@ -127,14 +133,8 @@
|
||||
<addaction name="actionUndo"/>
|
||||
<addaction name="actionRedo"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuTools">
|
||||
<property name="title">
|
||||
<string>Tools</string>
|
||||
</property>
|
||||
<addaction name="actionImport_Palette"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuEdit"/>
|
||||
<addaction name="menuTools"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<action name="actionUndo">
|
||||
|
||||
@@ -80,6 +80,43 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_Logging">
|
||||
<property name="title">
|
||||
<string>Logging</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_StatusMessages">
|
||||
<property name="text">
|
||||
<string>Status bar message types</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_StatusErrors">
|
||||
<property name="text">
|
||||
<string>Errors</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_StatusWarnings">
|
||||
<property name="text">
|
||||
<string>Warnings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_StatusInformation">
|
||||
<property name="text">
|
||||
<string>Information</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>570</width>
|
||||
<height>680</height>
|
||||
<height>692</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
@@ -94,7 +94,7 @@
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/folder.ico</normaloff>:/icons/folder.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -164,7 +164,7 @@
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/folder.ico</normaloff>:/icons/folder.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -248,7 +248,7 @@
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/folder.ico</normaloff>:/icons/folder.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -467,37 +467,16 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>570</width>
|
||||
<height>622</height>
|
||||
<height>552</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_16">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_MapDataDefaults">
|
||||
<widget class="QGroupBox" name="groupBox_NewMapDefaults">
|
||||
<property name="title">
|
||||
<string>Map Data Defaults</string>
|
||||
<string>New Map Defaults</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_Elevation">
|
||||
<property name="text">
|
||||
<string>Elevation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_MapWidth">
|
||||
<property name="text">
|
||||
<string>Width</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_Elevation">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The default elevation that will be used to fill new maps</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="checkBox_CreateTextFile">
|
||||
<property name="toolTip">
|
||||
@@ -508,61 +487,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_MapWidth">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The default layout width for new maps</p></body></html></string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_MapHeight">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The default layout height for new maps</p></body></html></string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_FillMetatile">
|
||||
<property name="text">
|
||||
<string>Metatile ID</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_Collision">
|
||||
<property name="text">
|
||||
<string>Collision</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_BorderMetatiles">
|
||||
<property name="text">
|
||||
<string>Border Metatiles</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="UIntHexSpinBox" name="spinBox_FillMetatile">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The default metatile value that will be used to fill new maps</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_Collision">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The default collision that will be used to fill new maps</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="3">
|
||||
<widget class="QStackedWidget" name="stackedWidget_BorderMetatiles">
|
||||
<widget class="QWidget" name="page_CustomBorderSize">
|
||||
@@ -634,6 +558,51 @@
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<layout class="QFormLayout" name="formLayout_5">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_MapWidth">
|
||||
<property name="text">
|
||||
<string>Width</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_MapWidth">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The default layout width for new maps</p></body></html></string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_MapHeight">
|
||||
<property name="text">
|
||||
<string>Height</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_MapHeight">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The default layout height for new maps</p></body></html></string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_BorderMetatiles">
|
||||
<property name="text">
|
||||
<string>Border Metatiles</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="3">
|
||||
<widget class="QWidget" name="widget_CustomSizeBorderMetatiles" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
@@ -649,13 +618,52 @@
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="UIntHexSpinBox" name="spinBox_FillMetatile">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The default metatile value that will be used to fill new maps</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_MapHeight">
|
||||
<item row="2" column="2" colspan="2">
|
||||
<layout class="QFormLayout" name="formLayout_6">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_Elevation">
|
||||
<property name="text">
|
||||
<string>Elevation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_Collision">
|
||||
<property name="text">
|
||||
<string>Collision</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_Collision">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The default collision that will be used to fill new maps</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_Elevation">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The default elevation that will be used to fill new maps</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_FillMetatile">
|
||||
<property name="text">
|
||||
<string>Height</string>
|
||||
<string>Metatile ID</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -1197,7 +1205,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>570</width>
|
||||
<height>927</height>
|
||||
<height>915</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||
@@ -1216,7 +1224,7 @@
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/folder.ico</normaloff>:/icons/folder.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -1276,7 +1284,7 @@
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/folder.ico</normaloff>:/icons/folder.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -1308,7 +1316,7 @@
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/folder.ico</normaloff>:/icons/folder.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -1346,7 +1354,7 @@
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/folder.ico</normaloff>:/icons/folder.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -1367,7 +1375,7 @@
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/folder.ico</normaloff>:/icons/folder.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -1378,7 +1386,7 @@
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/folder.ico</normaloff>:/icons/folder.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -1411,7 +1419,7 @@
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/delete.ico</normaloff>:/icons/delete.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -1464,7 +1472,7 @@
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/add.ico</normaloff>:/icons/add.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -1674,7 +1682,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>544</width>
|
||||
<height>341</height>
|
||||
<height>338</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="layout_ProjectPaths">
|
||||
@@ -1703,7 +1711,7 @@
|
||||
<string>Add Global Constants File...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/add.ico</normaloff>:/icons/add.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -1714,7 +1722,7 @@
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/help.ico</normaloff>:/icons/help.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -1754,7 +1762,7 @@
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/help.ico</normaloff>:/icons/help.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -1791,7 +1799,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>544</width>
|
||||
<height>425</height>
|
||||
<height>421</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="layout_Identifiers">
|
||||
@@ -1820,7 +1828,7 @@
|
||||
<string>Add Global Constant...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/add.ico</normaloff>:/icons/add.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -1886,6 +1894,8 @@
|
||||
<header location="global">uintspinbox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<resources>
|
||||
<include location="../resources/images.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
||||
@@ -633,32 +633,36 @@
|
||||
</property>
|
||||
<addaction name="actionSave_Tileset"/>
|
||||
<addaction name="separator"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuTools">
|
||||
<property name="title">
|
||||
<string>Tools</string>
|
||||
</property>
|
||||
<addaction name="actionImport_Primary_Tiles"/>
|
||||
<addaction name="actionImport_Secondary_Tiles"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionImport_Primary_Metatiles"/>
|
||||
<addaction name="actionImport_Secondary_Metatiles"/>
|
||||
<addaction name="actionChange_Metatiles_Count"/>
|
||||
<addaction name="actionChange_Palettes"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionExport_Primary_Tiles_Image"/>
|
||||
<addaction name="actionExport_Secondary_Tiles_Image"/>
|
||||
<addaction name="actionExport_Primary_Metatiles_Image"/>
|
||||
<addaction name="actionExport_Secondary_Metatiles_Image"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuTools">
|
||||
<property name="title">
|
||||
<string>Tools</string>
|
||||
</property>
|
||||
<addaction name="actionChange_Palettes"/>
|
||||
<addaction name="separator"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuEdit">
|
||||
<property name="title">
|
||||
<string>Edit</string>
|
||||
</property>
|
||||
<addaction name="actionUndo"/>
|
||||
<addaction name="actionRedo"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionCut"/>
|
||||
<addaction name="actionCopy"/>
|
||||
<addaction name="actionPaste"/>
|
||||
<addaction name="actionUndo"/>
|
||||
<addaction name="actionRedo"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionChange_Metatiles_Count"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuView">
|
||||
<property name="title">
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <QUrl>
|
||||
#include <QVersionNumber>
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <set>
|
||||
|
||||
#include "events.h"
|
||||
#include "gridsettings.h"
|
||||
@@ -96,6 +97,7 @@ public:
|
||||
this->eventSelectionShapeMode = QGraphicsPixmapItem::MaskShape;
|
||||
this->shownInGameReloadMessage = false;
|
||||
this->gridSettings = GridSettings();
|
||||
this->statusBarLogTypes = { LogType::LOG_ERROR, LogType::LOG_WARN };
|
||||
}
|
||||
void addRecentProject(QString project);
|
||||
void setRecentProjects(QStringList projects);
|
||||
@@ -161,6 +163,8 @@ public:
|
||||
QByteArray newLayoutDialogGeometry;
|
||||
bool shownInGameReloadMessage;
|
||||
GridSettings gridSettings;
|
||||
// Prefer over QSet to prevent shuffling elements when writing the config file.
|
||||
std::set<LogType> statusBarLogTypes;
|
||||
|
||||
protected:
|
||||
virtual QString getConfigFilepath() override;
|
||||
|
||||
@@ -85,9 +85,12 @@ public:
|
||||
bool hasEvent(Event *) const;
|
||||
|
||||
QStringList getScriptLabels(Event::Group group = Event::Group::None);
|
||||
QString getScriptsFilePath() const;
|
||||
QString getScriptsFilepath() const;
|
||||
void openScript(const QString &label);
|
||||
|
||||
static QString getJsonFilepath(const QString &mapName);
|
||||
QString getJsonFilepath() const { return getJsonFilepath(m_name); }
|
||||
|
||||
void deleteConnections();
|
||||
QList<MapConnection*> getConnections() const { return m_connections; }
|
||||
MapConnection* getConnection(const QString &direction) const;
|
||||
|
||||
@@ -73,6 +73,8 @@ public:
|
||||
bool tryParseJsonFile(QJsonDocument *out, const QString &filepath, QString *error = nullptr);
|
||||
bool tryParseOrderedJsonFile(poryjson::Json::object *out, const QString &filepath, QString *error = nullptr);
|
||||
|
||||
static int getJsonLineNumber(const QString &filepath, const QString &searchText);
|
||||
|
||||
// Returns the 1-indexed line number for the definition of scriptLabel in the scripts file at filePath.
|
||||
// Returns 0 if a definition for scriptLabel cannot be found.
|
||||
static int getScriptLineNumber(const QString &filePath, const QString &scriptLabel);
|
||||
|
||||
@@ -184,6 +184,8 @@ public:
|
||||
void shouldReselectEvents();
|
||||
void scaleMapView(int);
|
||||
static void openInTextEditor(const QString &path, int lineNum = 0);
|
||||
void openMapJson(const QString &mapName) const;
|
||||
void openLayoutJson(const QString &layoutId) const;
|
||||
void setCollisionGraphics();
|
||||
|
||||
enum ZValue {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <QTextStream>
|
||||
#include <QString>
|
||||
#include <QDebug>
|
||||
#include <QStatusBar>
|
||||
|
||||
enum LogType {
|
||||
LOG_ERROR,
|
||||
@@ -15,12 +16,14 @@ enum LogType {
|
||||
LOG_INFO,
|
||||
};
|
||||
|
||||
void logInfo(QString message);
|
||||
void logWarn(QString message);
|
||||
void logError(QString message);
|
||||
void log(QString message, LogType type);
|
||||
void logInit();
|
||||
void logInfo(const QString &message);
|
||||
void logWarn(const QString &message);
|
||||
void logError(const QString &message);
|
||||
void log(const QString &message, LogType type);
|
||||
QString getLogPath();
|
||||
QString getMostRecentError();
|
||||
bool cleanupLargeLog();
|
||||
void addLogStatusBar(QStatusBar *statusBar, const QSet<LogType> &types = {});
|
||||
bool removeLogStatusBar(QStatusBar *statusBar);
|
||||
|
||||
#endif // LOG_H
|
||||
|
||||
@@ -412,6 +412,7 @@ private:
|
||||
void updateWindowTitle();
|
||||
|
||||
void initWindow();
|
||||
void initLogStatusBar();
|
||||
void initCustomUI();
|
||||
void initExtraSignals();
|
||||
void initEditor();
|
||||
|
||||
@@ -215,7 +215,7 @@ public:
|
||||
|
||||
static QString getScriptFileExtension(bool usePoryScript);
|
||||
QString getScriptDefaultString(bool usePoryScript, QString mapName) const;
|
||||
QStringList getEventScriptsFilePaths() const;
|
||||
QStringList getEventScriptsFilepaths() const;
|
||||
void insertGlobalScriptLabels(QStringList &scriptLabels) const;
|
||||
|
||||
QString getDefaultPrimaryTilesetLabel() const;
|
||||
|
||||
@@ -37,6 +37,9 @@ public:
|
||||
void setFilterLocked(bool locked) { m_filterLocked = locked; }
|
||||
bool isFilterLocked() const { return m_filterLocked; }
|
||||
|
||||
void setExpandListForSearch(bool expand) { m_expandListForSearch = expand; }
|
||||
bool getExpandListForSearch() const { return m_expandListForSearch; }
|
||||
|
||||
void setSearchFocus();
|
||||
|
||||
signals:
|
||||
@@ -51,6 +54,7 @@ private:
|
||||
bool m_filterLocked = false;
|
||||
bool m_editsAllowed = false;
|
||||
bool m_emptyFoldersVisible = true;
|
||||
bool m_expandListForSearch = true;
|
||||
};
|
||||
|
||||
#endif // MAPLISTTOOLBAR_H
|
||||
|
||||
BIN
resources/icons/error.ico
Normal file
BIN
resources/icons/error.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
BIN
resources/icons/information.ico
Normal file
BIN
resources/icons/information.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
BIN
resources/icons/warning.ico
Normal file
BIN
resources/icons/warning.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
@@ -5,6 +5,7 @@
|
||||
<file>icons/collapse_all.ico</file>
|
||||
<file>icons/cursor.ico</file>
|
||||
<file>icons/delete.ico</file>
|
||||
<file>icons/error.ico</file>
|
||||
<file>icons/expand_all.ico</file>
|
||||
<file>icons/file_add.ico</file>
|
||||
<file>icons/file_edit.ico</file>
|
||||
@@ -20,6 +21,7 @@
|
||||
<file>icons/folder_map_opened.ico</file>
|
||||
<file>icons/folder_map.ico</file>
|
||||
<file>icons/folder.ico</file>
|
||||
<file>icons/information.ico</file>
|
||||
<file>icons/lock_edit.ico</file>
|
||||
<file>icons/unlock_edit.ico</file>
|
||||
<file>icons/help.ico</file>
|
||||
@@ -46,6 +48,7 @@
|
||||
<file>icons/sort_map.ico</file>
|
||||
<file>icons/sort_number.ico</file>
|
||||
<file>icons/tall_grass.ico</file>
|
||||
<file>icons/warning.ico</file>
|
||||
<file>icons/minimap.ico</file>
|
||||
<file>icons/application_form_edit.ico</file>
|
||||
<file>icons/connections.ico</file>
|
||||
|
||||
@@ -476,6 +476,13 @@ void PorymapConfig::parseConfigKeyValue(QString key, QString value) {
|
||||
this->gridSettings.style = GridSettings::getStyleFromName(value);
|
||||
} else if (key == "grid_color") {
|
||||
this->gridSettings.color = getConfigColor(key, value);
|
||||
} else if (key == "status_bar_log_types") {
|
||||
this->statusBarLogTypes.clear();
|
||||
auto typeStrings = value.split(",", Qt::SkipEmptyParts);
|
||||
for (const auto &typeString : typeStrings) {
|
||||
LogType type = static_cast<LogType>(getConfigInteger(key, typeString, 0, 2));
|
||||
this->statusBarLogTypes.insert(type);
|
||||
}
|
||||
} else {
|
||||
logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->getConfigFilepath()).arg(key));
|
||||
}
|
||||
@@ -559,6 +566,12 @@ QMap<QString, QString> PorymapConfig::getKeyValueMap() {
|
||||
map.insert("grid_y", QString::number(this->gridSettings.offsetY));
|
||||
map.insert("grid_style", GridSettings::getStyleName(this->gridSettings.style));
|
||||
map.insert("grid_color", this->gridSettings.color.name().remove("#")); // Our text config treats '#' as the start of a comment.
|
||||
|
||||
QStringList logTypesStrings;
|
||||
for (const auto &type : this->statusBarLogTypes) {
|
||||
logTypesStrings.append(QString::number(type));
|
||||
}
|
||||
map.insert("status_bar_log_types", logTypesStrings.join(","));
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
@@ -148,13 +148,13 @@ void Map::invalidateScripts() {
|
||||
|
||||
QStringList Map::getScriptLabels(Event::Group group) {
|
||||
if (!m_scriptsLoaded) {
|
||||
const QString scriptsFilePath = getScriptsFilePath();
|
||||
m_scriptLabels = ParseUtil::getGlobalScriptLabels(scriptsFilePath);
|
||||
const QString scriptsFilepath = getScriptsFilepath();
|
||||
m_scriptLabels = ParseUtil::getGlobalScriptLabels(scriptsFilepath);
|
||||
m_scriptsLoaded = true;
|
||||
|
||||
// Track the scripts file for changes. Path may have changed, so stop tracking old files.
|
||||
m_scriptFileWatcher->removePaths(m_scriptFileWatcher->files());
|
||||
m_scriptFileWatcher->addPath(scriptsFilePath);
|
||||
m_scriptFileWatcher->addPath(scriptsFilepath);
|
||||
}
|
||||
|
||||
QStringList scriptLabels = m_scriptLabels;
|
||||
@@ -173,7 +173,7 @@ QStringList Map::getScriptLabels(Event::Group group) {
|
||||
return scriptLabels;
|
||||
}
|
||||
|
||||
QString Map::getScriptsFilePath() const {
|
||||
QString Map::getScriptsFilepath() const {
|
||||
const bool usePoryscript = projectConfig.usePoryScript;
|
||||
auto path = QDir::cleanPath(QString("%1/%2/%3/scripts")
|
||||
.arg(projectConfig.projectDir)
|
||||
@@ -186,6 +186,13 @@ QString Map::getScriptsFilePath() const {
|
||||
return path;
|
||||
}
|
||||
|
||||
QString Map::getJsonFilepath(const QString &mapName) {
|
||||
return QDir::cleanPath(QString("%1/%2/%3/map.json")
|
||||
.arg(projectConfig.projectDir)
|
||||
.arg(projectConfig.getFilePath(ProjectFilePath::data_map_folders))
|
||||
.arg(mapName));
|
||||
}
|
||||
|
||||
void Map::resetEvents() {
|
||||
m_events[Event::Group::Object].clear();
|
||||
m_events[Event::Group::Warp].clear();
|
||||
|
||||
@@ -819,14 +819,26 @@ bool ParseUtil::jsonToBool(const QJsonValue &value, bool * ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int ParseUtil::getScriptLineNumber(const QString &filePath, const QString &scriptLabel) {
|
||||
int ParseUtil::getJsonLineNumber(const QString &filepath, const QString &searchText) {
|
||||
if (searchText.isEmpty())
|
||||
return 0;
|
||||
|
||||
const QString text = readTextFile(filepath);
|
||||
int index = text.indexOf(searchText);
|
||||
if (index < 0)
|
||||
return 0;
|
||||
|
||||
return text.left(index).count('\n') + 1;
|
||||
}
|
||||
|
||||
int ParseUtil::getScriptLineNumber(const QString &filepath, const QString &scriptLabel) {
|
||||
if (scriptLabel.isEmpty())
|
||||
return 0;
|
||||
|
||||
if (filePath.endsWith(".inc") || filePath.endsWith(".s"))
|
||||
return getRawScriptLineNumber(readTextFile(filePath), scriptLabel);
|
||||
else if (filePath.endsWith(".pory"))
|
||||
return getPoryScriptLineNumber(readTextFile(filePath), scriptLabel);
|
||||
if (filepath.endsWith(".inc") || filepath.endsWith(".s"))
|
||||
return getRawScriptLineNumber(readTextFile(filepath), scriptLabel);
|
||||
else if (filepath.endsWith(".pory"))
|
||||
return getPoryScriptLineNumber(readTextFile(filepath), scriptLabel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2272,13 +2272,13 @@ void Editor::deleteSelectedEvents() {
|
||||
}
|
||||
|
||||
void Editor::openMapScripts() const {
|
||||
openInTextEditor(map->getScriptsFilePath());
|
||||
openInTextEditor(map->getScriptsFilepath());
|
||||
}
|
||||
|
||||
void Editor::openScript(const QString &scriptLabel) const {
|
||||
// Find the location of scriptLabel.
|
||||
QStringList scriptPaths(map->getScriptsFilePath());
|
||||
scriptPaths << project->getEventScriptsFilePaths();
|
||||
QStringList scriptPaths(map->getScriptsFilepath());
|
||||
scriptPaths << project->getEventScriptsFilepaths();
|
||||
int lineNum = 0;
|
||||
QString scriptPath = scriptPaths.first();
|
||||
for (const auto &path : scriptPaths) {
|
||||
@@ -2292,6 +2292,16 @@ void Editor::openScript(const QString &scriptLabel) const {
|
||||
openInTextEditor(scriptPath, lineNum);
|
||||
}
|
||||
|
||||
void Editor::openMapJson(const QString &mapName) const {
|
||||
openInTextEditor(Map::getJsonFilepath(mapName));
|
||||
}
|
||||
|
||||
void Editor::openLayoutJson(const QString &layoutId) const {
|
||||
QString path = QDir::cleanPath(QString("%1/%2").arg(projectConfig.projectDir).arg(projectConfig.getFilePath(ProjectFilePath::json_layouts)));
|
||||
QString idField = QString("\"id\": \"%1\",").arg(layoutId);
|
||||
openInTextEditor(path, ParseUtil::getJsonLineNumber(path, idField));
|
||||
}
|
||||
|
||||
void Editor::openInTextEditor(const QString &path, int lineNum) {
|
||||
QString command = porymapConfig.textEditorGotoLine;
|
||||
if (command.isEmpty()) {
|
||||
|
||||
160
src/log.cpp
160
src/log.cpp
@@ -3,6 +3,25 @@
|
||||
#include <QDir>
|
||||
#include <QStandardPaths>
|
||||
#include <QSysInfo>
|
||||
#include <QLabel>
|
||||
#include <QPointer>
|
||||
#include <QTimer>
|
||||
|
||||
namespace Log {
|
||||
static QString mostRecentError;
|
||||
static QString path;
|
||||
static QFile file;
|
||||
static QTextStream textStream;
|
||||
|
||||
struct Display {
|
||||
QPointer<QStatusBar> statusBar;
|
||||
QPointer<QLabel> message;
|
||||
QPointer<QLabel> icon;
|
||||
QSet<LogType> acceptedTypes;
|
||||
};
|
||||
static QList<Display> displays;
|
||||
static QTimer displayClearTimer;
|
||||
};
|
||||
|
||||
// Enabling this does not seem to be simple to color console output
|
||||
// on Windows for all CLIs without external libraries or extreme bloat.
|
||||
@@ -18,22 +37,20 @@
|
||||
#define CLEAR_COLOR "\033[0m"
|
||||
#endif
|
||||
|
||||
void logInfo(QString message) {
|
||||
void logInfo(const QString &message) {
|
||||
log(message, LogType::LOG_INFO);
|
||||
}
|
||||
|
||||
void logWarn(QString message) {
|
||||
void logWarn(const QString &message) {
|
||||
log(message, LogType::LOG_WARN);
|
||||
}
|
||||
|
||||
static QString mostRecentError;
|
||||
|
||||
void logError(QString message) {
|
||||
mostRecentError = message;
|
||||
void logError(const QString &message) {
|
||||
Log::mostRecentError = message;
|
||||
log(message, LogType::LOG_ERROR);
|
||||
}
|
||||
|
||||
QString colorizeMessage(QString message, LogType type) {
|
||||
QString colorizeMessage(const QString &message, LogType type) {
|
||||
QString colorized = message;
|
||||
switch (type)
|
||||
{
|
||||
@@ -50,50 +67,131 @@ QString colorizeMessage(QString message, LogType type) {
|
||||
return colorized;
|
||||
}
|
||||
|
||||
void log(QString message, LogType type) {
|
||||
void addLogStatusBar(QStatusBar *statusBar, const QSet<LogType> &acceptedTypes) {
|
||||
if (!statusBar) return;
|
||||
|
||||
static const QSet<LogType> allTypes = {LOG_ERROR, LOG_WARN, LOG_INFO};
|
||||
|
||||
Log::Display display = {
|
||||
.statusBar = statusBar,
|
||||
.message = new QLabel(statusBar),
|
||||
.icon = new QLabel(statusBar),
|
||||
.acceptedTypes = acceptedTypes.isEmpty() ? allTypes : acceptedTypes,
|
||||
};
|
||||
statusBar->addWidget(display.icon);
|
||||
statusBar->addWidget(display.message);
|
||||
Log::displays.append(display);
|
||||
}
|
||||
|
||||
void removeLogStatusBar(int index) {
|
||||
Log::Display display = Log::displays.takeAt(index);
|
||||
display.statusBar->removeWidget(display.icon);
|
||||
display.statusBar->removeWidget(display.message);
|
||||
delete display.icon;
|
||||
delete display.message;
|
||||
}
|
||||
|
||||
bool removeLogStatusBar(QStatusBar *statusBar) {
|
||||
if (!statusBar) return false;
|
||||
|
||||
for (int i = 0; i < Log::displays.length(); i++) {
|
||||
if (Log::displays.at(i).statusBar == statusBar) {
|
||||
removeLogStatusBar(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void updateLogDisplays(const QString &message, LogType type) {
|
||||
static const QMap<LogType, QPixmap> icons = {
|
||||
{LogType::LOG_INFO, QPixmap(QStringLiteral(":/icons/information.ico"))},
|
||||
{LogType::LOG_WARN, QPixmap(QStringLiteral(":/icons/warning.ico"))},
|
||||
{LogType::LOG_ERROR, QPixmap(QStringLiteral(":/icons/error.ico"))},
|
||||
};
|
||||
|
||||
bool startTimer = false;
|
||||
auto it = QMutableListIterator(Log::displays);
|
||||
while (it.hasNext()) {
|
||||
auto display = it.next();
|
||||
if (!display.statusBar) {
|
||||
// Status bar was deleted externally, remove entry from the list.
|
||||
it.remove();
|
||||
continue;
|
||||
}
|
||||
// Update the display, but only if it accepts this message type.
|
||||
if (display.acceptedTypes.contains(type)) {
|
||||
display.icon->setPixmap(icons.value(type));
|
||||
display.statusBar->clearMessage();
|
||||
display.message->setText(message);
|
||||
startTimer = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-hide status bar messages after a set period of time
|
||||
if (startTimer) Log::displayClearTimer.start(5000);
|
||||
}
|
||||
|
||||
void clearLogDisplays() {
|
||||
for (const auto &display : Log::displays) {
|
||||
display.icon->setPixmap(QPixmap());
|
||||
display.message->setText(QString());
|
||||
}
|
||||
}
|
||||
|
||||
void log(const QString &message, LogType type) {
|
||||
QString now = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
|
||||
QString typeString = "";
|
||||
switch (type)
|
||||
{
|
||||
case LogType::LOG_INFO:
|
||||
typeString = " [INFO]";
|
||||
typeString = QStringLiteral(" [INFO]");
|
||||
break;
|
||||
case LogType::LOG_WARN:
|
||||
typeString = " [WARN]";
|
||||
typeString = QStringLiteral(" [WARN]");
|
||||
break;
|
||||
case LogType::LOG_ERROR:
|
||||
typeString = "[ERROR]";
|
||||
typeString = QStringLiteral("[ERROR]");
|
||||
break;
|
||||
}
|
||||
|
||||
message = QString("%1 %2 %3").arg(now).arg(typeString).arg(message);
|
||||
updateLogDisplays(message, type);
|
||||
|
||||
qDebug().noquote() << colorizeMessage(message, type);
|
||||
QFile outFile(getLogPath());
|
||||
outFile.open(QIODevice::WriteOnly | QIODevice::Append);
|
||||
QTextStream ts(&outFile);
|
||||
ts << message << Qt::endl;
|
||||
QString fullMessage = QString("%1 %2 %3").arg(now).arg(typeString).arg(message);
|
||||
|
||||
qDebug().noquote() << colorizeMessage(fullMessage, type);
|
||||
|
||||
Log::textStream << fullMessage << Qt::endl;
|
||||
Log::file.flush();
|
||||
}
|
||||
|
||||
QString getLogPath() {
|
||||
return Log::path;
|
||||
}
|
||||
|
||||
QString getMostRecentError() {
|
||||
return Log::mostRecentError;
|
||||
}
|
||||
|
||||
bool cleanupLargeLog() {
|
||||
return Log::file.size() >= 20000000 && Log::file.resize(0);
|
||||
}
|
||||
|
||||
void logInit() {
|
||||
QString settingsPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||
QDir dir(settingsPath);
|
||||
if (!dir.exists())
|
||||
dir.mkpath(settingsPath);
|
||||
return dir.absoluteFilePath("porymap.log");
|
||||
}
|
||||
Log::path = dir.absoluteFilePath(QStringLiteral("porymap.log"));
|
||||
Log::file.setFileName(Log::path);
|
||||
Log::file.open(QIODevice::WriteOnly | QIODevice::Append);
|
||||
Log::textStream.setDevice(&Log::file);
|
||||
|
||||
QString getMostRecentError() {
|
||||
return mostRecentError;
|
||||
}
|
||||
QObject::connect(&Log::displayClearTimer, &QTimer::timeout, [=] {
|
||||
clearLogDisplays();
|
||||
});
|
||||
|
||||
bool cleanupLargeLog() {
|
||||
QFile logFile(getLogPath());
|
||||
if (logFile.size() < 20000000)
|
||||
return false;
|
||||
|
||||
bool removed = logFile.remove();
|
||||
if (removed)
|
||||
logWarn(QString("Previous log file %1 was cleared due to being over 20MB in size.").arg(getLogPath()));
|
||||
return removed;
|
||||
if (cleanupLargeLog()) {
|
||||
logWarn(QString("Previous log file %1 was cleared due to being over 20MB in size.").arg(Log::path));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
|
||||
ui->setupUi(this);
|
||||
|
||||
cleanupLargeLog();
|
||||
logInit();
|
||||
logInfo(QString("Launching Porymap v%1").arg(QCoreApplication::applicationVersion()));
|
||||
}
|
||||
|
||||
@@ -142,6 +142,7 @@ void MainWindow::setWindowDisabled(bool disabled) {
|
||||
|
||||
void MainWindow::initWindow() {
|
||||
porymapConfig.load();
|
||||
this->initLogStatusBar();
|
||||
this->initCustomUI();
|
||||
this->initExtraSignals();
|
||||
this->initEditor();
|
||||
@@ -237,6 +238,14 @@ void MainWindow::applyUserShortcuts() {
|
||||
shortcut->setKeys(shortcutsConfig.userShortcuts(shortcut));
|
||||
}
|
||||
|
||||
void MainWindow::initLogStatusBar() {
|
||||
removeLogStatusBar(this->statusBar());
|
||||
QSet logTypes = QSet(porymapConfig.statusBarLogTypes.begin(), porymapConfig.statusBarLogTypes.end());
|
||||
if (!logTypes.isEmpty()) {
|
||||
addLogStatusBar(this->statusBar(), logTypes);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::initCustomUI() {
|
||||
static const QMap<int, QString> mainTabNames = {
|
||||
{MainTab::Map, "Map"},
|
||||
@@ -489,6 +498,10 @@ void MainWindow::initMapList() {
|
||||
ui->mapListToolBar_Locations->setEditsAllowedButtonVisible(false);
|
||||
ui->mapListToolBar_Layouts->setEditsAllowedButtonVisible(false);
|
||||
|
||||
// When searching the Layouts list, don't expand to show all the maps. If the user is searching
|
||||
// this list then they're probably more interested in the layouts than the maps.
|
||||
ui->mapListToolBar_Layouts->setExpandListForSearch(false);
|
||||
|
||||
// Initialize settings from config
|
||||
ui->mapListToolBar_Groups->setEditsAllowed(porymapConfig.mapListEditGroupsEnabled);
|
||||
for (auto i = porymapConfig.mapListHideEmptyEnabled.constBegin(); i != porymapConfig.mapListHideEmptyEnabled.constEnd(); i++) {
|
||||
@@ -627,13 +640,32 @@ void MainWindow::loadUserSettings() {
|
||||
}
|
||||
|
||||
void MainWindow::restoreWindowState() {
|
||||
logInfo("Restoring main window geometry from previous session.");
|
||||
QMap<QString, QByteArray> geometry = porymapConfig.getMainGeometry();
|
||||
this->restoreGeometry(geometry.value("main_window_geometry"));
|
||||
this->restoreState(geometry.value("main_window_state"));
|
||||
this->ui->splitter_map->restoreState(geometry.value("map_splitter_state"));
|
||||
this->ui->splitter_main->restoreState(geometry.value("main_splitter_state"));
|
||||
this->ui->splitter_Metatiles->restoreState(geometry.value("metatiles_splitter_state"));
|
||||
const QByteArray mainWindowGeometry = geometry.value("main_window_geometry");
|
||||
if (!mainWindowGeometry.isEmpty()) {
|
||||
logInfo("Restoring main window geometry from previous session.");
|
||||
restoreGeometry(mainWindowGeometry);
|
||||
restoreState(geometry.value("main_window_state"));
|
||||
ui->splitter_map->restoreState(geometry.value("map_splitter_state"));
|
||||
ui->splitter_main->restoreState(geometry.value("main_splitter_state"));
|
||||
ui->splitter_Metatiles->restoreState(geometry.value("metatiles_splitter_state"));
|
||||
}
|
||||
|
||||
// Resize the window if it exceeds the available screen size.
|
||||
auto screen = windowHandle() ? windowHandle()->screen() : QGuiApplication::primaryScreen();
|
||||
if (!screen) return;
|
||||
const QRect screenGeometry = screen->availableGeometry();
|
||||
if (this->width() > screenGeometry.width() || this->height() > screenGeometry.height()) {
|
||||
auto pixelRatio = screen->devicePixelRatio();
|
||||
logInfo(QString("Resizing main window. Dimensions of %1x%2 exceed available screen size of %3x%4")
|
||||
.arg(qRound(this->width() * pixelRatio))
|
||||
.arg(qRound(this->height() * pixelRatio))
|
||||
.arg(qRound(screenGeometry.width() * pixelRatio))
|
||||
.arg(qRound(screenGeometry.height() * pixelRatio)));
|
||||
resize(qMin(this->width(), screenGeometry.width()),
|
||||
qMin(this->height(), screenGeometry.height()));
|
||||
move(screenGeometry.center() - this->rect().center());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::setTheme(QString theme) {
|
||||
@@ -662,7 +694,6 @@ bool MainWindow::openProject(QString dir, bool initial) {
|
||||
|
||||
if (!QDir(dir).exists()) {
|
||||
const QString errorMsg = QString("Failed to open %1: No such directory").arg(projectString);
|
||||
this->statusBar()->showMessage(errorMsg);
|
||||
if (initial) {
|
||||
// Graceful startup if recent project directory is missing
|
||||
logWarn(errorMsg);
|
||||
@@ -681,7 +712,6 @@ bool MainWindow::openProject(QString dir, bool initial) {
|
||||
}
|
||||
|
||||
const QString openMessage = QString("Opening %1").arg(projectString);
|
||||
this->statusBar()->showMessage(openMessage);
|
||||
logInfo(openMessage);
|
||||
|
||||
porysplash->start();
|
||||
@@ -718,7 +748,6 @@ bool MainWindow::openProject(QString dir, bool initial) {
|
||||
|
||||
// Load the project
|
||||
if (!(loadProjectData() && setProjectUI() && setInitialMap())) {
|
||||
this->statusBar()->showMessage(QString("Failed to open %1").arg(projectString));
|
||||
showProjectOpenFailure();
|
||||
delete this->editor->project;
|
||||
// TODO: Allow changing project settings at this point
|
||||
@@ -730,7 +759,6 @@ bool MainWindow::openProject(QString dir, bool initial) {
|
||||
this->editor->project->saveConfig();
|
||||
|
||||
updateWindowTitle();
|
||||
this->statusBar()->showMessage(QString("Opened %1").arg(projectString));
|
||||
|
||||
porymapConfig.projectManuallyClosed = false;
|
||||
porymapConfig.addRecentProject(dir);
|
||||
@@ -1104,12 +1132,20 @@ bool MainWindow::setMap(const QString &mapName) {
|
||||
// When editing in layout-only mode they are disabled.
|
||||
void MainWindow::setLayoutOnlyMode(bool layoutOnly) {
|
||||
bool mapEditingEnabled = !layoutOnly;
|
||||
this->ui->mainTabBar->setTabEnabled(MainTab::Events, mapEditingEnabled);
|
||||
this->ui->mainTabBar->setTabEnabled(MainTab::Header, mapEditingEnabled);
|
||||
this->ui->mainTabBar->setTabEnabled(MainTab::Connections, mapEditingEnabled);
|
||||
this->ui->mainTabBar->setTabEnabled(MainTab::WildPokemon, mapEditingEnabled && editor->project->wildEncountersLoaded);
|
||||
ui->mainTabBar->setTabEnabled(MainTab::Events, mapEditingEnabled);
|
||||
ui->mainTabBar->setTabEnabled(MainTab::Header, mapEditingEnabled);
|
||||
ui->mainTabBar->setTabEnabled(MainTab::Connections, mapEditingEnabled);
|
||||
ui->mainTabBar->setTabEnabled(MainTab::WildPokemon, mapEditingEnabled && this->editor->project->wildEncountersLoaded);
|
||||
|
||||
this->ui->comboBox_LayoutSelector->setEnabled(mapEditingEnabled);
|
||||
// Set a tool tip to explain why the tabs are disabled.
|
||||
static const QString disabledToolTip = Util::toHtmlParagraph("You are in layout-only mode. This tab is only enabled when a map is open.");
|
||||
QString toolTip = mapEditingEnabled ? QString() : disabledToolTip;
|
||||
ui->mainTabBar->setTabToolTip(MainTab::Events, toolTip);
|
||||
ui->mainTabBar->setTabToolTip(MainTab::Header, toolTip);
|
||||
ui->mainTabBar->setTabToolTip(MainTab::Connections, toolTip);
|
||||
ui->mainTabBar->setTabToolTip(MainTab::WildPokemon, this->editor->project->wildEncountersLoaded ? toolTip : QString());
|
||||
|
||||
ui->comboBox_LayoutSelector->setEnabled(mapEditingEnabled);
|
||||
}
|
||||
|
||||
// setLayout, but with a visible error message in case of failure.
|
||||
@@ -1480,6 +1516,9 @@ void MainWindow::onOpenMapListContextMenu(const QPoint &point) {
|
||||
if (itemType == "map_name") {
|
||||
// Right-clicking on a map.
|
||||
openItemAction = menu.addAction("Open Map");
|
||||
connect(menu.addAction("Open JSON file"), &QAction::triggered, [this, itemName] {
|
||||
this->editor->openMapJson(itemName);
|
||||
});
|
||||
menu.addSeparator();
|
||||
copyListNameAction = menu.addAction("Copy Map Name");
|
||||
copyToolTipAction = menu.addAction("Copy Map ID");
|
||||
@@ -1507,6 +1546,9 @@ void MainWindow::onOpenMapListContextMenu(const QPoint &point) {
|
||||
} else if (itemType == "map_layout") {
|
||||
// Right-clicking on a map layout
|
||||
openItemAction = menu.addAction("Open Layout");
|
||||
connect(menu.addAction("Open JSON file"), &QAction::triggered, [this, itemName] {
|
||||
this->editor->openLayoutJson(itemName);
|
||||
});
|
||||
menu.addSeparator();
|
||||
copyListNameAction = menu.addAction("Copy Layout Name");
|
||||
copyToolTipAction = menu.addAction("Copy Layout ID");
|
||||
@@ -3006,6 +3048,7 @@ void MainWindow::on_actionPreferences_triggered() {
|
||||
connect(preferenceEditor, &PreferenceEditor::themeChanged, this, &MainWindow::setTheme);
|
||||
connect(preferenceEditor, &PreferenceEditor::themeChanged, editor, &Editor::maskNonVisibleConnectionTiles);
|
||||
connect(preferenceEditor, &PreferenceEditor::preferencesSaved, this, &MainWindow::togglePreferenceSpecificUi);
|
||||
connect(preferenceEditor, &PreferenceEditor::preferencesSaved, this, &MainWindow::initLogStatusBar);
|
||||
// Changes to porymapConfig.loadAllEventScripts or porymapConfig.eventSelectionShapeMode
|
||||
// require us to repopulate the EventFrames and redraw event pixmaps, respectively.
|
||||
connect(preferenceEditor, &PreferenceEditor::preferencesSaved, editor, &Editor::updateEvents);
|
||||
|
||||
@@ -367,7 +367,7 @@ QSet<QString> Project::getTopLevelMapFields() const {
|
||||
}
|
||||
|
||||
QJsonDocument Project::readMapJson(const QString &mapName, QString *error) {
|
||||
const QString mapFilepath = QString("%1%2/map.json").arg(projectConfig.getFilePath(ProjectFilePath::data_map_folders)).arg(mapName);
|
||||
const QString mapFilepath = Map::getJsonFilepath(mapName);
|
||||
watchFile(mapFilepath);
|
||||
|
||||
QJsonDocument doc;
|
||||
@@ -744,7 +744,11 @@ bool Project::saveMapLayouts() {
|
||||
}
|
||||
|
||||
void Project::watchFile(const QString &filename) {
|
||||
this->fileWatcher.addPath(QString("%1/%2").arg(this->root).arg(filename));
|
||||
if (!filename.startsWith(this->root)) {
|
||||
this->fileWatcher.addPath(QString("%1/%2").arg(this->root).arg(filename));
|
||||
} else {
|
||||
this->fileWatcher.addPath(filename);
|
||||
}
|
||||
}
|
||||
|
||||
void Project::watchFiles(const QStringList &filenames) {
|
||||
@@ -1234,7 +1238,7 @@ bool Project::saveMap(Map *map, bool skipLayout) {
|
||||
}
|
||||
|
||||
// Create map.json for map data.
|
||||
QString mapFilepath = fullPath + "/map.json";
|
||||
QString mapFilepath = map->getJsonFilepath();
|
||||
QFile mapFile(mapFilepath);
|
||||
if (!mapFile.open(QIODevice::WriteOnly)) {
|
||||
logError(QString("Could not open '%1' for writing: %2").arg(mapFilepath).arg(mapFile.errorString()));
|
||||
@@ -2885,7 +2889,7 @@ bool Project::readEventScriptLabels() {
|
||||
this->globalScriptLabels.clear();
|
||||
|
||||
if (porymapConfig.loadAllEventScripts) {
|
||||
for (const auto &filePath : getEventScriptsFilePaths())
|
||||
for (const auto &filePath : getEventScriptsFilepaths())
|
||||
this->globalScriptLabels << ParseUtil::getGlobalScriptLabels(filePath);
|
||||
|
||||
this->globalScriptLabels.sort(Qt::CaseInsensitive);
|
||||
@@ -2928,7 +2932,7 @@ QString Project::getScriptDefaultString(bool usePoryScript, QString mapName) con
|
||||
return QString("%1_MapScripts::\n\t.byte 0\n").arg(mapName);
|
||||
}
|
||||
|
||||
QStringList Project::getEventScriptsFilePaths() const {
|
||||
QStringList Project::getEventScriptsFilepaths() const {
|
||||
QStringList filePaths(QDir::cleanPath(root + "/" + projectConfig.getFilePath(ProjectFilePath::data_event_scripts)));
|
||||
const QString scriptsDir = QDir::cleanPath(root + "/" + projectConfig.getFilePath(ProjectFilePath::data_scripts_folders));
|
||||
const QString mapsDir = QDir::cleanPath(root + "/" + projectConfig.getFilePath(ProjectFilePath::data_map_folders));
|
||||
|
||||
@@ -43,11 +43,11 @@ ColorPicker::~ColorPicker()
|
||||
void ColorPicker::hover(const QPoint &pos) {
|
||||
QScreen *screen = QGuiApplication::screenAt(pos);
|
||||
if (!screen) {
|
||||
// Try the screen the color picker is on, or the primary screen.
|
||||
const QWindow *window = windowHandle();
|
||||
if (window) screen = window->screen();
|
||||
screen = (window && window->screen()) ? window->screen() : QGuiApplication::primaryScreen();
|
||||
if (!screen) return;
|
||||
}
|
||||
if (!screen)
|
||||
return;
|
||||
|
||||
// 15 X 15 box with 8x magnification = 120px square)
|
||||
QPixmap grab = screen->grabWindow(0, pos.x() - zoom_box_dimensions / 2, pos.y() - zoom_box_dimensions / 2, zoom_box_dimensions, zoom_box_dimensions);
|
||||
|
||||
@@ -138,7 +138,7 @@ void MapListToolBar::applyFilter(const QString &filterText) {
|
||||
if (filterText.isEmpty()) {
|
||||
m_list->collapseAll();
|
||||
emit filterCleared(m_list);
|
||||
} else {
|
||||
} else if (m_expandListForSearch) {
|
||||
m_list->expandToDepth(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,11 @@ void PreferenceEditor::updateFields() {
|
||||
ui->checkBox_CheckForUpdates->setChecked(porymapConfig.checkForUpdates);
|
||||
ui->checkBox_DisableEventWarning->setChecked(porymapConfig.eventDeleteWarningDisabled);
|
||||
ui->checkBox_AutocompleteAllScripts->setChecked(porymapConfig.loadAllEventScripts);
|
||||
|
||||
auto logTypeEnd = porymapConfig.statusBarLogTypes.end();
|
||||
ui->checkBox_StatusErrors->setChecked(porymapConfig.statusBarLogTypes.find(LogType::LOG_ERROR) != logTypeEnd);
|
||||
ui->checkBox_StatusWarnings->setChecked(porymapConfig.statusBarLogTypes.find(LogType::LOG_WARN) != logTypeEnd);
|
||||
ui->checkBox_StatusInformation->setChecked(porymapConfig.statusBarLogTypes.find(LogType::LOG_INFO) != logTypeEnd);
|
||||
}
|
||||
|
||||
void PreferenceEditor::saveFields() {
|
||||
@@ -77,6 +82,12 @@ void PreferenceEditor::saveFields() {
|
||||
porymapConfig.reopenOnLaunch = ui->checkBox_OpenRecentProject->isChecked();
|
||||
porymapConfig.checkForUpdates = ui->checkBox_CheckForUpdates->isChecked();
|
||||
porymapConfig.eventDeleteWarningDisabled = ui->checkBox_DisableEventWarning->isChecked();
|
||||
|
||||
porymapConfig.statusBarLogTypes.clear();
|
||||
if (ui->checkBox_StatusErrors->isChecked()) porymapConfig.statusBarLogTypes.insert(LogType::LOG_ERROR);
|
||||
if (ui->checkBox_StatusWarnings->isChecked()) porymapConfig.statusBarLogTypes.insert(LogType::LOG_WARN);
|
||||
if (ui->checkBox_StatusInformation->isChecked()) porymapConfig.statusBarLogTypes.insert(LogType::LOG_INFO);
|
||||
|
||||
porymapConfig.save();
|
||||
|
||||
emit preferencesSaved();
|
||||
|
||||
Reference in New Issue
Block a user