mirror of
https://github.com/huderlem/porymap.git
synced 2026-03-21 17:45:44 -05:00
Merge branch 'dev' of https://github.com/huderlem/porymap
This commit is contained in:
commit
7a2e4bb51e
53
CHANGELOG.md
53
CHANGELOG.md
|
|
@ -5,7 +5,58 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|||
and this project somewhat adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). The MAJOR version number is bumped when there are **"Breaking Changes"** in the pret projects. For more on this, see [the manual page on breaking changes](https://huderlem.github.io/porymap/manual/breaking-changes.html).
|
||||
|
||||
## [Unreleased]
|
||||
Nothing, yet.
|
||||
### Added
|
||||
- Add `View > Show Unused Colors` to the Palette Editor.
|
||||
- Add `Tools > Find Color Usage` to the Palette Editor. This opens a dialog showing which metatiles use a particular color.
|
||||
- Add `Edit > Swap Metatiles` to the Tileset Editor. While in this mode, selecting two metatiles in the selector will swap their positions. When changes to the tilesets are saved these relocations will be applied to all layouts that use the relevant tileset(s).
|
||||
- Add `View > Layer Arrangement` to the Tileset Editor, which changes whether the metatile layer view is oriented vertically (default) or horizontally.
|
||||
- Add an `Export Metatiles Image` option to the Tileset Editor that provides many more options for customizing metatile images.
|
||||
- Add an `Export Porytiles Layer Images` option to the Tileset Editor, which is a shortcut for individually exporting layer images that Porytiles can use.
|
||||
- Add an option under `Preferences` to include common scripts in the autocomplete for Script labels.
|
||||
- Add a setting under `Project Settings` to change the width of the metatile selectors.
|
||||
- Add versions of the API functions `[get|set]MetatileLayerOrder` and `[get|set]MetatileLayerOpacity` that work globally, rather than on individual layouts.
|
||||
- A link to Porymap's manual is now available under `Help`.
|
||||
|
||||
### Changed
|
||||
- The Player View Rectangle is now visible on the Events tab, as is the Cursor Tile Outline for certain tools.
|
||||
- When hovering over tiles in the Tileset Editor their palette and x/yflip are now listed alongside the tile ID.
|
||||
- The scroll position of the map view now remains the same between the Connections tab and the Map/Events tabs.
|
||||
- The Move tool now behaves more like a traditional pan tool (with no momentum).
|
||||
- The map image exporter now uses a checkered background to indicate transparency.
|
||||
- Invalid tile IDs are now rendered as magenta (like invalid metatiles), instead of rendering the same as a transparent tile.
|
||||
- While holding down `Ctrl` (`Cmd` on macOS) painting on the metatile layer view will now only change the tile's palette.
|
||||
- Full menu paths are now listed for shortcuts in the Shortcuts Editor.
|
||||
- Adding new event data to a map that has a `shared_events_map` will now remove the `shared_events_map`, rather than discard the event data.
|
||||
|
||||
### Fixed
|
||||
- Fix crash when rendering tiles with invalid palette numbers.
|
||||
- Fix crash when opening the Tileset Editor for tilesets with no metatiles.
|
||||
- Fix crash when changing the map/border size in certain API callbacks.
|
||||
- Fix metatile images exporting at 2x scale.
|
||||
- Fix display errors when a project's metatile limits are not divisible by 8.
|
||||
- Fix incorrect dividing line position for primary tiles images that are smaller than the maximum size.
|
||||
- Fix the checkered background of the `Change Dimensions` popup shifting while scrolling around.
|
||||
- Fix pasting Wild Pokémon data then changing maps resetting the pasted data.
|
||||
- Fix click-drag map selections behaving unexpectedly when the cursor is outside the map grid.
|
||||
- Fix events being dragged in negative coordinates lagging behind the cursor.
|
||||
- Fix the shortcut for duplicating events working while on the Connections tab.
|
||||
- Fix the Shortcuts Editor displaying the duplicate shortcut prompt repeatedly.
|
||||
- Fix the clear text button on the left in each row of the Shortcuts Editor also clearing the shortcut on the right.
|
||||
- Fix Undo/Redo ignoring the automatic resizing that occurs if a layout/border was an unexpected size.
|
||||
- Fix Undo/Redo in the Tileset and Palette Editors and Paste in the Tileset Editor appearing enabled even when they don't do anything.
|
||||
- Fix `Ctrl+Shift+Z` not being set as a default shortcut for Redo in the Palette Editor like it is for other windows.
|
||||
- Fix the Tileset Editor's status bar not updating while selecting tiles in the metatile layer view, or when pasting metatiles.
|
||||
- Fix the main window's status bar not immediately reflecting changes made while painting metatiles / movement permissions.
|
||||
- Fix cleared metatile labels not updating until the project is reloaded.
|
||||
- Fix some changes in the Tileset Editor being discarded if the window is closed too quickly.
|
||||
- Fix the Region Map Editor incorrectly displaying whether a `MAPSEC` has region map data.
|
||||
- Fix the Primary/Secondary Tileset selectors allowing invalid text, and considering a map unsaved if changed to invalid text then back again.
|
||||
- Fix broken error message for the primary tileset on the new map/layout dialogs.
|
||||
- Fix the dialog for duplicating/importing a map layout not allowing the tilesets to be changed.
|
||||
- Fix warning not appearing when the log file exceeds maximum size.
|
||||
- Fix possible lag while using the Tileset Editor's tile selector.
|
||||
- Fix unnecessary resources being used to watch files.
|
||||
- Fix possible crash on Linux if too many inotify instances are requested.
|
||||
|
||||
## [6.1.0] - 2025-06-09
|
||||
### Added
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ Porymap is extensible via scripting capabilities. This allows the user to write
|
|||
- Procedurally Generated Maps
|
||||
- Randomize Grass Patterns
|
||||
|
||||
.. note::
|
||||
If you are compiling Porymap yourself, these features will only be available if Qt's ``qml`` module is installed.
|
||||
|
||||
|
||||
Custom Scripts Editor
|
||||
---------------------
|
||||
|
|
@ -1222,6 +1225,58 @@ All tileset functions are callable via the global ``map`` object.
|
|||
:returns: the pixel data
|
||||
:rtype: array
|
||||
|
||||
.. |describe-metatile-layer-order|
|
||||
replace:: where ``0`` is the bottom layer, ``1`` is the middle layer, and ``2`` is the top layer. The default order is ``[0, 1, 2]``
|
||||
|
||||
.. |describe-metatile-layer-order-handling|
|
||||
replace:: If no elements are provided the layer order will be reset to the default. Any layer not listed in the provided ``order`` will not be rendered. Any additional elements after the first 3 are ignored
|
||||
|
||||
.. js:function:: map.getMetatileLayerOrder()
|
||||
|
||||
Gets the order that metatile layers are rendered for the current layout, |describe-metatile-layer-order|.
|
||||
|
||||
If you'd like to get the default metatile layer order for all layouts, see :js:func:`utility.getMetatileLayerOrder` instead.
|
||||
|
||||
:returns: array of layers
|
||||
:rtype: array
|
||||
|
||||
.. js:function:: map.setMetatileLayerOrder(order)
|
||||
|
||||
Sets the order that metatile layers are rendered for the current layout, |describe-metatile-layer-order|.
|
||||
|
||||
|describe-metatile-layer-order-handling|.
|
||||
|
||||
If you'd like to set the default metatile layer order for all layouts, see :js:func:`utility.setMetatileLayerOrder` instead.
|
||||
|
||||
:param order: array of layers
|
||||
:type order: array
|
||||
|
||||
.. |describe-metatile-layer-opacity|
|
||||
replace:: where the first element is the bottom layer, the second element is the middle layer, and the third element is the top layer. The default opacities are ``[1.0, 1.0, 1.0]``
|
||||
|
||||
.. |describe-metatile-layer-opacity-handling|
|
||||
replace:: Any additional elements after the first 3 are ignored. Any elements not provided will be rendered with opacity ``1.0``
|
||||
|
||||
.. js:function:: map.getMetatileLayerOpacity()
|
||||
|
||||
Gets the opacities that metatile layers are rendered with for the current layout, |describe-metatile-layer-opacity|.
|
||||
|
||||
If you'd like to get the default metatile layer opacities for all layouts, see :js:func:`utility.getMetatileLayerOpacity` instead.
|
||||
|
||||
:returns: array of opacities for each layer
|
||||
:rtype: array
|
||||
|
||||
.. js:function:: map.setMetatileLayerOpacity(opacities)
|
||||
|
||||
Sets the opacities that metatile layers are rendered with for the current layout, |describe-metatile-layer-opacity|.
|
||||
|
||||
|describe-metatile-layer-opacity-handling|.
|
||||
|
||||
If you'd like to set the default metatile layer opacities for all layouts, see :js:func:`utility.setMetatileLayerOpacity` instead.
|
||||
|
||||
:param opacities: array of opacities for each layer
|
||||
:type opacities: array
|
||||
|
||||
Overlay Functions
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
|
@ -1811,30 +1866,42 @@ All settings functions are callable via the global ``utility`` object.
|
|||
|
||||
.. js:function:: utility.getMetatileLayerOrder()
|
||||
|
||||
Gets the order that metatile layers are rendered.
|
||||
Gets the order that metatile layers are rendered by default, |describe-metatile-layer-order|.
|
||||
|
||||
:returns: array of layers. The bottom layer is represented as 0.
|
||||
If you'd like to get the metatile layer order for only the current layout, see :js:func:`map.getMetatileLayerOrder` instead.
|
||||
|
||||
:returns: array of layers
|
||||
:rtype: array
|
||||
|
||||
.. js:function:: utility.setMetatileLayerOrder(order)
|
||||
|
||||
Sets the order that metatile layers are rendered.
|
||||
Sets the order that metatile layers are rendered by default, |describe-metatile-layer-order|.
|
||||
|
||||
:param order: array of layers. The bottom layer is represented as 0.
|
||||
|describe-metatile-layer-order-handling|.
|
||||
|
||||
If you'd like to set the metatile layer order for only the current layout, see :js:func:`map.setMetatileLayerOrder` instead.
|
||||
|
||||
:param order: array of layers
|
||||
:type order: array
|
||||
|
||||
.. js:function:: utility.getMetatileLayerOpacity()
|
||||
|
||||
Gets the opacities that metatile layers are rendered with.
|
||||
Gets the opacities that metatile layers are rendered with by default, |describe-metatile-layer-opacity|.
|
||||
|
||||
:returns: array of opacities for each layer. The bottom layer is the first element.
|
||||
If you'd like to get the metatile layer opacities for only the current layout, see :js:func:`map.getMetatileLayerOpacity` instead.
|
||||
|
||||
:returns: array of opacities for each layer
|
||||
:rtype: array
|
||||
|
||||
.. js:function:: utility.setMetatileLayerOpacity(opacities)
|
||||
|
||||
Sets the opacities that metatile layers are rendered with.
|
||||
Sets the opacities that metatile layers are rendered with by default, |describe-metatile-layer-opacity|.
|
||||
|
||||
:param opacities: array of opacities for each layer. The bottom layer is the first element.
|
||||
|describe-metatile-layer-opacity-handling|.
|
||||
|
||||
If you'd like to set the metatile layer opacities for only the current layout, see :js:func:`map.setMetatileLayerOpacity` instead.
|
||||
|
||||
:param opacities: array of opacities for each layer
|
||||
:type opacities: array
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1638,9 +1638,6 @@
|
|||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_NoEvents">
|
||||
<property name="text">
|
||||
<string>There are no events on the current map.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
|
|
@ -2926,6 +2923,7 @@
|
|||
<string>Help</string>
|
||||
</property>
|
||||
<addaction name="actionAbout_Porymap"/>
|
||||
<addaction name="actionOpen_Manual"/>
|
||||
<addaction name="actionOpen_Log_File"/>
|
||||
<addaction name="actionOpen_Config_Folder"/>
|
||||
<addaction name="actionCheck_for_Updates"/>
|
||||
|
|
@ -3267,6 +3265,11 @@
|
|||
<string>Alt+Right</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionOpen_Manual">
|
||||
<property name="text">
|
||||
<string>Open Manual</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
|
|
|
|||
526
forms/metatileimageexporter.ui
Normal file
526
forms/metatileimageexporter.ui
Normal file
|
|
@ -0,0 +1,526 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MetatileImageExporter</class>
|
||||
<widget class="QDialog" name="MetatileImageExporter">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>649</width>
|
||||
<height>601</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Export Metatiles Image</string>
|
||||
</property>
|
||||
<property name="sizeGripEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="0" column="1">
|
||||
<widget class="QFrame" name="frame_Options">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::FocusPolicy::ClickFocus</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_Options">
|
||||
<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>
|
||||
<widget class="QScrollArea" name="scrollArea_Options">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents_Options">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>304</width>
|
||||
<height>532</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<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>
|
||||
<widget class="QGroupBox" name="groupBox_Tilesets">
|
||||
<property name="title">
|
||||
<string>Tilesets</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_SecondaryTileset">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>If checked, automatically update the metatile range to include the full secondary tileset.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Secondary Tileset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="NoScrollComboBox" name="comboBox_PrimaryTileset">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="NoScrollComboBox" name="comboBox_SecondaryTileset">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_PrimaryTileset">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>If checked, automatically update the metatile range to include the full primary tileset.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Primary Tileset</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>1</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_MetatileRange">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Metatile Range</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_MetatileStart">
|
||||
<property name="text">
|
||||
<string>Start</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="UIntHexSpinBox" name="spinBox_MetatileStart">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The metatile ID to start the rendered image at.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_MetatileEnd">
|
||||
<property name="text">
|
||||
<string>End</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="UIntHexSpinBox" name="spinBox_MetatileEnd">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The metatile ID to end the rendered image at.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_Layers">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Each metatile consists of 3 layers of tiles. These layers can be toggled here by clicking the checkbox, or rearranged by clicking and dragging them up or down in the list.</p></body></html></string>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Layers</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<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>
|
||||
<widget class="ReorderableListWidget" name="listWidget_Layers">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarPolicy::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarPolicy::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::SizeAdjustPolicy::AdjustToContentsOnFirstShow</enum>
|
||||
</property>
|
||||
<property name="dragEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DragDropMode::InternalMove</enum>
|
||||
</property>
|
||||
<property name="defaultDropAction">
|
||||
<enum>Qt::DropAction::MoveAction</enum>
|
||||
</property>
|
||||
<property name="resizeMode">
|
||||
<enum>QListView::ResizeMode::Adjust</enum>
|
||||
</property>
|
||||
<property name="itemAlignment">
|
||||
<set>Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_Transparency">
|
||||
<property name="title">
|
||||
<string>Transparency</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioButton_TransparencyNormal">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>If checked, transparent pixels in the image will be rendered with alpha of 0.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Normal</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioButton_TransparencyBlack">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>If checked, transparent pixels in the image will be rendered as black. This is the default in-game behavior.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Black</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioButton_TransparencyFirst">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>If checked, transparent pixels in the image will be rendered using the first color in tileset palette 0. This is the default behavior of the GBA.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>First palette color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_Misc">
|
||||
<property name="title">
|
||||
<string>Miscellaneous</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="checkBox_Placeholders">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>If checked, display the placeholder tiles that are rendered for the unused layer in-game. For a given metatile only 2 of the 3 tile layers are used, and the 3rd layer is filled with these placeholder tiles. The unused layer and placeholder tile change depending on the metatile's layer type.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Render placeholder metatiles</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_WidthMetatiles">
|
||||
<property name="text">
|
||||
<string>Width (metatiles)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="UIntSpinBox" name="spinBox_WidthMetatiles">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Width of the output image in metatiles.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_WidthPixels">
|
||||
<property name="text">
|
||||
<string>Width (pixels)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="UIntSpinBox" name="spinBox_WidthPixels">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Width of the output image in pixels. Automatically rounded up to a multiple of a metatile's pixel width.</p></body></html></string>
|
||||
</property>
|
||||
<property name="minimum" stdset="0">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="maximum" stdset="0">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="singleStep" stdset="0">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="value" stdset="0">
|
||||
<number>128</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</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>1</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_Buttons">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_Reset">
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
<property name="autoDefault">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<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="QPushButton" name="pushButton_Close">
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
</property>
|
||||
<property name="autoDefault">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_Save">
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
<property name="autoDefault">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_Preview">
|
||||
<property name="title">
|
||||
<string>Preview</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QScrollArea" name="scrollArea_Preview">
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::SizeAdjustPolicy::AdjustToContents</enum>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents_Preview">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>285</width>
|
||||
<height>551</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<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="2" column="3">
|
||||
<widget class="QGraphicsView" name="graphicsView_Preview">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="mouseTracking">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::SizeAdjustPolicy::AdjustIgnored</enum>
|
||||
</property>
|
||||
<property name="dragMode">
|
||||
<enum>QGraphicsView::DragMode::NoDrag</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>NoScrollComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>noscrollcombobox.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>UIntSpinBox</class>
|
||||
<extends>QAbstractSpinBox</extends>
|
||||
<header>uintspinbox.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>UIntHexSpinBox</class>
|
||||
<extends>UIntSpinBox</extends>
|
||||
<header location="global">uintspinbox.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ReorderableListWidget</class>
|
||||
<extends>QListWidget</extends>
|
||||
<header>metatileimageexporter.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
152
forms/palettecolorsearch.ui
Normal file
152
forms/palettecolorsearch.ui
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PaletteColorSearch</class>
|
||||
<widget class="QDialog" name="PaletteColorSearch">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>547</width>
|
||||
<height>329</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Palette Color Search</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_Title">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="searchBar">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<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>
|
||||
<widget class="QFrame" name="frame_Color">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_Color">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="NoScrollSpinBox" name="spinBox_ColorId">
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_Palette">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Palette</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinBox_PaletteId"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<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>
|
||||
<widget class="QTableWidget" name="table_Results">
|
||||
<property name="columnCount">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<column/>
|
||||
<column/>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::StandardButton::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>NoScrollSpinBox</class>
|
||||
<extends>QSpinBox</extends>
|
||||
<header>noscrollspinbox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -38,6 +38,27 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="toolButton_ColorSearch">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Opens a search dialog to find which tilesets/metatiles are using certain colors.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/magnifier.ico</normaloff>:/icons/magnifier.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_AllColorsUsed">
|
||||
<property name="text">
|
||||
<string>(All colors used)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
|
|
@ -89,7 +110,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>883</width>
|
||||
<height>784</height>
|
||||
<height>779</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="layout_Colors">
|
||||
|
|
@ -133,11 +154,28 @@
|
|||
<addaction name="actionUndo"/>
|
||||
<addaction name="actionRedo"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuView">
|
||||
<property name="title">
|
||||
<string>View</string>
|
||||
</property>
|
||||
<addaction name="actionShow_Unused_Colors"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuTools">
|
||||
<property name="title">
|
||||
<string>Tools</string>
|
||||
</property>
|
||||
<addaction name="actionFind_Color_Usage"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuEdit"/>
|
||||
<addaction name="menuView"/>
|
||||
<addaction name="menuTools"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<action name="actionUndo">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Undo</string>
|
||||
</property>
|
||||
|
|
@ -152,6 +190,9 @@
|
|||
</property>
|
||||
</action>
|
||||
<action name="actionRedo">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Redo</string>
|
||||
</property>
|
||||
|
|
@ -164,7 +205,22 @@
|
|||
<string>Import Palette</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionShow_Unused_Colors">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show Unused Colors</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionFind_Color_Usage">
|
||||
<property name="text">
|
||||
<string>Find Color Usage...</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<resources>
|
||||
<include location="../resources/images.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@
|
|||
<item row="3" column="0">
|
||||
<spacer name="verticalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
|
@ -159,7 +159,7 @@
|
|||
<item row="0" column="3">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
|
@ -209,7 +209,7 @@
|
|||
<item>
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
|
@ -253,13 +253,42 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_AutocompleteAllScripts">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>If checked, the list of suggestions when typing in an Event's Script field will include all global script labels in the project. Enabling this setting will make Porymap's startup slower.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Autocomplete Script labels using all possible scripts</string>
|
||||
<widget class="QGroupBox" name="groupBox_ScriptAutocomplete">
|
||||
<property name="title">
|
||||
<string>Script label autocomplete</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioButton_AutocompleteAllScripts">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>If checked, the list of suggestions when typing in an Event's Script field will include all global script labels in the project. This is the slowest option for Porymap's project opening.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>All possible scripts</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioButton_AutocompleteCommonScripts">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>If checked, the list of suggestions when typing in an Event's Script field will include script labels from the current map's scripts file, scripts in-use by the map's other events, and all script files in the <span style=" font-family:'SFMono-Regular','Menlo','Monaco','Consolas','Liberation Mono','Courier New','Courier','monospace'; font-size:11px; color:#e74c3c; background-color:#ffffff;">data_scripts_folders </span>folder.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Current map, and global script files</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioButton_AutocompleteMapScripts">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>If checked, the list of suggestions when typing in an Event's Script field will only include script labels from the current map's scripts file and scripts in-use by the map's other events. This is the fastest option for Porymap's project opening.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Current map only</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
|
@ -294,7 +323,7 @@
|
|||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
|
@ -323,7 +352,7 @@
|
|||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea_TextEditor">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
|
|
@ -333,13 +362,13 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>476</width>
|
||||
<height>343</height>
|
||||
<width>495</width>
|
||||
<height>376</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinimumSize</enum>
|
||||
<enum>QLayout::SizeConstraint::SetMinimumSize</enum>
|
||||
</property>
|
||||
<item row="6" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_TextEditorGotoLineHelp">
|
||||
|
|
@ -347,7 +376,7 @@
|
|||
<string><html><head/><body><p>When this command is set a button will appear next to the <span style=" font-weight:600; font-style:italic;">Script</span> combo-box in the <span style=" font-weight:600; font-style:italic;">Events</span> tab which executes this command.<span style=" font-weight:600;"> %F</span> will be substituted with the file path of the script and <span style=" font-weight:600;">%L</span> will be substituted with the line number of the script in that file. <span style=" font-weight:600;">%F </span><span style=" font-style:italic;">must</span> be given if <span style=" font-weight:600;">%L</span> is given. If <span style=" font-weight:600;">%F</span> is <span style=" font-style:italic;">not</span> given then the script's file path will be added to the end of the command. If the script can't be found then the current map's scripts file is opened.</p></body></html></string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
|
|
@ -380,7 +409,7 @@
|
|||
<string><html><head/><body><p>This is the command that is executed when clicking <span style=" font-weight:600; font-style:italic;">Open Project in Text Editor</span> in the <span style=" font-weight:600; font-style:italic;">Tools</span> menu. <span style=" font-weight:600;">%D</span> will be substituted with the project's root directory. If <span style=" font-weight:600;">%D</span> is <span style=" font-style:italic;">not</span> specified then the project directory will be added to the end of the command.</p></body></html></string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
|
|
@ -410,10 +439,10 @@
|
|||
<item row="2" column="0" colspan="2">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
|
@ -426,7 +455,7 @@
|
|||
<item row="7" column="0" colspan="2">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
|
@ -447,7 +476,7 @@
|
|||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
<set>QDialogButtonBox::StandardButton::Apply|QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
|||
|
|
@ -852,7 +852,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>570</width>
|
||||
<height>798</height>
|
||||
<height>837</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_12">
|
||||
|
|
@ -973,6 +973,27 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_MetatileSelectorWidth">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_MetatileSelectorWidth">
|
||||
<property name="text">
|
||||
<string>Metatile Selector Width</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_MetatileSelectorWidth">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The width (in metatiles) of the metatile selectors on the Map tab and in the Tileset Editor.</p></body></html></string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_WarningTilesetsTab">
|
||||
<property name="styleSheet">
|
||||
|
|
@ -1873,16 +1894,6 @@
|
|||
<extends>QComboBox</extends>
|
||||
<header>noscrollcombobox.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>NoScrollSpinBox</class>
|
||||
<extends>QSpinBox</extends>
|
||||
<header>noscrollspinbox.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>NoScrollTextEdit</class>
|
||||
<extends>QTextEdit</extends>
|
||||
<header>noscrolltextedit.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>UIntSpinBox</class>
|
||||
<extends>QAbstractSpinBox</extends>
|
||||
|
|
@ -1893,6 +1904,16 @@
|
|||
<extends>UIntSpinBox</extends>
|
||||
<header location="global">uintspinbox.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>NoScrollSpinBox</class>
|
||||
<extends>QSpinBox</extends>
|
||||
<header>noscrollspinbox.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>NoScrollTextEdit</class>
|
||||
<extends>QTextEdit</extends>
|
||||
<header>noscrolltextedit.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../resources/images.qrc"/>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>733</width>
|
||||
<width>748</width>
|
||||
<height>784</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
|
@ -65,7 +65,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>239</width>
|
||||
<width>241</width>
|
||||
<height>659</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
|
@ -158,7 +158,7 @@
|
|||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>166</height>
|
||||
<height>190</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
|
|
@ -194,177 +194,291 @@
|
|||
<property name="checkable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="15" column="0" colspan="4">
|
||||
<widget class="QLineEdit" name="lineEdit_metatileLabel">
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2" colspan="3">
|
||||
<widget class="NoScrollComboBox" name="comboBox_layerType">
|
||||
<layout class="QGridLayout" name="gridLayout_MetatileProperties">
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QFrame" name="frame_RawAttributesValue">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>185</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||
<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>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_RawAttributesValue">
|
||||
<property name="text">
|
||||
<string>Raw Attributes Value</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="UIntHexSpinBox" name="spinBox_RawAttributesValue"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_10">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>1</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0" colspan="5">
|
||||
<widget class="QLabel" name="label_metatileLabel">
|
||||
<property name="text">
|
||||
<string>Metatile Label (Optional)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_BottomTop">
|
||||
<property name="text">
|
||||
<string>Bottom/Top</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0" colspan="5">
|
||||
<widget class="QLabel" name="label_terrainType">
|
||||
<property name="text">
|
||||
<string>Terrain Type</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" colspan="3">
|
||||
<widget class="QLabel" name="label_layerType">
|
||||
<property name="text">
|
||||
<string>Layer Type</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0" colspan="5">
|
||||
<widget class="NoScrollComboBox" name="comboBox_metatileBehaviors">
|
||||
<item row="0" column="1" rowspan="2">
|
||||
<widget class="QFrame" name="frame_LayerType">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="insertPolicy">
|
||||
<enum>QComboBox::InsertPolicy::NoInsert</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_LayerType">
|
||||
<property name="text">
|
||||
<string>Layer Type</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="NoScrollComboBox" name="comboBox_LayerType">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>185</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>1</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QGraphicsView" name="graphicsView_metatileLayers">
|
||||
<item row="6" column="0" colspan="2">
|
||||
<widget class="QFrame" name="frame_MetatileLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>66</width>
|
||||
<height>34</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>96</width>
|
||||
<height>34</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarPolicy::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarPolicy::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<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>2</number>
|
||||
</property>
|
||||
<item row="1" column="1">
|
||||
<widget class="QToolButton" name="copyButton_MetatileLabel">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Copies the full metatile label to the clipboard.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/clipboard.ico</normaloff>:/icons/clipboard.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLineEdit" name="lineEdit_MetatileLabel">
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_MetatileLabel">
|
||||
<property name="text">
|
||||
<string>Metatile Label (Optional)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<spacer name="verticalSpacer_11">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>1</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0" colspan="5">
|
||||
<widget class="NoScrollComboBox" name="comboBox_terrainType">
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QFrame" name="frame_TerrainType">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="insertPolicy">
|
||||
<enum>QComboBox::InsertPolicy::NoInsert</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<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>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_TerrainType">
|
||||
<property name="text">
|
||||
<string>Terrain Type</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="NoScrollComboBox" name="comboBox_TerrainType">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="insertPolicy">
|
||||
<enum>QComboBox::InsertPolicy::NoInsert</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_9">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>1</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<spacer name="horizontalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Maximum</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="9" column="0" colspan="5">
|
||||
<widget class="NoScrollComboBox" name="comboBox_encounterType">
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QFrame" name="frame_EncounterType">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="insertPolicy">
|
||||
<enum>QComboBox::InsertPolicy::NoInsert</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<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>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_EncounterType">
|
||||
<property name="text">
|
||||
<string>Encounter Type</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="NoScrollComboBox" name="comboBox_EncounterType">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="insertPolicy">
|
||||
<enum>QComboBox::InsertPolicy::NoInsert</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_8">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>1</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="5">
|
||||
<widget class="QLabel" name="label_metatileBehavior">
|
||||
<property name="text">
|
||||
<string>Metatile Behavior</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0" colspan="5">
|
||||
<widget class="QLabel" name="label_rawAttributesValue">
|
||||
<property name="text">
|
||||
<string>Raw Attributes Value</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0" colspan="5">
|
||||
<widget class="QLabel" name="label_encounterType">
|
||||
<property name="text">
|
||||
<string>Encounter Type</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="4">
|
||||
<widget class="QToolButton" name="copyButton_metatileLabel">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Copies the full metatile label to the clipboard.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/clipboard.ico</normaloff>:/icons/clipboard.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="0">
|
||||
<item row="10" column="0">
|
||||
<spacer name="verticalSpacer_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
|
|
@ -377,8 +491,119 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="13" column="0" colspan="5">
|
||||
<widget class="UIntHexSpinBox" name="spinBox_rawAttributesValue"/>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QFrame" name="frame_MetatileBehavior">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<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>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_MetatileBehavior">
|
||||
<property name="text">
|
||||
<string>Metatile Behavior</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="NoScrollComboBox" name="comboBox_MetatileBehaviors">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="insertPolicy">
|
||||
<enum>QComboBox::InsertPolicy::NoInsert</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>1</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" rowspan="2">
|
||||
<widget class="QFrame" name="frame_Layers">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_Layers">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_BottomTop">
|
||||
<property name="text">
|
||||
<string>Bottom/Top</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGraphicsView" name="graphicsView_MetatileLayers">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>1</width>
|
||||
<height>1</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarPolicy::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarPolicy::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_12">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>1</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
|
@ -457,12 +682,6 @@
|
|||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QFrame" name="frame_SelectedTile">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>98</width>
|
||||
|
|
@ -503,16 +722,22 @@
|
|||
</item>
|
||||
<item>
|
||||
<widget class="QGraphicsView" name="graphicsView_selectedTile">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>18</width>
|
||||
<height>18</height>
|
||||
<width>98</width>
|
||||
<height>98</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>98</width>
|
||||
<height>34</height>
|
||||
<height>98</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
|
|
@ -526,22 +751,22 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>1</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="2">
|
||||
<spacer name="verticalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -561,8 +786,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>445</width>
|
||||
<height>237</height>
|
||||
<width>458</width>
|
||||
<height>203</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
|
|
@ -623,7 +848,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>733</width>
|
||||
<width>748</width>
|
||||
<height>37</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
|
@ -631,18 +856,42 @@
|
|||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuExport_Tiles_Image">
|
||||
<property name="title">
|
||||
<string>Export Tiles Image</string>
|
||||
</property>
|
||||
<addaction name="actionExport_Primary_Tiles_Image"/>
|
||||
<addaction name="actionExport_Secondary_Tiles_Image"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuImport_AdvanceMap_Metatiles">
|
||||
<property name="title">
|
||||
<string>Import Metatiles from Advance Map 1.92</string>
|
||||
</property>
|
||||
<addaction name="actionImport_Primary_AdvanceMap_Metatiles"/>
|
||||
<addaction name="actionImport_Secondary_AdvanceMap_Metatiles"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuImport_Tiles_Image">
|
||||
<property name="title">
|
||||
<string>Import Tiles Image</string>
|
||||
</property>
|
||||
<addaction name="actionImport_Primary_Tiles_Image"/>
|
||||
<addaction name="actionImport_Secondary_Tiles_Image"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuExport_porytiles_Layer_Images">
|
||||
<property name="title">
|
||||
<string>Export Porytiles Layer Images</string>
|
||||
</property>
|
||||
<addaction name="actionExport_Primary_Porytiles_Layer_Images"/>
|
||||
<addaction name="actionExport_Secondary_Porytiles_Layer_Images"/>
|
||||
</widget>
|
||||
<addaction name="actionSave_Tileset"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionImport_Primary_Tiles"/>
|
||||
<addaction name="actionImport_Secondary_Tiles"/>
|
||||
<addaction name="menuImport_Tiles_Image"/>
|
||||
<addaction name="menuImport_AdvanceMap_Metatiles"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionImport_Primary_Metatiles"/>
|
||||
<addaction name="actionImport_Secondary_Metatiles"/>
|
||||
<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"/>
|
||||
<addaction name="menuExport_Tiles_Image"/>
|
||||
<addaction name="actionExport_Metatiles_Image"/>
|
||||
<addaction name="menuExport_porytiles_Layer_Images"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuTools">
|
||||
<property name="title">
|
||||
|
|
@ -663,11 +912,20 @@
|
|||
<addaction name="actionPaste"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionChange_Metatiles_Count"/>
|
||||
<addaction name="actionSwap_Metatiles"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuView">
|
||||
<property name="title">
|
||||
<string>View</string>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuLayer_Arrangement">
|
||||
<property name="title">
|
||||
<string>Layer Arrangement</string>
|
||||
</property>
|
||||
<addaction name="actionLayer_Arrangement_Horizontal"/>
|
||||
<addaction name="actionLayer_Arrangement_Vertical"/>
|
||||
</widget>
|
||||
<addaction name="menuLayer_Arrangement"/>
|
||||
<addaction name="actionLayer_Grid"/>
|
||||
<addaction name="actionMetatile_Grid"/>
|
||||
<addaction name="actionShow_Tileset_Divider"/>
|
||||
|
|
@ -691,16 +949,6 @@
|
|||
<string>Ctrl+S</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionImport_Primary_Tiles">
|
||||
<property name="text">
|
||||
<string>Import Primary Tiles Image...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionImport_Secondary_Tiles">
|
||||
<property name="text">
|
||||
<string>Import Secondary Tiles Image...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionChange_Metatiles_Count">
|
||||
<property name="text">
|
||||
<string>Change Number of Metatiles...</string>
|
||||
|
|
@ -736,6 +984,9 @@
|
|||
</property>
|
||||
</action>
|
||||
<action name="actionUndo">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Undo</string>
|
||||
</property>
|
||||
|
|
@ -744,6 +995,9 @@
|
|||
</property>
|
||||
</action>
|
||||
<action name="actionRedo">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Redo</string>
|
||||
</property>
|
||||
|
|
@ -751,36 +1005,6 @@
|
|||
<string>Ctrl+Y</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExport_Primary_Tiles_Image">
|
||||
<property name="text">
|
||||
<string>Export Primary Tiles Image...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExport_Secondary_Tiles_Image">
|
||||
<property name="text">
|
||||
<string>Export Secondary Tiles Image...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionImport_Primary_Metatiles">
|
||||
<property name="text">
|
||||
<string>Import Primary Metatiles from Advance Map 1.92...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionImport_Secondary_Metatiles">
|
||||
<property name="text">
|
||||
<string>Import Secondary Metatiles from Advance Map 1.92...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExport_Primary_Metatiles_Image">
|
||||
<property name="text">
|
||||
<string>Export Primary Metatiles Image...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExport_Secondary_Metatiles_Image">
|
||||
<property name="text">
|
||||
<string>Export Secondary Metatiles Image...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCut">
|
||||
<property name="text">
|
||||
<string>Cut</string>
|
||||
|
|
@ -798,6 +1022,9 @@
|
|||
</property>
|
||||
</action>
|
||||
<action name="actionPaste">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Paste</string>
|
||||
</property>
|
||||
|
|
@ -840,6 +1067,78 @@
|
|||
<string>Show Raw Metatile Attributes</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExport_Primary_Tiles_Image">
|
||||
<property name="text">
|
||||
<string>Primary...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExport_Secondary_Tiles_Image">
|
||||
<property name="text">
|
||||
<string>Secondary...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionImport_Primary_AdvanceMap_Metatiles">
|
||||
<property name="text">
|
||||
<string>Primary...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionImport_Secondary_AdvanceMap_Metatiles">
|
||||
<property name="text">
|
||||
<string>Secondary...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionImport_Primary_Tiles_Image">
|
||||
<property name="text">
|
||||
<string>Primary...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionImport_Secondary_Tiles_Image">
|
||||
<property name="text">
|
||||
<string>Secondary...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExport_Metatiles_Image">
|
||||
<property name="text">
|
||||
<string>Export Metatiles Image...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExport_Primary_Porytiles_Layer_Images">
|
||||
<property name="text">
|
||||
<string>Primary...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExport_Secondary_Porytiles_Layer_Images">
|
||||
<property name="text">
|
||||
<string>Secondary...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionLayer_Arrangement_Horizontal">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Horizontal</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionLayer_Arrangement_Vertical">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Vertical</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSwap_Metatiles">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Swap Metatiles</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>X</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
|
|
|||
|
|
@ -27,6 +27,12 @@ extern const QVersionNumber porymapVersion;
|
|||
|
||||
#define CONFIG_BACKWARDS_COMPATABILITY
|
||||
|
||||
enum ScriptAutocompleteMode {
|
||||
MapOnly,
|
||||
MapAndCommon,
|
||||
All,
|
||||
};
|
||||
|
||||
class KeyValueConfigBase
|
||||
{
|
||||
public:
|
||||
|
|
@ -54,7 +60,8 @@ protected:
|
|||
static bool getConfigBool(const QString &key, const QString &value);
|
||||
static int getConfigInteger(const QString &key, const QString &value, int min = INT_MIN, int max = INT_MAX, int defaultValue = 0);
|
||||
static uint32_t getConfigUint32(const QString &key, const QString &value, uint32_t min = 0, uint32_t max = UINT_MAX, uint32_t defaultValue = 0);
|
||||
static QColor getConfigColor(const QString &key, const QString &value, const QColor &defaultValue = Qt::black);
|
||||
static QColor getConfigColor(const QString &key, const QString &value, const QColor &defaultValue = QColor(Qt::black));
|
||||
static QString toConfigColor(const QColor &color);
|
||||
|
||||
QString m_root;
|
||||
QString m_filename;
|
||||
|
|
@ -65,57 +72,7 @@ class PorymapConfig: public KeyValueConfigBase
|
|||
{
|
||||
public:
|
||||
PorymapConfig();
|
||||
virtual void reset() override {
|
||||
setRoot(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
|
||||
this->recentProjects.clear();
|
||||
this->projectManuallyClosed = false;
|
||||
this->reopenOnLaunch = true;
|
||||
this->mapListTab = 0;
|
||||
this->mapListEditGroupsEnabled = false;
|
||||
this->mapListHideEmptyEnabled.clear();
|
||||
this->prettyCursors = true;
|
||||
this->mirrorConnectingMaps = true;
|
||||
this->showDiveEmergeMaps = false;
|
||||
this->diveEmergeMapOpacity = 30;
|
||||
this->diveMapOpacity = 15;
|
||||
this->emergeMapOpacity = 15;
|
||||
this->collisionOpacity = 50;
|
||||
this->collisionZoom = 30;
|
||||
this->metatilesZoom = 30;
|
||||
this->tilesetEditorMetatilesZoom = 30;
|
||||
this->tilesetEditorTilesZoom = 30;
|
||||
this->showPlayerView = false;
|
||||
this->showCursorTile = true;
|
||||
this->showBorder = true;
|
||||
this->showGrid = false;
|
||||
this->showTilesetEditorMetatileGrid = false;
|
||||
this->showTilesetEditorLayerGrid = true;
|
||||
this->showTilesetEditorDivider = false;
|
||||
this->showTilesetEditorRawAttributes = false;
|
||||
this->monitorFiles = true;
|
||||
this->tilesetCheckerboardFill = true;
|
||||
this->newMapHeaderSectionExpanded = false;
|
||||
this->theme = "default";
|
||||
this->wildMonChartTheme = "";
|
||||
this->textEditorOpenFolder = "";
|
||||
this->textEditorGotoLine = "";
|
||||
this->paletteEditorBitDepth = 24;
|
||||
this->projectSettingsTab = 0;
|
||||
this->loadAllEventScripts = false;
|
||||
this->warpBehaviorWarningDisabled = false;
|
||||
this->eventDeleteWarningDisabled = false;
|
||||
this->eventOverlayEnabled = false;
|
||||
this->checkForUpdates = true;
|
||||
this->lastUpdateCheckTime = QDateTime();
|
||||
this->lastUpdateCheckVersion = porymapVersion;
|
||||
this->rateLimitTimes.clear();
|
||||
this->eventSelectionShapeMode = QGraphicsPixmapItem::MaskShape;
|
||||
this->shownInGameReloadMessage = false;
|
||||
this->gridSettings = GridSettings();
|
||||
this->statusBarLogTypes = { LogType::LOG_ERROR, LogType::LOG_WARN };
|
||||
this->applicationFont = QFont();
|
||||
this->mapListFont = PorymapConfig::defaultMapListFont();
|
||||
}
|
||||
virtual void reset() override;
|
||||
void addRecentProject(QString project);
|
||||
void setRecentProjects(QStringList projects);
|
||||
QString getRecentProject();
|
||||
|
|
@ -151,6 +108,7 @@ public:
|
|||
int metatilesZoom;
|
||||
int tilesetEditorMetatilesZoom;
|
||||
int tilesetEditorTilesZoom;
|
||||
Qt::Orientation tilesetEditorLayerOrientation;
|
||||
bool showPlayerView;
|
||||
bool showCursorTile;
|
||||
bool showBorder;
|
||||
|
|
@ -159,6 +117,7 @@ public:
|
|||
bool showTilesetEditorLayerGrid;
|
||||
bool showTilesetEditorDivider;
|
||||
bool showTilesetEditorRawAttributes;
|
||||
bool showPaletteEditorUnusedColors;
|
||||
bool monitorFiles;
|
||||
bool tilesetCheckerboardFill;
|
||||
bool newMapHeaderSectionExpanded;
|
||||
|
|
@ -168,7 +127,7 @@ public:
|
|||
QString textEditorGotoLine;
|
||||
int paletteEditorBitDepth;
|
||||
int projectSettingsTab;
|
||||
bool loadAllEventScripts;
|
||||
ScriptAutocompleteMode scriptAutocompleteMode;
|
||||
bool warpBehaviorWarningDisabled;
|
||||
bool eventDeleteWarningDisabled;
|
||||
bool eventOverlayEnabled;
|
||||
|
|
@ -351,7 +310,7 @@ public:
|
|||
this->prefabImportPrompted = false;
|
||||
this->tilesetsHaveCallback = true;
|
||||
this->tilesetsHaveIsCompressed = true;
|
||||
this->setTransparentPixelsBlack = true;
|
||||
this->transparencyColor = QColor(Qt::black);
|
||||
this->preserveMatchingOnlyData = false;
|
||||
this->filePaths.clear();
|
||||
this->eventIconPaths.clear();
|
||||
|
|
@ -368,6 +327,7 @@ public:
|
|||
this->unusedTileSplit = 0x0000;
|
||||
this->maxEventsPerGroup = 255;
|
||||
this->forcedMajorVersion = 0;
|
||||
this->metatileSelectorWidth = 8;
|
||||
this->globalConstantsFilepaths.clear();
|
||||
this->globalConstants.clear();
|
||||
this->identifiers.clear();
|
||||
|
|
@ -426,7 +386,7 @@ public:
|
|||
bool prefabImportPrompted;
|
||||
bool tilesetsHaveCallback;
|
||||
bool tilesetsHaveIsCompressed;
|
||||
bool setTransparentPixelsBlack;
|
||||
QColor transparencyColor;
|
||||
bool preserveMatchingOnlyData;
|
||||
int metatileAttributesSize;
|
||||
uint32_t metatileBehaviorMask;
|
||||
|
|
@ -447,6 +407,7 @@ public:
|
|||
QList<uint32_t> warpBehaviors;
|
||||
int maxEventsPerGroup;
|
||||
int forcedMajorVersion;
|
||||
int metatileSelectorWidth;
|
||||
QStringList globalConstantsFilepaths;
|
||||
QMap<QString,QString> globalConstants;
|
||||
|
||||
|
|
|
|||
|
|
@ -122,8 +122,8 @@ public:
|
|||
int getZ() const { return this->elevation; }
|
||||
int getElevation() const { return this->elevation; }
|
||||
|
||||
int getPixelX() const { return (this->x * 16) - qMax(0, (pixmap.width() - 16) / 2); }
|
||||
int getPixelY() const { return (this->y * 16) - qMax(0, pixmap.height() - 16); }
|
||||
int getPixelX() const;
|
||||
int getPixelY() const;
|
||||
|
||||
virtual EventFrame *getEventFrame();
|
||||
virtual EventFrame *createEventFrame() = 0;
|
||||
|
|
@ -161,6 +161,7 @@ public:
|
|||
QString getIdName() const { return this->idName; }
|
||||
|
||||
static QString groupToString(Event::Group group);
|
||||
static QString groupToJsonKey(Event::Group group);
|
||||
static QString typeToString(Event::Type type);
|
||||
static QString typeToJsonKey(Event::Type type);
|
||||
static Event::Type typeFromJsonKey(QString type);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ public:
|
|||
if (head > 0) {
|
||||
return history.at(--head);
|
||||
}
|
||||
head = -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -37,9 +38,7 @@ public:
|
|||
|
||||
void push(T commit) {
|
||||
while (head + 1 < history.length()) {
|
||||
T item = history.last();
|
||||
history.removeLast();
|
||||
delete item;
|
||||
delete history.takeLast();
|
||||
}
|
||||
if (saved > head) {
|
||||
saved = -1;
|
||||
|
|
@ -48,7 +47,7 @@ public:
|
|||
head++;
|
||||
}
|
||||
|
||||
T current() {
|
||||
T current() const {
|
||||
if (head < 0 || history.length() == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -59,10 +58,30 @@ public:
|
|||
saved = head;
|
||||
}
|
||||
|
||||
bool isSaved() {
|
||||
bool isSaved() const {
|
||||
return saved == head;
|
||||
}
|
||||
|
||||
int length() const {
|
||||
return history.length();
|
||||
}
|
||||
|
||||
bool isEmpty() const {
|
||||
return history.isEmpty();
|
||||
}
|
||||
|
||||
int index() const {
|
||||
return head;
|
||||
}
|
||||
|
||||
bool canUndo() const {
|
||||
return head >= 0;
|
||||
}
|
||||
|
||||
bool canRedo() const {
|
||||
return (head + 1) < history.length();
|
||||
}
|
||||
|
||||
private:
|
||||
QList<T> history;
|
||||
int head = -1;
|
||||
|
|
|
|||
|
|
@ -51,10 +51,12 @@ public:
|
|||
void setLayoutId(const QString &layoutId) { m_layoutId = layoutId; }
|
||||
QString layoutId() const { return layout() ? layout()->id : m_layoutId; }
|
||||
|
||||
int getWidth() const;
|
||||
int getHeight() const;
|
||||
int getBorderWidth() const;
|
||||
int getBorderHeight() const;
|
||||
int getWidth() const { return m_layout ? m_layout->getWidth() : 0; }
|
||||
int getHeight() const { return m_layout ? m_layout->getHeight() : 0; }
|
||||
int getBorderWidth() const { return m_layout ? m_layout->getBorderWidth() : 0; }
|
||||
int getBorderHeight() const { return m_layout ? m_layout->getBorderHeight() : 0; }
|
||||
int pixelWidth() const { return m_layout ? m_layout->pixelWidth() : 0; }
|
||||
int pixelHeight() const { return m_layout ? m_layout->pixelHeight() : 0; }
|
||||
|
||||
void setHeader(const MapHeader &header) { *m_header = header; }
|
||||
MapHeader* header() const { return m_header; }
|
||||
|
|
@ -62,6 +64,8 @@ public:
|
|||
void setSharedEventsMap(const QString &sharedEventsMap) { m_sharedEventsMap = sharedEventsMap; }
|
||||
void setSharedScriptsMap(const QString &sharedScriptsMap);
|
||||
|
||||
bool isInheritingEvents() const { return !m_sharedEventsMap.isEmpty() && !hasEvents(); }
|
||||
bool isInheritingScripts() const { return !m_sharedScriptsMap.isEmpty(); }
|
||||
QString sharedEventsMap() const { return m_sharedEventsMap; }
|
||||
QString sharedScriptsMap() const { return m_sharedScriptsMap; }
|
||||
|
||||
|
|
@ -83,6 +87,7 @@ public:
|
|||
void addEvent(Event *);
|
||||
int getIndexOfEvent(Event *) const;
|
||||
bool hasEvent(Event *) const;
|
||||
bool hasEvents() const;
|
||||
|
||||
QStringList getScriptLabels(Event::Group group = Event::Group::None);
|
||||
QString getScriptsFilepath() const;
|
||||
|
|
@ -133,9 +138,6 @@ private:
|
|||
QMap<Event::Group, QList<Event *>> m_events;
|
||||
QSet<Event *> m_ownedEvents; // for memory management
|
||||
|
||||
QList<int> m_metatileLayerOrder;
|
||||
QList<float> m_metatileLayerOpacity;
|
||||
|
||||
void trackConnection(MapConnection*);
|
||||
|
||||
// MapConnections in 'ownedConnections' but not 'connections' persist in the edit history.
|
||||
|
|
@ -149,7 +151,7 @@ signals:
|
|||
void modified();
|
||||
void scriptsModified();
|
||||
void mapDimensionsChanged(const QSize &size);
|
||||
void openScriptRequested(QString label);
|
||||
void openScriptRequested(const QString &label);
|
||||
void connectionAdded(MapConnection*);
|
||||
void connectionRemoved(MapConnection*);
|
||||
void layoutChanged();
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ public:
|
|||
MapConnection* createMirror();
|
||||
|
||||
QPixmap render() const;
|
||||
QPoint relativePos(bool clipped = false) const;
|
||||
QPoint relativePixelPos(bool clipped = false) const;
|
||||
|
||||
static QPointer<Project> project;
|
||||
static const QMap<QString, QString> oppositeDirections;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class BorderMetatilesPixmapItem;
|
|||
class Layout : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
Layout() {}
|
||||
Layout() {};
|
||||
Layout(const Layout &other);
|
||||
|
||||
static QString layoutConstantFromName(const QString &name);
|
||||
|
|
@ -32,6 +32,9 @@ public:
|
|||
int height;
|
||||
int border_width;
|
||||
int border_height;
|
||||
int pixelWidth() const { return this->width * Metatile::pixelWidth(); }
|
||||
int pixelHeight() const { return this->height * Metatile::pixelHeight(); }
|
||||
QSize pixelSize() const { return QSize(pixelWidth(), pixelHeight()); }
|
||||
|
||||
QString border_path;
|
||||
QString blockdata_path;
|
||||
|
|
@ -64,8 +67,25 @@ public:
|
|||
QSize borderDimensions;
|
||||
} lastCommitBlocks; // to track map changes
|
||||
|
||||
QList<int> metatileLayerOrder;
|
||||
QList<float> metatileLayerOpacity;
|
||||
void setMetatileLayerOrder(const QList<int> &layerOrder) { m_metatileLayerOrder = layerOrder; }
|
||||
const QList<int> &metatileLayerOrder() const {
|
||||
return !m_metatileLayerOrder.isEmpty() ? m_metatileLayerOrder : Layout::globalMetatileLayerOrder();
|
||||
}
|
||||
static void setGlobalMetatileLayerOrder(const QList<int> &layerOrder) { s_globalMetatileLayerOrder = layerOrder; }
|
||||
static const QList<int> &globalMetatileLayerOrder() {
|
||||
static const QList<int> defaultLayerOrder = {0, 1, 2};
|
||||
return !s_globalMetatileLayerOrder.isEmpty() ? s_globalMetatileLayerOrder : defaultLayerOrder;
|
||||
}
|
||||
|
||||
void setMetatileLayerOpacity(const QList<float> &layerOpacity) { m_metatileLayerOpacity = layerOpacity; }
|
||||
const QList<float> &metatileLayerOpacity() const {
|
||||
return !m_metatileLayerOpacity.isEmpty() ? m_metatileLayerOpacity : Layout::globalMetatileLayerOpacity();
|
||||
}
|
||||
static void setGlobalMetatileLayerOpacity(const QList<float> &layerOpacity) { s_globalMetatileLayerOpacity = layerOpacity; }
|
||||
static const QList<float> &globalMetatileLayerOpacity() {
|
||||
static const QList<float> defaultLayerOpacity = {1.0, 1.0, 1.0};
|
||||
return !s_globalMetatileLayerOpacity.isEmpty() ? s_globalMetatileLayerOpacity : defaultLayerOpacity;
|
||||
}
|
||||
|
||||
LayoutPixmapItem *layoutItem = nullptr;
|
||||
CollisionPixmapItem *collisionItem = nullptr;
|
||||
|
|
@ -100,13 +120,17 @@ public:
|
|||
QRect getVisibleRect() const;
|
||||
|
||||
bool isWithinBounds(int x, int y) const;
|
||||
bool isWithinBounds(const QPoint &pos) const;
|
||||
bool isWithinBounds(const QRect &rect) const;
|
||||
bool isWithinBorderBounds(int x, int y) const;
|
||||
|
||||
bool getBlock(int x, int y, Block *out);
|
||||
bool getBlock(int x, int y, Block *out) const;
|
||||
void setBlock(int x, int y, Block block, bool enableScriptCallback = false);
|
||||
void setBlockdata(Blockdata blockdata, bool enableScriptCallback = false);
|
||||
|
||||
uint16_t getMetatileId(int x, int y) const;
|
||||
bool setMetatileId(int x, int y, uint16_t metatileId, 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);
|
||||
|
|
@ -135,9 +159,8 @@ public:
|
|||
void _floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation);
|
||||
void magicFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation);
|
||||
|
||||
QPixmap render(bool ignoreCache = false, Layout *fromLayout = nullptr, QRect bounds = QRect(0, 0, -1, -1));
|
||||
QPixmap render(bool ignoreCache = false, Layout *fromLayout = nullptr, const QRect &bounds = QRect(0, 0, -1, -1));
|
||||
QPixmap renderCollision(bool ignoreCache);
|
||||
// QPixmap renderConnection(MapConnection, Layout *);
|
||||
QPixmap renderBorder(bool ignoreCache = false);
|
||||
|
||||
QPixmap getLayoutItemPixmap();
|
||||
|
|
@ -146,6 +169,8 @@ public:
|
|||
void setCollisionItem(CollisionPixmapItem *item) { collisionItem = item; }
|
||||
void setBorderItem(BorderMetatilesPixmapItem *item) { borderItem = item; }
|
||||
|
||||
bool metatileIsValid(uint16_t metatileId) { return Tileset::metatileIsValid(metatileId, this->tileset_primary, this->tileset_secondary); }
|
||||
|
||||
private:
|
||||
void setNewDimensionsBlockdata(int newWidth, int newHeight);
|
||||
void setNewBorderDimensionsBlockdata(int newWidth, int newHeight);
|
||||
|
|
@ -154,6 +179,11 @@ private:
|
|||
|
||||
static int getBorderDrawDistance(int dimension, qreal minimum);
|
||||
|
||||
QList<int> m_metatileLayerOrder;
|
||||
QList<float> m_metatileLayerOpacity;
|
||||
static QList<int> s_globalMetatileLayerOrder;
|
||||
static QList<float> s_globalMetatileLayerOpacity;
|
||||
|
||||
signals:
|
||||
void dimensionsChanged(const QSize &size);
|
||||
void needsRedrawing();
|
||||
|
|
|
|||
|
|
@ -61,7 +61,15 @@ public:
|
|||
static int getDefaultAttributesSize(BaseGameVersion version);
|
||||
static void setLayout(Project*);
|
||||
static QString getMetatileIdString(uint16_t metatileId);
|
||||
static QString getMetatileIdStrings(const QList<uint16_t> metatileIds);
|
||||
static QString getMetatileIdStrings(const QList<uint16_t> &metatileIds);
|
||||
static QString getLayerName(int layerNum);
|
||||
|
||||
static constexpr int tileWidth() { return 2; }
|
||||
static constexpr int tileHeight() { return 2; }
|
||||
static constexpr int tilesPerLayer() { return Metatile::tileWidth() * Metatile::tileHeight(); }
|
||||
static constexpr int pixelWidth() { return Metatile::tileWidth() * Tile::pixelWidth(); }
|
||||
static constexpr int pixelHeight() { return Metatile::tileHeight() * Tile::pixelHeight(); }
|
||||
static constexpr QSize pixelSize() { return QSize(pixelWidth(), pixelHeight()); }
|
||||
|
||||
inline bool operator==(const Metatile &other) {
|
||||
return this->tiles == other.tiles && this->attributes == other.attributes;
|
||||
|
|
|
|||
|
|
@ -26,10 +26,14 @@
|
|||
});
|
||||
*/
|
||||
|
||||
#if __has_include(<QNetworkAccessManager>)
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QDateTime>
|
||||
#endif
|
||||
|
||||
#ifdef QT_NETWORK_LIB
|
||||
|
||||
class NetworkReplyData : public QObject
|
||||
{
|
||||
|
|
@ -84,4 +88,6 @@ private:
|
|||
const QNetworkRequest getRequest(const QUrl &url);
|
||||
};
|
||||
|
||||
#endif // QT_NETWORK_LIB
|
||||
|
||||
#endif // NETWORK_H
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#define TILE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QSize>
|
||||
|
||||
class Tile
|
||||
{
|
||||
|
|
@ -24,6 +25,12 @@ public:
|
|||
static int getIndexInTileset(int);
|
||||
|
||||
static const uint16_t maxValue;
|
||||
|
||||
static constexpr int pixelWidth() { return 8; }
|
||||
static constexpr int pixelHeight() { return 8; }
|
||||
static constexpr QSize pixelSize() { return QSize(Tile::pixelWidth(), Tile::pixelHeight()); }
|
||||
static constexpr int numPixels() { return Tile::pixelWidth() * Tile::pixelHeight(); }
|
||||
static constexpr int sizeInBytes() { return sizeof(uint16_t); }
|
||||
};
|
||||
|
||||
inline bool operator==(const Tile &a, const Tile &b) {
|
||||
|
|
|
|||
|
|
@ -30,17 +30,21 @@ public:
|
|||
QString metatile_attrs_label;
|
||||
QString metatile_attrs_path;
|
||||
QString tilesImagePath;
|
||||
QImage tilesImage;
|
||||
QStringList palettePaths;
|
||||
|
||||
QList<QImage> tiles;
|
||||
QHash<int, QString> metatileLabels;
|
||||
QList<QList<QRgb>> palettes;
|
||||
QList<QList<QRgb>> palettePreviews;
|
||||
|
||||
static QString stripPrefix(const QString &fullName);
|
||||
static Tileset* getPaletteTileset(int, Tileset*, Tileset*);
|
||||
static const Tileset* getPaletteTileset(int, const Tileset*, const Tileset*);
|
||||
static Tileset* getMetatileTileset(int, Tileset*, Tileset*);
|
||||
static const Tileset* getMetatileTileset(int, const Tileset*, const Tileset*);
|
||||
static Tileset* getTileTileset(int, Tileset*, Tileset*);
|
||||
static const Tileset* getTileTileset(int, const Tileset*, const Tileset*);
|
||||
static Metatile* getMetatile(int, Tileset*, Tileset*);
|
||||
static const Metatile* getMetatile(int, const Tileset*, const Tileset*);
|
||||
static Tileset* getMetatileLabelTileset(int, Tileset*, Tileset*);
|
||||
static QString getMetatileLabel(int, Tileset *, Tileset *);
|
||||
static QString getOwnedMetatileLabel(int, Tileset *, Tileset *);
|
||||
|
|
@ -48,9 +52,9 @@ public:
|
|||
static bool setMetatileLabel(int, QString, Tileset *, Tileset *);
|
||||
QString getMetatileLabelPrefix();
|
||||
static QString getMetatileLabelPrefix(const QString &name);
|
||||
static QList<QList<QRgb>> getBlockPalettes(Tileset*, Tileset*, bool useTruePalettes = false);
|
||||
static QList<QRgb> getPalette(int, Tileset*, Tileset*, bool useTruePalettes = false);
|
||||
static bool metatileIsValid(uint16_t metatileId, Tileset *, Tileset *);
|
||||
static QList<QList<QRgb>> getBlockPalettes(const Tileset*, const Tileset*, bool useTruePalettes = false);
|
||||
static QList<QRgb> getPalette(int, const Tileset*, const Tileset*, bool useTruePalettes = false);
|
||||
static bool metatileIsValid(uint16_t metatileId, const Tileset*, const Tileset*);
|
||||
static QHash<int, QString> getHeaderMemberMap(bool usingAsm);
|
||||
static QString getExpectedDir(QString tilesetName, bool isSecondary);
|
||||
QString getExpectedDir();
|
||||
|
|
@ -76,15 +80,38 @@ public:
|
|||
void setMetatiles(const QList<Metatile*> &metatiles);
|
||||
void addMetatile(Metatile* metatile);
|
||||
|
||||
QList<Metatile*> metatiles() const { return m_metatiles; }
|
||||
Metatile* metatileAt(unsigned int i) const { return m_metatiles.at(i); }
|
||||
const QList<Metatile*> &metatiles() const { return m_metatiles; }
|
||||
const Metatile* metatileAt(unsigned int i) const { return m_metatiles.at(i); }
|
||||
|
||||
void clearMetatiles();
|
||||
void resizeMetatiles(int newNumMetatiles);
|
||||
int numMetatiles() const { return m_metatiles.length(); }
|
||||
int maxMetatiles() const;
|
||||
|
||||
uint16_t firstMetatileId() const;
|
||||
uint16_t lastMetatileId() const;
|
||||
bool containsMetatileId(uint16_t metatileId) const { return metatileId >= firstMetatileId() && metatileId <= lastMetatileId(); }
|
||||
|
||||
uint16_t firstTileId() const;
|
||||
uint16_t lastTileId() const;
|
||||
bool containsTileId(uint16_t tileId) const { return tileId >= firstTileId() && tileId <= lastTileId(); }
|
||||
|
||||
int numTiles() const { return m_tiles.length(); }
|
||||
int maxTiles() const;
|
||||
|
||||
QImage tileImage(uint16_t tileId) const { return m_tiles.value(Tile::getIndexInTileset(tileId)); }
|
||||
|
||||
QSet<int> getUnusedColorIds(int paletteId, const Tileset *pairedTileset, const QSet<int> &searchColors = {}) const;
|
||||
QList<uint16_t> findMetatilesUsingColor(int paletteId, int colorId, const Tileset *pairedTileset) const;
|
||||
|
||||
static constexpr int maxPalettes() { return 16; }
|
||||
static constexpr int numColorsPerPalette() { return 16; }
|
||||
|
||||
private:
|
||||
QList<Metatile*> m_metatiles;
|
||||
|
||||
QList<QImage> m_tiles;
|
||||
QImage m_tilesImage;
|
||||
bool m_hasUnsavedTilesImage = false;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Util {
|
||||
void numericalModeSort(QStringList &list);
|
||||
int roundUp(int numToRound, int multiple);
|
||||
int roundUpToMultiple(int numToRound, int multiple);
|
||||
QString toDefineCase(QString input);
|
||||
QString toHexString(uint32_t value, int minLength = 0);
|
||||
QString toHtmlParagraph(const QString &text);
|
||||
|
|
@ -16,6 +16,7 @@ namespace Util {
|
|||
QString replaceExtension(const QString &path, const QString &newExtension);
|
||||
void setErrorStylesheet(QLineEdit *lineEdit, bool isError);
|
||||
QString toStylesheetString(const QFont &font);
|
||||
void show(QWidget *w);
|
||||
}
|
||||
|
||||
#endif // UTILITY_H
|
||||
|
|
|
|||
|
|
@ -67,8 +67,6 @@ public:
|
|||
bool setLayout(QString layoutName);
|
||||
void unsetMap();
|
||||
|
||||
Tileset *getCurrentMapPrimaryTileset();
|
||||
|
||||
bool displayMap();
|
||||
bool displayLayout();
|
||||
|
||||
|
|
@ -122,9 +120,10 @@ public:
|
|||
void updateEventPixmapItemZValue(EventPixmapItem *item);
|
||||
qreal getEventOpacity(const Event *event) const;
|
||||
|
||||
bool isMouseInMap() const;
|
||||
void setPlayerViewRect(const QRectF &rect);
|
||||
void updateCursorRectPos(int x, int y);
|
||||
void setCursorRectVisible(bool visible);
|
||||
void setCursorRectPos(const QPoint &pos);
|
||||
void updateCursorRectVisibility();
|
||||
|
||||
void onEventDragged(Event *event, const QPoint &oldPosition, const QPoint &newPosition);
|
||||
void onEventReleased(Event *event, const QPoint &position);
|
||||
|
|
@ -171,7 +170,7 @@ public:
|
|||
void setEditMode(EditMode editMode);
|
||||
EditMode getEditMode() const { return this->editMode; }
|
||||
|
||||
bool getEditingLayout();
|
||||
bool getEditingLayout() const;
|
||||
|
||||
void setMapEditingButtonsEnabled(bool enabled);
|
||||
|
||||
|
|
@ -208,7 +207,8 @@ public:
|
|||
|
||||
public slots:
|
||||
void openMapScripts() const;
|
||||
void openScript(const QString &scriptLabel) const;
|
||||
bool openScript(const QString &scriptLabel) const;
|
||||
bool openScriptInFile(const QString &scriptLabel, const QString &filepath) const;
|
||||
void openProjectInTextEditor() const;
|
||||
void maskNonVisibleConnectionTiles();
|
||||
void onBorderMetatilesChanged();
|
||||
|
|
@ -251,26 +251,26 @@ private:
|
|||
QString getMovementPermissionText(uint16_t collision, uint16_t elevation);
|
||||
QString getMetatileDisplayMessage(uint16_t metatileId);
|
||||
void setCollisionTabSpinBoxes(uint16_t collision, uint16_t elevation);
|
||||
void adjustStraightPathPos(QGraphicsSceneMouseEvent *event, LayoutPixmapItem *item, QPoint *pos) const;
|
||||
static bool startDetachedProcess(const QString &command,
|
||||
const QString &workingDirectory = QString(),
|
||||
qint64 *pid = nullptr);
|
||||
|
||||
private slots:
|
||||
bool canPaintMetatiles() const;
|
||||
void onMapStartPaint(QGraphicsSceneMouseEvent *event, LayoutPixmapItem *item);
|
||||
void onMapEndPaint(QGraphicsSceneMouseEvent *event, LayoutPixmapItem *item);
|
||||
void setStatusFromMapPos(const QPoint &pos);
|
||||
|
||||
private slots:
|
||||
void setSmartPathCursorMode(QGraphicsSceneMouseEvent *event);
|
||||
void setStraightPathCursorMode(QGraphicsSceneMouseEvent *event);
|
||||
void mouseEvent_map(QGraphicsSceneMouseEvent *event, LayoutPixmapItem *item);
|
||||
void mouseEvent_collision(QGraphicsSceneMouseEvent *event, CollisionPixmapItem *item);
|
||||
void setSelectedConnectionItem(ConnectionPixmapItem *connectionItem);
|
||||
void onHoveredMovementPermissionChanged(uint16_t, uint16_t);
|
||||
void onHoveredMovementPermissionCleared();
|
||||
void onHoveredMetatileSelectionChanged(uint16_t);
|
||||
void onHoveredMetatileSelectionCleared();
|
||||
void onHoveredMapMetatileChanged(const QPoint &pos);
|
||||
void onHoveredMapMetatileCleared();
|
||||
void onHoveredMapMovementPermissionChanged(int, int);
|
||||
void onHoveredMapMovementPermissionCleared();
|
||||
void onMapHoverEntered(const QPoint &pos);
|
||||
void onMapHoverChanged(const QPoint &pos);
|
||||
void onMapHoverCleared();
|
||||
void onSelectedMetatilesChanged();
|
||||
void onWheelZoom(int);
|
||||
|
||||
|
|
@ -283,7 +283,6 @@ signals:
|
|||
void wildMonTableEdited();
|
||||
void currentMetatilesSelectionChanged();
|
||||
void mapRulerStatusChanged(const QString &);
|
||||
void tilesetUpdated(QString);
|
||||
void gridToggled(bool);
|
||||
void editActionSet(EditAction newEditAction);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QCloseEvent>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QJSValue>
|
||||
#include "project.h"
|
||||
#include "orderedjson.h"
|
||||
#include "config.h"
|
||||
|
|
@ -36,6 +35,10 @@
|
|||
#include "message.h"
|
||||
#include "resizelayoutpopup.h"
|
||||
|
||||
#if __has_include(<QJSValue>)
|
||||
#include <QJSValue>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace Ui {
|
||||
|
|
@ -56,9 +59,14 @@ public:
|
|||
|
||||
void initialize();
|
||||
|
||||
Q_INVOKABLE void setPrimaryTileset(const QString &tileset);
|
||||
Q_INVOKABLE void setSecondaryTileset(const QString &tileset);
|
||||
|
||||
// Scripting API
|
||||
#ifdef QT_QML_LIB
|
||||
Q_INVOKABLE QJSValue getBlock(int x, int y);
|
||||
void tryRedrawMapArea(bool forceRedraw);
|
||||
void redrawResizedMapArea();
|
||||
void tryCommitMapChanges(bool commitChanges);
|
||||
Q_INVOKABLE void setBlock(int x, int y, int metatileId, int collision, int elevation, bool forceRedraw = true, bool commitChanges = true);
|
||||
Q_INVOKABLE void setBlock(int x, int y, int rawValue, bool forceRedraw = true, bool commitChanges = true);
|
||||
|
|
@ -118,8 +126,6 @@ public:
|
|||
Q_INVOKABLE int getNumSecondaryTilesetTiles();
|
||||
Q_INVOKABLE QString getPrimaryTileset();
|
||||
Q_INVOKABLE QString getSecondaryTileset();
|
||||
Q_INVOKABLE void setPrimaryTileset(QString tileset);
|
||||
Q_INVOKABLE void setSecondaryTileset(QString tileset);
|
||||
void saveMetatilesByMetatileId(int metatileId);
|
||||
void saveMetatileAttributesByMetatileId(int metatileId);
|
||||
Metatile * getMetatile(int metatileId);
|
||||
|
|
@ -145,6 +151,10 @@ public:
|
|||
Q_INVOKABLE void setMetatileTiles(int metatileId, QJSValue tilesObj, int tileStart = 0, int tileEnd = -1, bool forceRedraw = true);
|
||||
Q_INVOKABLE void setMetatileTiles(int metatileId, int tileId, bool xflip, bool yflip, int palette, int tileStart = 0, int tileEnd = -1, bool forceRedraw = true);
|
||||
Q_INVOKABLE QJSValue getTilePixels(int tileId);
|
||||
Q_INVOKABLE QList<int> getMetatileLayerOrder() const;
|
||||
Q_INVOKABLE void setMetatileLayerOrder(const QList<int> &order);
|
||||
Q_INVOKABLE QList<float> getMetatileLayerOpacity() const;
|
||||
Q_INVOKABLE void setMetatileLayerOpacity(const QList<float> &opacities);
|
||||
Q_INVOKABLE QString getSong();
|
||||
Q_INVOKABLE void setSong(QString song);
|
||||
Q_INVOKABLE QString getLocation();
|
||||
|
|
@ -167,6 +177,7 @@ public:
|
|||
Q_INVOKABLE void setAllowEscaping(bool allow);
|
||||
Q_INVOKABLE int getFloorNumber();
|
||||
Q_INVOKABLE void setFloorNumber(int floorNumber);
|
||||
#endif // QT_QML_LIB
|
||||
|
||||
public slots:
|
||||
void on_mainTabBar_tabBarClicked(int index);
|
||||
|
|
@ -246,8 +257,6 @@ private slots:
|
|||
void on_pushButton_AddConnection_clicked();
|
||||
void on_button_OpenDiveMap_clicked();
|
||||
void on_button_OpenEmergeMap_clicked();
|
||||
void on_comboBox_PrimaryTileset_currentTextChanged(const QString &arg1);
|
||||
void on_comboBox_SecondaryTileset_currentTextChanged(const QString &arg1);
|
||||
void on_pushButton_ChangeDimensions_clicked();
|
||||
|
||||
void resetMapViewScale();
|
||||
|
|
@ -286,6 +295,7 @@ private slots:
|
|||
void on_spinBox_SelectedCollision_valueChanged(int collision);
|
||||
void on_actionRegion_Map_Editor_triggered();
|
||||
void on_actionPreferences_triggered();
|
||||
void on_actionOpen_Manual_triggered();
|
||||
void on_actionCheck_for_Updates_triggered();
|
||||
void togglePreferenceSpecificUi();
|
||||
void on_actionProject_Settings_triggered();
|
||||
|
|
@ -321,8 +331,11 @@ private:
|
|||
QPointer<FilterChildrenProxyModel> layoutListProxyModel = nullptr;
|
||||
QPointer<LayoutTreeModel> layoutTreeModel = nullptr;
|
||||
|
||||
#ifdef QT_NETWORK_LIB
|
||||
QPointer<UpdatePromoter> updatePromoter = nullptr;
|
||||
QPointer<NetworkAccessManager> networkAccessManager = nullptr;
|
||||
#endif
|
||||
|
||||
QPointer<AboutPorymap> aboutWindow = nullptr;
|
||||
QPointer<WildMonChart> wildMonChart = nullptr;
|
||||
QPointer<WildMonSearch> wildMonSearch = nullptr;
|
||||
|
|
@ -380,7 +393,6 @@ private:
|
|||
void openDuplicateMapOrLayoutDialog();
|
||||
void openNewMapGroupDialog();
|
||||
void openNewLocationDialog();
|
||||
void openSubWindow(QWidget * window);
|
||||
void scrollMapList(MapTree *list, const QString &itemName);
|
||||
void scrollMapListToCurrentMap(MapTree *list);
|
||||
void scrollMapListToCurrentLayout(MapTree *list);
|
||||
|
|
|
|||
|
|
@ -61,7 +61,6 @@ public:
|
|||
QMap<QString, uint32_t> metatileBehaviorMap;
|
||||
QMap<uint32_t, QString> metatileBehaviorMapInverse;
|
||||
ParseUtil parser;
|
||||
QFileSystemWatcher fileWatcher;
|
||||
QSet<QString> modifiedFiles;
|
||||
bool usingAsmTilesets;
|
||||
QSet<QString> disabledSettingsNames;
|
||||
|
|
@ -105,11 +104,12 @@ public:
|
|||
bool load();
|
||||
|
||||
QMap<QString, Tileset*> tilesetCache;
|
||||
Tileset* loadTileset(QString, Tileset *tileset = nullptr);
|
||||
Tileset* getTileset(QString, bool forceLoad = false);
|
||||
Tileset* getTileset(const QString&, bool forceLoad = false);
|
||||
QStringList primaryTilesetLabels;
|
||||
QStringList secondaryTilesetLabels;
|
||||
QStringList tilesetLabelsOrdered;
|
||||
QSet<QString> getPairedTilesetLabels(const Tileset *tileset) const;
|
||||
QSet<QString> getTilesetLayoutIds(const Tileset *priamryTileset, const Tileset *secondaryTileset) const;
|
||||
|
||||
bool readMapGroups();
|
||||
void addNewMapGroup(const QString &groupName);
|
||||
|
|
@ -216,7 +216,11 @@ public:
|
|||
|
||||
static QString getScriptFileExtension(bool usePoryScript);
|
||||
QString getScriptDefaultString(bool usePoryScript, QString mapName) const;
|
||||
QStringList getEventScriptsFilepaths() const;
|
||||
|
||||
QStringList getAllEventScriptsFilepaths() const;
|
||||
QStringList getMapScriptsFilepaths() const;
|
||||
QStringList getCommonEventScriptsFilepaths() const;
|
||||
QStringList findScriptsFiles(const QString &searchDir, const QStringList &fileNames = {"*"}) const;
|
||||
void insertGlobalScriptLabels(QStringList &scriptLabels) const;
|
||||
|
||||
QString getDefaultPrimaryTilesetLabel() const;
|
||||
|
|
@ -252,17 +256,22 @@ public:
|
|||
static QString getDynamicMapDefineName();
|
||||
static QString getDynamicMapName();
|
||||
static QString getEmptySpeciesName();
|
||||
static QMargins getPixelViewDistance();
|
||||
static QMargins getMetatileViewDistance();
|
||||
static int getNumTilesPrimary() { return num_tiles_primary; }
|
||||
static int getNumTilesTotal() { return num_tiles_total; }
|
||||
static int getNumTilesSecondary() { return getNumTilesTotal() - getNumTilesPrimary(); }
|
||||
static int getNumMetatilesPrimary() { return num_metatiles_primary; }
|
||||
static int getNumMetatilesTotal() { return Block::getMaxMetatileId() + 1; }
|
||||
static int getNumMetatilesSecondary() { return getNumMetatilesTotal() - getNumMetatilesPrimary(); }
|
||||
static int getNumPalettesPrimary(){ return num_pals_primary; }
|
||||
static int getNumPalettesTotal() { return num_pals_total; }
|
||||
static int getNumPalettesSecondary() { return getNumPalettesTotal() - getNumPalettesPrimary(); }
|
||||
static QString getEmptyMapsecName();
|
||||
static QString getMapGroupPrefix();
|
||||
|
||||
private:
|
||||
QPointer<QFileSystemWatcher> fileWatcher;
|
||||
QMap<QString, qint64> modifiedFileTimestamps;
|
||||
QMap<QString, QString> facingDirections;
|
||||
QHash<QString, QString> speciesToIconPath;
|
||||
|
|
@ -332,6 +341,9 @@ private:
|
|||
void ignoreWatchedFilesTemporarily(const QStringList &filepaths);
|
||||
void recordFileChange(const QString &filepath);
|
||||
void resetFileCache();
|
||||
void resetFileWatcher();
|
||||
void logFileWatchStatus();
|
||||
void cacheTileset(const QString &label, Tileset *tileset);
|
||||
|
||||
bool saveMapLayouts();
|
||||
bool saveMapGroups();
|
||||
|
|
|
|||
|
|
@ -2,12 +2,19 @@
|
|||
#ifndef SCRIPTING_H
|
||||
#define SCRIPTING_H
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "block.h"
|
||||
#include <QStringList>
|
||||
#include "scriptutility.h"
|
||||
|
||||
#include <QStringList>
|
||||
class Block;
|
||||
class Tile;
|
||||
class MainWindow;
|
||||
|
||||
#if __has_include(<QJSEngine>)
|
||||
#include <QJSEngine>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef QT_QML_LIB
|
||||
|
||||
// !! New callback functions or changes to existing callback function names/arguments
|
||||
// should be synced to resources/text/script_template.txt and docsrc/manual/scripting-capabilities.rst
|
||||
|
|
@ -51,7 +58,7 @@ public:
|
|||
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_TilesetUpdated(const QString &tilesetName);
|
||||
static void cb_MainTabChanged(int oldTab, int newTab);
|
||||
static void cb_MapViewTabChanged(int oldTab, int newTab);
|
||||
static void cb_BorderVisibilityToggled(bool visible);
|
||||
|
|
@ -78,4 +85,34 @@ private:
|
|||
void invokeCallback(CallbackType type, QJSValueList args);
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class Scripting
|
||||
{
|
||||
public:
|
||||
Scripting(MainWindow *) {}
|
||||
~Scripting() {}
|
||||
static void init(MainWindow *) {}
|
||||
static void stop() {}
|
||||
static void populateGlobalObject(MainWindow *) {}
|
||||
|
||||
static void cb_ProjectOpened(QString) {};
|
||||
static void cb_ProjectClosed(QString) {};
|
||||
static void cb_MetatileChanged(int, int, Block, Block) {};
|
||||
static void cb_BorderMetatileChanged(int, int, uint16_t, uint16_t) {};
|
||||
static void cb_BlockHoverChanged(int, int) {};
|
||||
static void cb_BlockHoverCleared() {};
|
||||
static void cb_MapOpened(QString) {};
|
||||
static void cb_LayoutOpened(QString) {};
|
||||
static void cb_MapResized(int, int, const QMargins &) {};
|
||||
static void cb_BorderResized(int, int, int, int) {};
|
||||
static void cb_MapShifted(int, int) {};
|
||||
static void cb_TilesetUpdated(const QString &) {};
|
||||
static void cb_MainTabChanged(int, int) {};
|
||||
static void cb_MapViewTabChanged(int, int) {};
|
||||
static void cb_BorderVisibilityToggled(bool) {};
|
||||
};
|
||||
|
||||
#endif // QT_QML_LIB
|
||||
|
||||
#endif // SCRIPTING_H
|
||||
|
|
|
|||
|
|
@ -2,14 +2,24 @@
|
|||
#ifndef SCRIPTUTILITY_H
|
||||
#define SCRIPTUTILITY_H
|
||||
|
||||
#include "mainwindow.h"
|
||||
#if __has_include(<QJSValue>)
|
||||
#include <QJSValue>
|
||||
#endif
|
||||
|
||||
#ifdef QT_QML_LIB
|
||||
|
||||
#include <QAction>
|
||||
#include <QMessageBox>
|
||||
#include <QSet>
|
||||
#include <QTimer>
|
||||
|
||||
class MainWindow;
|
||||
|
||||
class ScriptUtility : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ScriptUtility(MainWindow *mainWindow);
|
||||
ScriptUtility(MainWindow *mainWindow) : window(mainWindow) {}
|
||||
~ScriptUtility();
|
||||
|
||||
QString getActionFunctionName(int actionIndex);
|
||||
|
|
@ -38,9 +48,9 @@ public:
|
|||
Q_INVOKABLE bool getSmartPathsEnabled();
|
||||
Q_INVOKABLE QList<QString> getCustomScripts();
|
||||
Q_INVOKABLE QList<int> getMetatileLayerOrder();
|
||||
Q_INVOKABLE void setMetatileLayerOrder(QList<int> order);
|
||||
Q_INVOKABLE void setMetatileLayerOrder(const QList<int> &order);
|
||||
Q_INVOKABLE QList<float> getMetatileLayerOpacity();
|
||||
Q_INVOKABLE void setMetatileLayerOpacity(QList<float> order);
|
||||
Q_INVOKABLE void setMetatileLayerOpacity(const QList<float> &order);
|
||||
Q_INVOKABLE QList<QString> getMapNames();
|
||||
Q_INVOKABLE QList<QString> getMapConstants();
|
||||
Q_INVOKABLE QList<QString> getLayoutNames();
|
||||
|
|
@ -57,6 +67,8 @@ public:
|
|||
Q_INVOKABLE bool isPrimaryTileset(QString tilesetName);
|
||||
Q_INVOKABLE bool isSecondaryTileset(QString tilesetName);
|
||||
|
||||
static bool validateMetatileLayerOrder(const QList<int> &order);
|
||||
|
||||
private:
|
||||
void callTimeoutFunction(QJSValue callback);
|
||||
void runMessageBox(QString text, QString informativeText, QString detailedText, QMessageBox::Icon icon);
|
||||
|
|
@ -67,4 +79,6 @@ private:
|
|||
QHash<int, QString> actionMap;
|
||||
};
|
||||
|
||||
#endif // QT_QML_LIB
|
||||
|
||||
#endif // SCRIPTUTILITY_H
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ public:
|
|||
Settings();
|
||||
bool smartPathsEnabled;
|
||||
bool betterCursors;
|
||||
QCursor mapCursor;
|
||||
bool playerViewRectEnabled;
|
||||
bool cursorTileRectEnabled;
|
||||
};
|
||||
|
|
|
|||
39
include/ui/checkeredbgscene.h
Normal file
39
include/ui/checkeredbgscene.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef CHECKEREDBGSCENE_H
|
||||
#define CHECKEREDBGSCENE_H
|
||||
|
||||
#include <QGraphicsScene>
|
||||
|
||||
// Custom scene that paints its background a gray checkered pattern.
|
||||
// Additionally there is a definable "valid" area which will paint the checkerboard green inside.
|
||||
class CheckeredBgScene : public QGraphicsScene {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CheckeredBgScene(const QSize &gridSize, QObject *parent = nullptr)
|
||||
: QGraphicsScene(parent),
|
||||
gridSize(gridSize)
|
||||
{};
|
||||
CheckeredBgScene(int width, int height, QObject *parent = nullptr)
|
||||
: CheckeredBgScene(QSize(width, height), parent)
|
||||
{};
|
||||
|
||||
void setValidRect(int x, int y, int width, int height) {
|
||||
this->validRect = QRect(x * this->gridSize.width(),
|
||||
y * this->gridSize.height(),
|
||||
width * this->gridSize.width(),
|
||||
height * this->gridSize.height());
|
||||
}
|
||||
void setValidRect(const QRect &rect) {
|
||||
this->validRect = rect;
|
||||
}
|
||||
QRect getValidRect() { return this->validRect; }
|
||||
|
||||
protected:
|
||||
void drawBackground(QPainter *painter, const QRectF &rect) override;
|
||||
|
||||
private:
|
||||
QSize gridSize;
|
||||
QRect validRect;
|
||||
};
|
||||
|
||||
#endif // CHECKEREDBGSCENE_H
|
||||
|
|
@ -23,29 +23,14 @@ public:
|
|||
QSpinBox * selectedElevation;
|
||||
qreal *opacity;
|
||||
void updateMovementPermissionSelection(QGraphicsSceneMouseEvent *event);
|
||||
virtual void paint(QGraphicsSceneMouseEvent*);
|
||||
virtual void floodFill(QGraphicsSceneMouseEvent*);
|
||||
virtual void magicFill(QGraphicsSceneMouseEvent*);
|
||||
virtual void pick(QGraphicsSceneMouseEvent*);
|
||||
void draw(bool ignoreCache = false);
|
||||
virtual void paint(QGraphicsSceneMouseEvent*) override;
|
||||
virtual void floodFill(QGraphicsSceneMouseEvent*) override;
|
||||
virtual void magicFill(QGraphicsSceneMouseEvent*) override;
|
||||
virtual void pick(QGraphicsSceneMouseEvent*) override;
|
||||
void draw(bool ignoreCache = false) override;
|
||||
|
||||
private:
|
||||
unsigned actionId_ = 0;
|
||||
QPoint previousPos;
|
||||
void updateSelection(QPoint pos);
|
||||
|
||||
signals:
|
||||
void mouseEvent(QGraphicsSceneMouseEvent *, CollisionPixmapItem *);
|
||||
void hoveredMapMovementPermissionChanged(int, int);
|
||||
void hoveredMapMovementPermissionCleared();
|
||||
|
||||
protected:
|
||||
void hoverMoveEvent(QGraphicsSceneHoverEvent*);
|
||||
void hoverEnterEvent(QGraphicsSceneHoverEvent*);
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent*);
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent*);
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent*);
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent*);
|
||||
};
|
||||
|
||||
#endif // COLLISIONPIXMAPITEM_H
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#define CONNECTIONPIXMAPITEM_H
|
||||
|
||||
#include "mapconnection.h"
|
||||
#include "metatile.h"
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QPainter>
|
||||
#include <QPointer>
|
||||
|
|
@ -31,8 +32,8 @@ private:
|
|||
bool selected = false;
|
||||
unsigned actionId = 0;
|
||||
|
||||
static const int mWidth = 16;
|
||||
static const int mHeight = 16;
|
||||
static const int mWidth = Metatile::pixelWidth();
|
||||
static const int mHeight = Metatile::pixelHeight();
|
||||
|
||||
void updatePos();
|
||||
void updateOrigin();
|
||||
|
|
|
|||
|
|
@ -8,78 +8,56 @@
|
|||
class CursorTileRect : public QGraphicsItem
|
||||
{
|
||||
public:
|
||||
CursorTileRect(bool *enabled, QRgb color);
|
||||
QRectF boundingRect() const override
|
||||
{
|
||||
int width = this->width;
|
||||
int height = this->height;
|
||||
if (this->singleTileMode) {
|
||||
width = 16;
|
||||
height = 16;
|
||||
} else if (!this->rightClickSelectionAnchored && this->smartPathMode && this->selectionHeight == 3 && this->selectionWidth == 3) {
|
||||
width = 32;
|
||||
height = 32;
|
||||
}
|
||||
CursorTileRect(const QSize &tileSize, const QRgb &color, QGraphicsItem *parent = nullptr);
|
||||
|
||||
QSize size() const;
|
||||
|
||||
QRectF boundingRect() const override {
|
||||
auto s = size();
|
||||
qreal penWidth = 4;
|
||||
return QRectF(-penWidth,
|
||||
-penWidth,
|
||||
width + penWidth * 2,
|
||||
height + penWidth * 2);
|
||||
s.width() + penWidth * 2,
|
||||
s.height() + penWidth * 2);
|
||||
}
|
||||
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) override
|
||||
{
|
||||
if (!(*enabled)) return;
|
||||
int width = this->width;
|
||||
int height = this->height;
|
||||
if (this->singleTileMode) {
|
||||
width = 16;
|
||||
height = 16;
|
||||
} else if (this->smartPathInEffect()) {
|
||||
width = 32;
|
||||
height = 32;
|
||||
}
|
||||
|
||||
painter->setPen(this->color);
|
||||
painter->drawRect(x() - 1, y() - 1, width + 2, height + 2);
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) override {
|
||||
if (!isVisible()) return;
|
||||
auto rect = QRectF(pos(), size());
|
||||
painter->setPen(m_color);
|
||||
painter->drawRect(rect + QMargins(1,1,1,1)); // Fill
|
||||
painter->setPen(QColor(0, 0, 0));
|
||||
painter->drawRect(x() - 2, y() - 2, width + 4, height + 4);
|
||||
painter->drawRect(x(), y(), width, height);
|
||||
painter->drawRect(rect + QMargins(2,2,2,2)); // Outer border
|
||||
painter->drawRect(rect); // Inner border
|
||||
}
|
||||
|
||||
void initAnchor(int coordX, int coordY);
|
||||
void stopAnchor();
|
||||
void initRightClickSelectionAnchor(int coordX, int coordY);
|
||||
void stopRightClickSelectionAnchor();
|
||||
|
||||
void setSmartPathMode(bool enable) { this->smartPathMode = enable; }
|
||||
bool getSmartPathMode() const { return this->smartPathMode; }
|
||||
void setSmartPathMode(bool enable) { m_smartPathMode = enable; }
|
||||
bool getSmartPathMode() const { return m_smartPathMode; }
|
||||
|
||||
void setStraightPathMode(bool enable) { this->straightPathMode = enable; }
|
||||
bool getStraightPathMode() const { return this->straightPathMode; }
|
||||
|
||||
void setSingleTileMode(bool enable) { this->singleTileMode = enable; }
|
||||
bool getSingleTileMode() const { return this->singleTileMode; }
|
||||
void setSingleTileMode(bool enable) { m_singleTileMode = enable; }
|
||||
bool getSingleTileMode() const { return m_singleTileMode; }
|
||||
|
||||
void updateLocation(int x, int y);
|
||||
void updateSelectionSize(int width, int height);
|
||||
void setActive(bool active);
|
||||
bool getActive();
|
||||
bool *enabled;
|
||||
void updateSelectionSize(const QSize &size);
|
||||
void updateSelectionSize(int width, int height) { updateSelectionSize(QSize(width, height)); }
|
||||
|
||||
private:
|
||||
bool active;
|
||||
int width;
|
||||
int height;
|
||||
bool anchored;
|
||||
bool rightClickSelectionAnchored;
|
||||
bool smartPathMode;
|
||||
bool straightPathMode;
|
||||
bool singleTileMode;
|
||||
int anchorCoordX;
|
||||
int anchorCoordY;
|
||||
int selectionWidth;
|
||||
int selectionHeight;
|
||||
QRgb color;
|
||||
bool smartPathInEffect();
|
||||
const QSize m_tileSize;
|
||||
QSize m_selectionSize;
|
||||
QPoint m_anchorCoord;
|
||||
QRgb m_color;
|
||||
|
||||
bool m_anchored = false;
|
||||
bool m_rightClickSelectionAnchored = false;
|
||||
bool m_smartPathMode = false;
|
||||
bool m_singleTileMode = false;
|
||||
|
||||
bool smartPathInEffect() const;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,11 +4,26 @@
|
|||
#include <QGraphicsView>
|
||||
#include <QMouseEvent>
|
||||
|
||||
class NoScrollGraphicsView : public QGraphicsView
|
||||
// For general utility features that we add to QGraphicsView
|
||||
class GraphicsView : public QGraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NoScrollGraphicsView(QWidget *parent = nullptr) : QGraphicsView(parent) {}
|
||||
GraphicsView(QWidget *parent = nullptr) : QGraphicsView(parent) {}
|
||||
|
||||
void centerOn(const QGraphicsView *other) {
|
||||
if (other && other->viewport()) {
|
||||
QPoint center = other->viewport()->rect().center();
|
||||
QGraphicsView::centerOn(other->mapToScene(center));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class NoScrollGraphicsView : public GraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NoScrollGraphicsView(QWidget *parent = nullptr) : GraphicsView(parent) {}
|
||||
|
||||
protected:
|
||||
void wheelEvent(QWheelEvent *event) {
|
||||
|
|
@ -32,11 +47,11 @@ signals:
|
|||
void clicked(QMouseEvent *event);
|
||||
};
|
||||
|
||||
class ConnectionsView : public QGraphicsView
|
||||
class ConnectionsView : public GraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ConnectionsView(QWidget *parent = nullptr) : QGraphicsView(parent) {}
|
||||
ConnectionsView(QWidget *parent = nullptr) : GraphicsView(parent) {}
|
||||
|
||||
signals:
|
||||
void pressedDelete();
|
||||
|
|
|
|||
|
|
@ -6,13 +6,40 @@
|
|||
#include <QImage>
|
||||
#include <QPixmap>
|
||||
|
||||
class Layout;
|
||||
|
||||
QImage getCollisionMetatileImage(Block);
|
||||
QImage getCollisionMetatileImage(int, int);
|
||||
QImage getMetatileImage(uint16_t, Tileset*, Tileset*, const QList<int>&, const QList<float>&, bool useTruePalettes = false);
|
||||
QImage getMetatileImage(Metatile*, Tileset*, Tileset*, const QList<int>&, const QList<float>&, bool useTruePalettes = false);
|
||||
QImage getTileImage(uint16_t, Tileset*, Tileset*);
|
||||
QImage getPalettedTileImage(uint16_t, Tileset*, Tileset*, int, bool useTruePalettes = false);
|
||||
QImage getGreyscaleTileImage(uint16_t tile, Tileset *primaryTileset, Tileset *secondaryTileset);
|
||||
|
||||
QImage getMetatileImage(uint16_t, const Layout*, bool useTruePalettes = false);
|
||||
QImage getMetatileImage(const Metatile*, const Layout*, bool useTruePalettes = false);
|
||||
QImage getMetatileImage(uint16_t, const Tileset*, const Tileset*, const QList<int>& = {0,1,2}, const QList<float>& = {}, bool useTruePalettes = false);
|
||||
QImage getMetatileImage(const Metatile*, const Tileset*, const Tileset*, const QList<int>& = {0,1,2}, const QList<float>& = {}, bool useTruePalettes = false);
|
||||
|
||||
QImage getMetatileSheetImage(const Layout *layout, int numMetatilesWIde, bool useTruePalettes = false);
|
||||
QImage getMetatileSheetImage(const Tileset *primaryTileset,
|
||||
const Tileset *secondaryTileset,
|
||||
uint16_t metatileIdStart,
|
||||
uint16_t metatileIdEnd,
|
||||
int numMetatilesWIde,
|
||||
const QList<int> &layerOrder,
|
||||
const QList<float> &layerOpacity = {},
|
||||
const QSize &metatileSize = Metatile::pixelSize(),
|
||||
bool useTruePalettes = false);
|
||||
QImage getMetatileSheetImage(const Tileset *primaryTileset,
|
||||
const Tileset *secondaryTileset,
|
||||
int numMetatilesWide,
|
||||
const QList<int> &layerOrder,
|
||||
const QList<float> &layerOpacity = {},
|
||||
const QSize &metatileSize = Metatile::pixelSize(),
|
||||
bool useTruePalettes = false);
|
||||
|
||||
|
||||
QImage getTileImage(uint16_t, const Tileset*, const Tileset*);
|
||||
QImage getPalettedTileImage(uint16_t, const Tileset*, const Tileset*, int, bool useTruePalettes = false);
|
||||
QImage getColoredTileImage(uint16_t tileId, const Tileset *, const Tileset *, const QList<QRgb> &palette);
|
||||
QImage getGreyscaleTileImage(uint16_t tileId, const Tileset *, const Tileset *);
|
||||
|
||||
void flattenTo4bppImage(QImage * image);
|
||||
|
||||
static QList<QRgb> greyscalePalette({
|
||||
|
|
|
|||
|
|
@ -61,20 +61,22 @@ public:
|
|||
void magicFill(
|
||||
int initialX,
|
||||
int initialY,
|
||||
QPoint selectionDimensions,
|
||||
QList<MetatileSelectionItem> selectedMetatiles,
|
||||
QList<CollisionSelectionItem> selectedCollisions,
|
||||
const QSize &selectionDimensions,
|
||||
const QList <MetatileSelectionItem> &selectedMetatiles,
|
||||
const QList <CollisionSelectionItem> &selectedCollisions,
|
||||
bool fromScriptCall = false);
|
||||
void floodFill(int x, int y, bool fromScriptCall = false);
|
||||
void floodFill(int x, int y, uint16_t metatileId, bool fromScriptCall = false);
|
||||
void floodFill(int initialX,
|
||||
int initialY,
|
||||
QPoint selectionDimensions,
|
||||
QList<MetatileSelectionItem> selectedMetatiles,
|
||||
QList<CollisionSelectionItem> selectedCollisions,
|
||||
const QSize &selectionDimensions,
|
||||
const QList<MetatileSelectionItem> &selectedMetatiles,
|
||||
const QList<CollisionSelectionItem> &selectedCollisions,
|
||||
bool fromScriptCall = false);
|
||||
void floodFillSmartPath(int initialX, int initialY, bool fromScriptCall = false);
|
||||
|
||||
static bool isSmartPathSize(const QSize &size) { return size.width() == smartPathWidth && size.height() == smartPathHeight; }
|
||||
|
||||
virtual void pick(QGraphicsSceneMouseEvent*);
|
||||
virtual void select(QGraphicsSceneMouseEvent*);
|
||||
virtual void shift(QGraphicsSceneMouseEvent*);
|
||||
|
|
@ -86,32 +88,33 @@ public:
|
|||
void lockNondominantAxis(QGraphicsSceneMouseEvent *event);
|
||||
QPoint adjustCoords(QPoint pos);
|
||||
|
||||
void setEditsEnabled(bool enabled) { this->editsEnabled = enabled; }
|
||||
bool getEditsEnabled() { return this->editsEnabled; }
|
||||
protected:
|
||||
unsigned actionId_ = 0;
|
||||
|
||||
private:
|
||||
void paintSmartPath(int x, int y, bool fromScriptCall = false);
|
||||
static bool isValidSmartPathSelection(MetatileSelection selection);
|
||||
static QList<int> smartPathTable;
|
||||
static constexpr int smartPathWidth = 3;
|
||||
static constexpr int smartPathHeight = 3;
|
||||
static constexpr int smartPathMiddleIndex = (smartPathWidth / 2) + ((smartPathHeight / 2) * smartPathWidth);
|
||||
QPoint lastMetatileSelectionPos = QPoint(-1,-1);
|
||||
|
||||
unsigned actionId_ = 0;
|
||||
|
||||
bool editsEnabled = true;
|
||||
|
||||
signals:
|
||||
void startPaint(QGraphicsSceneMouseEvent *, LayoutPixmapItem *);
|
||||
void endPaint(QGraphicsSceneMouseEvent *, LayoutPixmapItem *);
|
||||
void mouseEvent(QGraphicsSceneMouseEvent *, LayoutPixmapItem *);
|
||||
void hoveredMapMetatileChanged(const QPoint &pos);
|
||||
void hoveredMapMetatileCleared();
|
||||
void hoverEntered(const QPoint &pos);
|
||||
void hoverChanged(const QPoint &pos);
|
||||
void hoverCleared();
|
||||
|
||||
protected:
|
||||
void hoverMoveEvent(QGraphicsSceneHoverEvent*);
|
||||
void hoverEnterEvent(QGraphicsSceneHoverEvent*);
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent*);
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent*);
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent*);
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent*);
|
||||
virtual void hoverMoveEvent(QGraphicsSceneHoverEvent*) override;
|
||||
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent*) override;
|
||||
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent*) override;
|
||||
virtual void mousePressEvent(QGraphicsSceneMouseEvent*) override;
|
||||
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent*) override;
|
||||
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent*) override;
|
||||
};
|
||||
|
||||
#endif // MAPPIXMAPITEM_H
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#define MAPIMAGEEXPORTER_H
|
||||
|
||||
#include "project.h"
|
||||
#include "checkeredbgscene.h"
|
||||
|
||||
class QGifImage;
|
||||
|
||||
|
|
@ -52,7 +53,7 @@ private:
|
|||
Project *m_project = nullptr;
|
||||
Map *m_map = nullptr;
|
||||
Layout *m_layout = nullptr;
|
||||
QGraphicsScene *m_scene = nullptr;
|
||||
CheckeredBgScene *m_scene = nullptr;
|
||||
QGifImage *m_timelapseGifImage = nullptr;
|
||||
QBuffer *m_timelapseBuffer = nullptr;
|
||||
QMovie *m_timelapseMovie = nullptr;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <QGraphicsObject>
|
||||
#include <QLine>
|
||||
#include "metatile.h"
|
||||
|
||||
|
||||
class MapRuler : public QGraphicsObject, private QLine
|
||||
|
|
@ -63,8 +64,8 @@ private:
|
|||
QPoint snapToWithinBounds(QPoint pos) const;
|
||||
void updateGeometry();
|
||||
void updateStatus(Qt::Corner corner);
|
||||
int pixWidth() const { return width() * 16; }
|
||||
int pixHeight() const { return height() * 16; }
|
||||
int pixWidth() const { return width() * Metatile::pixelWidth(); }
|
||||
int pixHeight() const { return height() * Metatile::pixelHeight(); }
|
||||
};
|
||||
|
||||
#endif // MAPRULER_H
|
||||
|
|
|
|||
|
|
@ -1,20 +1,23 @@
|
|||
#ifndef MAPVIEW_H
|
||||
#define MAPVIEW_H
|
||||
|
||||
#if __has_include(<QJSValue>)
|
||||
#include <QJSValue>
|
||||
#endif
|
||||
|
||||
#include "graphicsview.h"
|
||||
#include "overlay.h"
|
||||
#include "tile.h"
|
||||
|
||||
class Editor;
|
||||
|
||||
class MapView : public QGraphicsView
|
||||
class MapView : public GraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MapView() : QGraphicsView() {}
|
||||
MapView(QWidget *parent) : QGraphicsView(parent) {}
|
||||
MapView() : GraphicsView() {}
|
||||
MapView(QWidget *parent) : GraphicsView(parent) {}
|
||||
|
||||
Editor *editor;
|
||||
|
||||
|
|
@ -22,6 +25,7 @@ public:
|
|||
void clearOverlayMap();
|
||||
|
||||
// Overlay scripting API
|
||||
#ifdef QT_QML_LIB
|
||||
Q_INVOKABLE void clear(int layer);
|
||||
Q_INVOKABLE void clear();
|
||||
Q_INVOKABLE void hide(int layer);
|
||||
|
|
@ -74,6 +78,7 @@ public:
|
|||
Q_INVOKABLE void addTileImage(int x, int y, int tileId, bool xflip, bool yflip, int paletteId, bool setTransparency = false, int layer = 0);
|
||||
Q_INVOKABLE void addTileImage(int x, int y, QJSValue tileObj, bool setTransparency = false, int layer = 0);
|
||||
Q_INVOKABLE void addMetatileImage(int x, int y, int metatileId, bool setTransparency = false, int layer = 0);
|
||||
#endif // QT_QML_LIB
|
||||
|
||||
protected:
|
||||
virtual void drawForeground(QPainter *painter, const QRectF &rect) override;
|
||||
|
|
|
|||
103
include/ui/metatileimageexporter.h
Normal file
103
include/ui/metatileimageexporter.h
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
#ifndef METATILEIMAGEEXPORTER_H
|
||||
#define METATILEIMAGEEXPORTER_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QShowEvent>
|
||||
#include <QCloseEvent>
|
||||
#include <QListWidget>
|
||||
#include <QDropEvent>
|
||||
#include <QRadioButton>
|
||||
|
||||
#include "config.h"
|
||||
#include "checkeredbgscene.h"
|
||||
|
||||
class Tileset;
|
||||
|
||||
namespace Ui {
|
||||
class MetatileImageExporter;
|
||||
}
|
||||
|
||||
class ReorderableListWidget : public QListWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ReorderableListWidget(QWidget *parent = nullptr) : QListWidget(parent) {
|
||||
setDragEnabled(true);
|
||||
setDragDropMode(QAbstractItemView::InternalMove);
|
||||
setDefaultDropAction(Qt::MoveAction);
|
||||
};
|
||||
|
||||
signals:
|
||||
void reordered();
|
||||
|
||||
protected:
|
||||
virtual void dropEvent(QDropEvent *event) override {
|
||||
QListWidget::dropEvent(event);
|
||||
if (event->isAccepted()) {
|
||||
emit reordered();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class MetatileImageExporter : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
struct Settings {
|
||||
OrderedMap<int,bool> layerOrder = {
|
||||
{2, true},
|
||||
{1, true},
|
||||
{0, true},
|
||||
};
|
||||
uint16_t metatileStart = 0;
|
||||
uint16_t metatileEnd = 0xFFFF;
|
||||
uint16_t numMetatilesWide = projectConfig.metatileSelectorWidth;
|
||||
bool usePrimaryTileset = true;
|
||||
bool useSecondaryTileset = false;
|
||||
bool renderPlaceholders = false;
|
||||
int transparencyMode = 0;
|
||||
};
|
||||
|
||||
explicit MetatileImageExporter(QWidget *parent, Tileset *primaryTileset, Tileset *secondaryTileset, Settings *savedSettings = nullptr);
|
||||
~MetatileImageExporter();
|
||||
|
||||
bool saveImage(QString filepath = QString());
|
||||
QImage getImage();
|
||||
QString getDefaultFileName() const;
|
||||
void applySettings(const Settings &settings);
|
||||
void reset();
|
||||
|
||||
protected:
|
||||
virtual void showEvent(QShowEvent *) override;
|
||||
virtual void closeEvent(QCloseEvent *) override;
|
||||
|
||||
private:
|
||||
Ui::MetatileImageExporter *ui;
|
||||
|
||||
Tileset *m_primaryTileset;
|
||||
Tileset *m_secondaryTileset;
|
||||
Settings *m_savedSettings;
|
||||
|
||||
CheckeredBgScene *m_scene = nullptr;
|
||||
QGraphicsPixmapItem *m_preview = nullptr;
|
||||
bool m_previewUpdateQueued = false;
|
||||
QList<int> m_layerOrder;
|
||||
ProjectConfig m_savedConfig;
|
||||
QList<QRadioButton*> m_transparencyButtons;
|
||||
|
||||
void populate(const Settings &settings);
|
||||
void updatePreview();
|
||||
void tryUpdatePreview();
|
||||
void queuePreviewUpdate();
|
||||
void tryEnforceMetatileRange();
|
||||
void syncPixelWidth();
|
||||
void syncMetatileWidth();
|
||||
void validateMetatileStart();
|
||||
void validateMetatileEnd();
|
||||
void updateMetatileRange();
|
||||
void copyRenderSettings();
|
||||
void restoreRenderSettings();
|
||||
};
|
||||
|
||||
#endif // METATILEIMAGEEXPORTER_H
|
||||
|
|
@ -9,38 +9,50 @@
|
|||
class MetatileLayersItem: public SelectablePixmapItem {
|
||||
Q_OBJECT
|
||||
public:
|
||||
MetatileLayersItem(Metatile *metatile, Tileset *primaryTileset, Tileset *secondaryTileset): SelectablePixmapItem(16, 16, 6, 2) {
|
||||
this->metatile = metatile;
|
||||
this->primaryTileset = primaryTileset;
|
||||
this->secondaryTileset = secondaryTileset;
|
||||
this->clearLastModifiedCoords();
|
||||
this->clearLastHoveredCoords();
|
||||
setAcceptHoverEvents(true);
|
||||
}
|
||||
void draw();
|
||||
MetatileLayersItem(Metatile *metatile,
|
||||
Tileset *primaryTileset,
|
||||
Tileset *secondaryTileset,
|
||||
Qt::Orientation orientation = Qt::Vertical);
|
||||
|
||||
void draw() override;
|
||||
void setTilesets(Tileset*, Tileset*);
|
||||
void setMetatile(Metatile*);
|
||||
void clearLastModifiedCoords();
|
||||
void clearLastHoveredCoords();
|
||||
|
||||
bool hasCursor() const { return this->cursorCellPos != QPoint(-1,-1); }
|
||||
Tile tileUnderCursor() const;
|
||||
|
||||
QPoint tileIndexToPos(int index) const { return this->tilePositions.value(index); }
|
||||
int posToTileIndex(const QPoint &pos) const { return this->tilePositions.indexOf(pos); }
|
||||
int posToTileIndex(int x, int y) const { return posToTileIndex(QPoint(x, y)); }
|
||||
|
||||
void setOrientation(Qt::Orientation orientation);
|
||||
|
||||
bool showGrid;
|
||||
private:
|
||||
Metatile* metatile;
|
||||
Tileset *primaryTileset;
|
||||
Tileset *secondaryTileset;
|
||||
QPoint prevChangedPos;
|
||||
QPoint prevHoveredPos;
|
||||
Qt::Orientation orientation;
|
||||
|
||||
QPoint cursorCellPos = QPoint(-1,-1);
|
||||
|
||||
QList<QPoint> tilePositions;
|
||||
|
||||
QPoint getBoundedPos(const QPointF &);
|
||||
void updateSelection();
|
||||
bool setCursorCellPos(const QPoint &pos);
|
||||
signals:
|
||||
void tileChanged(int, int);
|
||||
void selectedTilesChanged(QPoint, int, int);
|
||||
void hoveredTileChanged(uint16_t);
|
||||
void tileChanged(const QPoint &pos);
|
||||
void paletteChanged(const QPoint &pos);
|
||||
void selectedTilesChanged(const QPoint &pos, const QSize &dimensions);
|
||||
void hoveredTileChanged(const Tile &tile);
|
||||
void hoveredTileCleared();
|
||||
protected:
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent*);
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent*);
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent*);
|
||||
void hoverMoveEvent(QGraphicsSceneHoverEvent*);
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent*);
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent*) override;
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent*) override;
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent*) override;
|
||||
void hoverMoveEvent(QGraphicsSceneHoverEvent*) override;
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent*) override;
|
||||
};
|
||||
|
||||
#endif // METATILELAYERSITEM_H
|
||||
|
|
|
|||
|
|
@ -9,20 +9,20 @@
|
|||
|
||||
struct MetatileSelectionItem
|
||||
{
|
||||
bool enabled;
|
||||
uint16_t metatileId;
|
||||
bool enabled = false;
|
||||
uint16_t metatileId = 0;
|
||||
};
|
||||
|
||||
struct CollisionSelectionItem
|
||||
{
|
||||
bool enabled;
|
||||
uint16_t collision;
|
||||
uint16_t elevation;
|
||||
bool enabled = false;
|
||||
uint16_t collision = 0;
|
||||
uint16_t elevation = 0;
|
||||
};
|
||||
|
||||
struct MetatileSelection
|
||||
{
|
||||
QPoint dimensions;
|
||||
QSize dimensions;
|
||||
bool hasCollision;
|
||||
QList<MetatileSelectionItem> metatileItems;
|
||||
QList<CollisionSelectionItem> collisionItems;
|
||||
|
|
@ -31,33 +31,34 @@ struct MetatileSelection
|
|||
class MetatileSelector: public SelectablePixmapItem {
|
||||
Q_OBJECT
|
||||
public:
|
||||
MetatileSelector(int numMetatilesWide, Layout *layout): SelectablePixmapItem(16, 16) {
|
||||
MetatileSelector(int numMetatilesWide, Layout *layout)
|
||||
: SelectablePixmapItem(Metatile::pixelSize()),
|
||||
numMetatilesWide(qMax(numMetatilesWide, 1))
|
||||
{
|
||||
this->externalSelection = false;
|
||||
this->prefabSelection = false;
|
||||
this->numMetatilesWide = numMetatilesWide;
|
||||
this->layout = layout;
|
||||
this->primaryTileset = layout->tileset_primary;
|
||||
this->secondaryTileset = layout->tileset_secondary;
|
||||
this->selection = MetatileSelection{};
|
||||
this->cellPos = QPoint(-1, -1);
|
||||
setAcceptHoverEvents(true);
|
||||
}
|
||||
|
||||
QPoint getSelectionDimensions() override;
|
||||
QSize getSelectionDimensions() const override;
|
||||
void draw() override;
|
||||
void refresh();
|
||||
|
||||
bool select(uint16_t metatile);
|
||||
void selectFromMap(uint16_t metatileId, uint16_t collision, uint16_t elevation);
|
||||
void setTilesets(Tileset*, Tileset*);
|
||||
MetatileSelection getMetatileSelection();
|
||||
MetatileSelection getMetatileSelection() const { return this->selection; }
|
||||
void setPrefabSelection(MetatileSelection selection);
|
||||
void setExternalSelection(int, int, QList<uint16_t>, QList<QPair<uint16_t, uint16_t>>);
|
||||
QPoint getMetatileIdCoordsOnWidget(uint16_t);
|
||||
void setExternalSelection(int, int, const QList<uint16_t>&, const QList<QPair<uint16_t, uint16_t>>&);
|
||||
QPoint getMetatileIdCoordsOnWidget(uint16_t metatileId) const;
|
||||
void setLayout(Layout *layout);
|
||||
bool isInternalSelection() const { return (!this->externalSelection && !this->prefabSelection); }
|
||||
|
||||
Tileset *primaryTileset;
|
||||
Tileset *secondaryTileset;
|
||||
Tileset *primaryTileset() const { return this->layout->tileset_primary; }
|
||||
Tileset *secondaryTileset() const { return this->layout->tileset_secondary; }
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent*) override;
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent*) override;
|
||||
|
|
@ -66,10 +67,10 @@ protected:
|
|||
void hoverLeaveEvent(QGraphicsSceneHoverEvent*) override;
|
||||
void drawSelection() override;
|
||||
private:
|
||||
const int numMetatilesWide;
|
||||
QPixmap basePixmap;
|
||||
bool externalSelection;
|
||||
bool prefabSelection;
|
||||
int numMetatilesWide;
|
||||
Layout *layout;
|
||||
int externalSelectionWidth;
|
||||
int externalSelectionHeight;
|
||||
|
|
@ -80,8 +81,9 @@ private:
|
|||
void updateBasePixmap();
|
||||
void updateSelectedMetatiles();
|
||||
void updateExternalSelectedMetatiles();
|
||||
uint16_t getMetatileId(int x, int y) const;
|
||||
QPoint getMetatileIdCoords(uint16_t);
|
||||
uint16_t posToMetatileId(int x, int y, bool *ok = nullptr) const;
|
||||
uint16_t posToMetatileId(const QPoint &pos, bool *ok = nullptr) const;
|
||||
QPoint metatileIdToPos(uint16_t metatileId, bool *ok = nullptr) const;
|
||||
bool positionIsValid(const QPoint &pos) const;
|
||||
bool selectionIsValid();
|
||||
void hoverChanged();
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@ public slots:
|
|||
void setTabActive(int index, bool active = true);
|
||||
void deactivateTab(int tabIndex);
|
||||
|
||||
signals:
|
||||
void edited();
|
||||
|
||||
private:
|
||||
void actionCopyTab(int index);
|
||||
void actionAddDeleteTab(int index);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
class MovableRect : public QGraphicsRectItem
|
||||
{
|
||||
public:
|
||||
MovableRect(bool *enabled, const QRectF &rect, const QRgb &color);
|
||||
MovableRect(const QRectF &rect, const QSize &cellSize, const QRgb &color);
|
||||
QRectF boundingRect() const override {
|
||||
qreal penWidth = 4;
|
||||
return QRectF(-penWidth,
|
||||
|
|
@ -29,13 +29,9 @@ public:
|
|||
}
|
||||
void updateLocation(int x, int y);
|
||||
|
||||
void setActive(bool active);
|
||||
bool getActive() const { return this->active; }
|
||||
|
||||
protected:
|
||||
bool *enabled = nullptr;
|
||||
bool active = true;
|
||||
QRectF baseRect;
|
||||
QSize cellSize;
|
||||
QRgb color;
|
||||
|
||||
void updateVisibility();
|
||||
|
|
@ -48,7 +44,7 @@ class ResizableRect : public QObject, public MovableRect
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ResizableRect(QObject *parent, bool *enabled, int width, int height, QRgb color);
|
||||
ResizableRect(QObject *parent, const QSize &cellSize, const QSize &size, const QRgb &color);
|
||||
|
||||
QRectF boundingRect() const override {
|
||||
return QRectF(this->rect() + QMargins(lineWidth, lineWidth, lineWidth, lineWidth));
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public:
|
|||
void setSettings(const Layout::Settings &settings);
|
||||
Layout::Settings settings() const;
|
||||
|
||||
void setDisabled(bool disabled);
|
||||
void setDimensionsDisabled(bool disabled);
|
||||
|
||||
bool validate();
|
||||
|
||||
|
|
|
|||
20
include/ui/numericsorttableitem.h
Normal file
20
include/ui/numericsorttableitem.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef NUMERICSORTTABLEITEM_H
|
||||
#define NUMERICSORTTABLEITEM_H
|
||||
|
||||
#include <QTableWidgetItem>
|
||||
#include <QCollator>
|
||||
|
||||
class NumericSortTableItem : public QTableWidgetItem
|
||||
{
|
||||
public:
|
||||
explicit NumericSortTableItem(const QString &text) : QTableWidgetItem(text) {};
|
||||
|
||||
protected:
|
||||
virtual bool operator<(const QTableWidgetItem &other) const override {
|
||||
QCollator collator;
|
||||
collator.setNumericMode(true);
|
||||
return collator.compare(text(), other.text()) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // NUMERICSORTTABLEITEM_H
|
||||
|
|
@ -8,6 +8,8 @@
|
|||
#include <QStaticText>
|
||||
#include <QPainterPath>
|
||||
|
||||
#ifdef QT_QML_LIB
|
||||
|
||||
class OverlayItem {
|
||||
public:
|
||||
OverlayItem() {}
|
||||
|
|
@ -123,4 +125,17 @@ private:
|
|||
QRectF *clippingRect;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class Overlay
|
||||
{
|
||||
public:
|
||||
Overlay() {}
|
||||
~Overlay() {}
|
||||
|
||||
void renderItems(QPainter *) {}
|
||||
};
|
||||
|
||||
#endif // QT_QML_LIB
|
||||
|
||||
#endif // OVERLAY_H
|
||||
|
|
|
|||
67
include/ui/palettecolorsearch.h
Normal file
67
include/ui/palettecolorsearch.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
#ifndef PALETTECOLORSEARCH_H
|
||||
#define PALETTECOLORSEARCH_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QIcon>
|
||||
#include <QMap>
|
||||
|
||||
class Tileset;
|
||||
class Project;
|
||||
|
||||
namespace Ui {
|
||||
class PaletteColorSearch;
|
||||
}
|
||||
|
||||
class PaletteColorSearch : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PaletteColorSearch(Project *project,
|
||||
const Tileset *primaryTileset,
|
||||
const Tileset *secondaryTileset,
|
||||
QWidget *parent = nullptr);
|
||||
~PaletteColorSearch();
|
||||
|
||||
void setPaletteId(int paletteId);
|
||||
int currentPaletteId() const;
|
||||
|
||||
void setColorId(int colorId);
|
||||
int currentColorId() const;
|
||||
|
||||
void setTilesets(const Tileset *primaryTileset, const Tileset *secondaryTileset);
|
||||
const Tileset* currentTileset() const;
|
||||
|
||||
signals:
|
||||
void metatileSelected(uint16_t metatileId);
|
||||
void paletteIdChanged(int paletteId);
|
||||
|
||||
private:
|
||||
struct RowData {
|
||||
QString tilesetName;
|
||||
QString pairedTilesetName;
|
||||
QString metatileId;
|
||||
QIcon metatileIcon;
|
||||
};
|
||||
|
||||
enum ResultsColumn {
|
||||
TilesetName,
|
||||
Metatile,
|
||||
};
|
||||
|
||||
Ui::PaletteColorSearch *ui;
|
||||
Project *m_project;
|
||||
const Tileset *m_primaryTileset;
|
||||
const Tileset *m_secondaryTileset;
|
||||
|
||||
QMap<QString,QList<RowData>> m_resultsCache;
|
||||
|
||||
void addTableEntry(const RowData &rowData);
|
||||
QList<RowData> search(int colorId) const;
|
||||
QList<RowData> search(int colorId, const Tileset *tileset, const Tileset *pairedTileset) const;
|
||||
void refresh();
|
||||
void updateResults();
|
||||
void cellDoubleClicked(int row, int col);
|
||||
};
|
||||
|
||||
#endif // PALETTECOLORSEARCH_H
|
||||
|
|
@ -2,10 +2,12 @@
|
|||
#define PALETTEEDITOR_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QPointer>
|
||||
|
||||
#include "colorinputwidget.h"
|
||||
#include "project.h"
|
||||
#include "history.h"
|
||||
#include "palettecolorsearch.h"
|
||||
|
||||
namespace Ui {
|
||||
class PaletteEditor;
|
||||
|
|
@ -24,25 +26,40 @@ class PaletteEditor : public QMainWindow {
|
|||
public:
|
||||
explicit PaletteEditor(Project*, Tileset*, Tileset*, int paletteId, QWidget *parent = nullptr);
|
||||
~PaletteEditor();
|
||||
|
||||
void setPaletteId(int);
|
||||
int currentPaletteId() const;
|
||||
|
||||
void setTilesets(Tileset*, Tileset*);
|
||||
|
||||
bool showingUnusedColors() const;
|
||||
|
||||
signals:
|
||||
void metatileSelected(uint16_t metatileId);
|
||||
|
||||
private:
|
||||
Ui::PaletteEditor *ui;
|
||||
Project *project = nullptr;
|
||||
QList<ColorInputWidget*> colorInputs;
|
||||
|
||||
Project *project;
|
||||
Tileset *primaryTileset;
|
||||
Tileset *secondaryTileset;
|
||||
|
||||
QList<History<PaletteHistoryItem*>> palettesHistory;
|
||||
QList<ColorInputWidget*> colorInputs;
|
||||
QMap<int, History<PaletteHistoryItem*>> palettesHistory;
|
||||
QMap<int,QSet<int>> unusedColorCache;
|
||||
QPointer<PaletteColorSearch> colorSearchWindow;
|
||||
|
||||
Tileset* getTileset(int paletteId);
|
||||
Tileset* getTileset(int paletteId) const;
|
||||
void refreshColorInputs();
|
||||
void refreshPaletteId();
|
||||
void commitEditHistory();
|
||||
void commitEditHistory(int paletteId);
|
||||
void updateEditHistoryActions();
|
||||
void restoreWindowState();
|
||||
void invalidateCache();
|
||||
void closeEvent(QCloseEvent*);
|
||||
void setColorInputTitles(bool show);
|
||||
QSet<int> getUnusedColorIds();
|
||||
void openColorSearch();
|
||||
|
||||
void setRgb(int index, QRgb rgb);
|
||||
void setPalette(int paletteId, const QList<QRgb> &palette);
|
||||
|
|
@ -50,14 +67,13 @@ private:
|
|||
void setBitDepth(int bits);
|
||||
int bitDepth = 24;
|
||||
|
||||
static const int numColors = 16;
|
||||
static const int numColors = Tileset::numColorsPerPalette();
|
||||
|
||||
signals:
|
||||
void closed();
|
||||
void changedPaletteColor();
|
||||
void changedPalette(int);
|
||||
private slots:
|
||||
void on_spinBox_PaletteId_valueChanged(int arg1);
|
||||
void on_actionUndo_triggered();
|
||||
void on_actionRedo_triggered();
|
||||
void on_actionImport_Palette_triggered();
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#define PREFERENCES_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include "config.h"
|
||||
|
||||
class NoScrollComboBox;
|
||||
class QAbstractButton;
|
||||
|
|
@ -23,7 +24,8 @@ public:
|
|||
signals:
|
||||
void preferencesSaved();
|
||||
void themeChanged(const QString &theme);
|
||||
void scriptSettingsChanged(bool on);
|
||||
void scriptSettingsChanged(ScriptAutocompleteMode mode);
|
||||
void reloadProjectRequested();
|
||||
|
||||
private:
|
||||
Ui::PreferenceEditor *ui;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
|
||||
#include "maplayout.h"
|
||||
#include "project.h"
|
||||
#include "checkeredbgscene.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QPointer>
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsLineItem>
|
||||
#include <QGraphicsRectItem>
|
||||
#include <QDialogButtonBox>
|
||||
|
|
@ -16,39 +16,12 @@ namespace Ui {
|
|||
class ResizeLayoutPopup;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Custom scene that paints its background a gray checkered pattern.
|
||||
/// Additionally there is a definable "valid" area which will paint the checkerboard green inside.
|
||||
class CheckeredBgScene : public QGraphicsScene {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CheckeredBgScene(QObject *parent = nullptr);
|
||||
void setValidRect(int x, int y, int width, int height) {
|
||||
this->validRect = QRect(x * this->gridSize, y * this->gridSize, width * this->gridSize, height * this->gridSize);
|
||||
}
|
||||
void setValidRect(QRect rect) {
|
||||
this->validRect = rect;
|
||||
}
|
||||
QRect getValidRect() { return this->validRect; }
|
||||
|
||||
protected:
|
||||
void drawBackground(QPainter *painter, const QRectF &rect) override;
|
||||
|
||||
private:
|
||||
int gridSize = 16; // virtual pixels
|
||||
QRect validRect = QRect();
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// PixmapItem subclass which allows for creating a boundary which determine whether
|
||||
/// the pixmap paints normally or with a black tint.
|
||||
/// This item is movable and snaps on a 16x16 grid.
|
||||
/// This item is movable and snaps on a 'cellSize' grid.
|
||||
class BoundedPixmapItem : public QGraphicsPixmapItem {
|
||||
public:
|
||||
BoundedPixmapItem(const QPixmap &pixmap, QGraphicsItem *parent = nullptr);
|
||||
BoundedPixmapItem(const QPixmap &pixmap, const QSize &cellSize, QGraphicsItem *parent = nullptr);
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) override;
|
||||
|
||||
void setBoundary(ResizableRect *rect) { this->boundary = rect; }
|
||||
|
|
@ -59,6 +32,7 @@ protected:
|
|||
private:
|
||||
ResizableRect *boundary = nullptr;
|
||||
QPointF clickedPos = QPointF();
|
||||
QSize cellSize;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,16 +7,27 @@
|
|||
class SelectablePixmapItem : public QObject, public QGraphicsPixmapItem {
|
||||
Q_OBJECT
|
||||
public:
|
||||
SelectablePixmapItem(int cellWidth, int cellHeight): SelectablePixmapItem(cellWidth, cellHeight, INT_MAX, INT_MAX) {}
|
||||
SelectablePixmapItem(int cellWidth, int cellHeight, int maxSelectionWidth, int maxSelectionHeight) {
|
||||
this->cellWidth = cellWidth;
|
||||
this->cellHeight = cellHeight;
|
||||
this->maxSelectionWidth = maxSelectionWidth;
|
||||
this->maxSelectionHeight = maxSelectionHeight;
|
||||
}
|
||||
virtual QPoint getSelectionDimensions();
|
||||
SelectablePixmapItem(const QSize &size, const QSize &maxSelectionSize = QSize(INT_MAX, INT_MAX))
|
||||
: SelectablePixmapItem(size.width(), size.height(), maxSelectionSize.width(), maxSelectionSize.height()) {}
|
||||
SelectablePixmapItem(int cellWidth, int cellHeight, int maxSelectionWidth = INT_MAX, int maxSelectionHeight = INT_MAX)
|
||||
: cellWidth(cellWidth),
|
||||
cellHeight(cellHeight),
|
||||
maxSelectionWidth(maxSelectionWidth),
|
||||
maxSelectionHeight(maxSelectionHeight),
|
||||
selectionInitialX(0),
|
||||
selectionInitialY(0),
|
||||
selectionOffsetX(0),
|
||||
selectionOffsetY(0)
|
||||
{}
|
||||
virtual QSize getSelectionDimensions() const { return QSize(abs(this->selectionOffsetX) + 1, abs(this->selectionOffsetY) + 1); }
|
||||
virtual void draw() = 0;
|
||||
|
||||
virtual void setMaxSelectionSize(const QSize &size) { setMaxSelectionSize(size.width(), size.height()); }
|
||||
virtual void setMaxSelectionSize(int width, int height);
|
||||
QSize maxSelectionSize() { return QSize(this->maxSelectionWidth, this->maxSelectionHeight); }
|
||||
|
||||
void setSelectionStyle(Qt::PenStyle style);
|
||||
|
||||
protected:
|
||||
int cellWidth;
|
||||
int cellHeight;
|
||||
|
|
@ -28,16 +39,28 @@ protected:
|
|||
int selectionOffsetY;
|
||||
|
||||
QPoint getSelectionStart();
|
||||
void select(int, int, int, int);
|
||||
void updateSelection(int, int);
|
||||
QPoint getCellPos(QPointF);
|
||||
void select(const QPoint &pos, const QSize &size = QSize(1,1));
|
||||
void select(int x, int y, int width = 1, int height = 1) { select(QPoint(x, y), QSize(width, height)); }
|
||||
void updateSelection(const QPoint &pos);
|
||||
QPoint getCellPos(const QPointF &itemPos);
|
||||
int getBoundedWidth(int width) const { return qBound(1, width, this->maxSelectionWidth); }
|
||||
int getBoundedHeight(int height) const { return qBound(1, height, this->maxSelectionHeight); }
|
||||
virtual void mousePressEvent(QGraphicsSceneMouseEvent*) override;
|
||||
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent*) override;
|
||||
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent*) override;
|
||||
virtual void drawSelectionRect(const QPoint &, const QSize &, Qt::PenStyle style = Qt::SolidLine);
|
||||
virtual void drawSelection();
|
||||
virtual int cellsWide() const { return this->cellWidth ? (pixmap().width() / this->cellWidth) : 0; }
|
||||
virtual int cellsTall() const { return this->cellHeight ? (pixmap().height() / this->cellHeight) : 0; }
|
||||
|
||||
signals:
|
||||
void selectionChanged(int, int, int, int);
|
||||
void selectionChanged(const QPoint&, const QSize&);
|
||||
|
||||
private:
|
||||
QPoint prevCellPos = QPoint(-1,-1);
|
||||
Qt::PenStyle selectionStyle = Qt::SolidLine;
|
||||
|
||||
void setSelection(const QPoint &pos, const QSize &size);
|
||||
};
|
||||
|
||||
#endif // SELECTABLEPIXMAPITEM_H
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ private:
|
|||
QHash<MultiKeyEdit *, QPointer<const QObject>> multiKeyEdits_objects;
|
||||
|
||||
void parseObjectList(const QObjectList &objectList);
|
||||
void parseObject(const QObject *object, QMap<const QObject*, QString> *objects_labels, QMap<const QObject*, QString> *objects_prefixes);
|
||||
QString getLabel(const QObject *object) const;
|
||||
bool stringPropertyIsNotEmpty(const QObject *object, const char *name) const;
|
||||
void populateMainContainer();
|
||||
|
|
@ -48,7 +49,6 @@ private:
|
|||
void addNewMultiKeyEdit(const QObject *object, const QString &shortcutContext);
|
||||
QList<MultiKeyEdit *> siblings(MultiKeyEdit *multiKeyEdit) const;
|
||||
void promptUserOnDuplicateFound(MultiKeyEdit *current, MultiKeyEdit *sender);
|
||||
void removeKeySequence(const QKeySequence &keySequence, MultiKeyEdit *multiKeyEdit);
|
||||
void saveShortcuts();
|
||||
void resetShortcuts();
|
||||
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ public:
|
|||
this->palette = PaletteUtil::parse(palFilepath, &err);
|
||||
}
|
||||
this->setPixmap(QPixmap::fromImage(this->tileset));
|
||||
this->numTilesWide = this->tileset.width() / 8;
|
||||
this->numTilesWide = this->tileset.width() / this->cellWidth;
|
||||
this->selectedTile = 0x00;
|
||||
setAcceptHoverEvents(true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,15 @@
|
|||
#define TILESETEDITOR_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QPointer>
|
||||
#include <QKeyEvent>
|
||||
#include "project.h"
|
||||
#include "history.h"
|
||||
#include "paletteeditor.h"
|
||||
#include "tileseteditormetatileselector.h"
|
||||
#include "tileseteditortileselector.h"
|
||||
#include "metatilelayersitem.h"
|
||||
#include "metatileimageexporter.h"
|
||||
|
||||
class NoScrollComboBox;
|
||||
class Layout;
|
||||
|
|
@ -18,6 +21,7 @@ class TilesetEditor;
|
|||
|
||||
class MetatileHistoryItem {
|
||||
public:
|
||||
MetatileHistoryItem() {};
|
||||
MetatileHistoryItem(uint16_t metatileId, Metatile *prevMetatile, Metatile *newMetatile, QString prevLabel, QString newLabel) {
|
||||
this->metatileId = metatileId;
|
||||
this->prevMetatile = prevMetatile;
|
||||
|
|
@ -25,15 +29,24 @@ public:
|
|||
this->prevLabel = prevLabel;
|
||||
this->newLabel = newLabel;
|
||||
}
|
||||
MetatileHistoryItem(uint16_t metatileIdA, uint16_t metatileIdB) {
|
||||
this->metatileId = metatileIdA;
|
||||
this->swapMetatileId = metatileIdB;
|
||||
this->isSwap = true;
|
||||
}
|
||||
~MetatileHistoryItem() {
|
||||
delete this->prevMetatile;
|
||||
delete this->newMetatile;
|
||||
}
|
||||
uint16_t metatileId;
|
||||
Metatile *prevMetatile;
|
||||
Metatile *newMetatile;
|
||||
|
||||
uint16_t metatileId = 0;
|
||||
Metatile *prevMetatile = nullptr;
|
||||
Metatile *newMetatile = nullptr;
|
||||
QString prevLabel;
|
||||
QString newLabel;
|
||||
|
||||
uint16_t swapMetatileId = 0;
|
||||
bool isSwap = false;
|
||||
};
|
||||
|
||||
class TilesetEditor : public QMainWindow
|
||||
|
|
@ -53,27 +66,19 @@ public:
|
|||
|
||||
QObjectList shortcutableObjects() const;
|
||||
|
||||
void setPaletteId(int paletteId);
|
||||
int paletteId() const;
|
||||
|
||||
public slots:
|
||||
void applyUserShortcuts();
|
||||
void onSelectedMetatileChanged(uint16_t);
|
||||
|
||||
private slots:
|
||||
void onWindowActivated();
|
||||
void onHoveredMetatileChanged(uint16_t);
|
||||
void onHoveredMetatileCleared();
|
||||
void onHoveredTileChanged(uint16_t);
|
||||
void onHoveredTileCleared();
|
||||
void onSelectedTilesChanged();
|
||||
void onMetatileLayerTileChanged(int, int);
|
||||
void onMetatileLayerSelectionChanged(QPoint, int, int);
|
||||
void onMetatileLayerSelectionChanged(const QPoint&, const QSize&);
|
||||
void onPaletteEditorChangedPaletteColor();
|
||||
void onPaletteEditorChangedPalette(int);
|
||||
|
||||
void on_spinBox_paletteSelector_valueChanged(int arg1);
|
||||
|
||||
void on_actionImport_Primary_Tiles_triggered();
|
||||
|
||||
void on_actionImport_Secondary_Tiles_triggered();
|
||||
|
||||
void on_actionChange_Metatiles_Count_triggered();
|
||||
|
||||
|
|
@ -89,17 +94,7 @@ private slots:
|
|||
void on_actionUndo_triggered();
|
||||
void on_actionRedo_triggered();
|
||||
|
||||
void on_lineEdit_metatileLabel_editingFinished();
|
||||
|
||||
void on_actionExport_Primary_Tiles_Image_triggered();
|
||||
void on_actionExport_Secondary_Tiles_Image_triggered();
|
||||
void on_actionExport_Primary_Metatiles_Image_triggered();
|
||||
void on_actionExport_Secondary_Metatiles_Image_triggered();
|
||||
|
||||
void on_actionImport_Primary_Metatiles_triggered();
|
||||
void on_actionImport_Secondary_Metatiles_triggered();
|
||||
|
||||
void on_copyButton_metatileLabel_clicked();
|
||||
void on_copyButton_MetatileLabel_clicked();
|
||||
|
||||
void on_actionCut_triggered();
|
||||
void on_actionCopy_triggered();
|
||||
|
|
@ -107,6 +102,10 @@ private slots:
|
|||
void on_horizontalSlider_MetatilesZoom_valueChanged(int value);
|
||||
void on_horizontalSlider_TilesZoom_valueChanged(int value);
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
void closeEvent(QCloseEvent*) override;
|
||||
|
||||
private:
|
||||
void initAttributesUi();
|
||||
void initMetatileSelector();
|
||||
|
|
@ -122,16 +121,18 @@ private:
|
|||
void drawSelectedTiles();
|
||||
void redrawTileSelector();
|
||||
void redrawMetatileSelector();
|
||||
void importTilesetTiles(Tileset*, bool);
|
||||
void importTilesetMetatiles(Tileset*, bool);
|
||||
void importTilesetTiles(Tileset*);
|
||||
void importAdvanceMapMetatiles(Tileset*);
|
||||
void exportTilesImage(Tileset*);
|
||||
void exportPorytilesLayerImages(Tileset*);
|
||||
void exportMetatilesImage();
|
||||
void refresh();
|
||||
void commitMetatileLabel();
|
||||
void closeEvent(QCloseEvent*);
|
||||
void countMetatileUsage();
|
||||
void countTileUsage();
|
||||
void copyMetatile(bool cut);
|
||||
void pasteMetatile(const Metatile * toPaste, QString label);
|
||||
bool replaceMetatile(uint16_t metatileId, const Metatile * src, QString label);
|
||||
void pasteMetatile(const Metatile &toPaste, QString label);
|
||||
bool replaceMetatile(uint16_t metatileId, const Metatile &src, QString label);
|
||||
void commitMetatileChange(Metatile * prevMetatile);
|
||||
void commitMetatileAndLabelChange(Metatile * prevMetatile, QString prevLabel);
|
||||
uint32_t attributeNameToValue(Metatile::Attr attribute, const QString &text, bool *ok);
|
||||
|
|
@ -142,24 +143,36 @@ private:
|
|||
void commitEncounterType();
|
||||
void commitTerrainType();
|
||||
void commitLayerType();
|
||||
void commit(MetatileHistoryItem *item);
|
||||
void updateEditHistoryActions();
|
||||
void setRawAttributesVisible(bool visible);
|
||||
void setXFlip(bool enabled);
|
||||
void setYFlip(bool enabled);
|
||||
void refreshTileFlips();
|
||||
void refreshPaletteId();
|
||||
void paintSelectedLayerTiles(const QPoint &pos, bool paletteOnly = false);
|
||||
void setMetatileLayerOrientation(Qt::Orientation orientation);
|
||||
void commitMetatileSwap(uint16_t metatileIdA, uint16_t metatileIdB);
|
||||
bool swapMetatiles(uint16_t metatileIdA, uint16_t metatileIdB);
|
||||
void applyMetatileSwapToLayouts(uint16_t metatileIdA, uint16_t metatileIdB);
|
||||
void applyMetatileSwapsToLayouts();
|
||||
void rebuildMetatilePropertiesFrame();
|
||||
void addWidgetToMetatileProperties(QWidget *w, int *row, int rowSpan);
|
||||
void updateLayerTileStatus();
|
||||
void showTileStatus(const Tile &tile);
|
||||
void showTileStatus(uint16_t tileId);
|
||||
void updateMetatileStatus();
|
||||
void showMetatileStatus(uint16_t metatileId);
|
||||
|
||||
Ui::TilesetEditor *ui;
|
||||
History<MetatileHistoryItem*> metatileHistory;
|
||||
TilesetEditorMetatileSelector *metatileSelector = nullptr;
|
||||
TilesetEditorTileSelector *tileSelector = nullptr;
|
||||
MetatileLayersItem *metatileLayersItem = nullptr;
|
||||
PaletteEditor *paletteEditor = nullptr;
|
||||
QPointer<PaletteEditor> paletteEditor = nullptr;
|
||||
Project *project = nullptr;
|
||||
Layout *layout = nullptr;
|
||||
Metatile *metatile = nullptr;
|
||||
Metatile *copiedMetatile = nullptr;
|
||||
QString copiedMetatileLabel;
|
||||
int paletteId;
|
||||
bool tileXFlip;
|
||||
bool tileYFlip;
|
||||
bool hasUnsavedChanges;
|
||||
Tileset *primaryTileset = nullptr;
|
||||
Tileset *secondaryTileset = nullptr;
|
||||
|
|
@ -170,6 +183,9 @@ private:
|
|||
QGraphicsScene *metatileLayersScene = nullptr;
|
||||
bool lockSelection = false;
|
||||
QSet<uint16_t> metatileReloadQueue;
|
||||
MetatileImageExporter::Settings *metatileImageExportSettings = nullptr;
|
||||
QList<QPair<uint16_t,uint16_t>> metatileIdSwaps;
|
||||
int numLayerViewRows;
|
||||
|
||||
bool save();
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ class Layout;
|
|||
class TilesetEditorMetatileSelector: public SelectablePixmapItem {
|
||||
Q_OBJECT
|
||||
public:
|
||||
TilesetEditorMetatileSelector(Tileset *primaryTileset, Tileset *secondaryTileset, Layout *layout);
|
||||
TilesetEditorMetatileSelector(int numMetatilesWide, Tileset *primaryTileset, Tileset *secondaryTileset, Layout *layout);
|
||||
Layout *layout = nullptr;
|
||||
|
||||
void draw() override;
|
||||
|
|
@ -18,11 +18,16 @@ public:
|
|||
|
||||
bool select(uint16_t metatileId);
|
||||
void setTilesets(Tileset*, Tileset*);
|
||||
uint16_t getSelectedMetatileId();
|
||||
void updateSelectedMetatile();
|
||||
QPoint getMetatileIdCoordsOnWidget(uint16_t metatileId);
|
||||
QImage buildPrimaryMetatilesImage();
|
||||
QImage buildSecondaryMetatilesImage();
|
||||
uint16_t getSelectedMetatileId() const { return this->selectedMetatileId; }
|
||||
QPoint getMetatileIdCoordsOnWidget(uint16_t metatileId) const;
|
||||
|
||||
void setSwapMode(bool enabled);
|
||||
void addToSwapSelection(uint16_t metatileId);
|
||||
void removeFromSwapSelection(uint16_t metatileId);
|
||||
void clearSwapSelection();
|
||||
|
||||
bool hasCursor() const { return this->prevCellPos != QPoint(-1,-1); }
|
||||
uint16_t metatileIdUnderCursor() const { return this->lastHoveredMetatileId; }
|
||||
|
||||
QVector<uint16_t> usedMetatiles;
|
||||
bool selectorShowUnused = false;
|
||||
|
|
@ -38,32 +43,37 @@ protected:
|
|||
void hoverLeaveEvent(QGraphicsSceneHoverEvent*) override;
|
||||
|
||||
private:
|
||||
const int numMetatilesWide;
|
||||
QImage baseImage;
|
||||
QPixmap basePixmap;
|
||||
Tileset *primaryTileset = nullptr;
|
||||
Tileset *secondaryTileset = nullptr;
|
||||
uint16_t selectedMetatileId;
|
||||
int numMetatilesWide;
|
||||
int numMetatilesHigh;
|
||||
uint16_t selectedMetatileId = 0;
|
||||
QPoint prevCellPos = QPoint(-1,-1);
|
||||
|
||||
QList<uint16_t> swapMetatileIds;
|
||||
uint16_t lastHoveredMetatileId = 0;
|
||||
bool inSwapMode = false;
|
||||
|
||||
void updateBasePixmap();
|
||||
uint16_t getMetatileId(int x, int y);
|
||||
QPoint getMetatileIdCoords(uint16_t);
|
||||
bool shouldAcceptEvent(QGraphicsSceneMouseEvent*);
|
||||
int numRows(int numMetatiles);
|
||||
int numRows();
|
||||
uint16_t posToMetatileId(int x, int y, bool *ok = nullptr) const;
|
||||
uint16_t posToMetatileId(const QPoint &pos, bool *ok = nullptr) const;
|
||||
QPoint metatileIdToPos(uint16_t metatileId, bool *ok = nullptr) const;
|
||||
bool isValidMetatileId(uint16_t metatileId) const;
|
||||
int numRows(int numMetatiles) const;
|
||||
int numRows() const;
|
||||
void drawGrid();
|
||||
void drawDivider();
|
||||
void drawFilters();
|
||||
void drawUnused();
|
||||
void drawCounts();
|
||||
QImage buildAllMetatilesImage();
|
||||
QImage buildImage(int metatileIdStart, int numMetatiles);
|
||||
int numPrimaryMetatilesRounded() const;
|
||||
|
||||
signals:
|
||||
void hoveredMetatileChanged(uint16_t);
|
||||
void hoveredMetatileCleared();
|
||||
void selectedMetatileChanged(uint16_t);
|
||||
void swapRequested(uint16_t, uint16_t);
|
||||
};
|
||||
|
||||
#endif // TILESETEDITORMETATILESELECTOR_H
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@
|
|||
class TilesetEditorTileSelector: public SelectablePixmapItem {
|
||||
Q_OBJECT
|
||||
public:
|
||||
TilesetEditorTileSelector(Tileset *primaryTileset, Tileset *secondaryTileset, int numLayers)
|
||||
: SelectablePixmapItem(16, 16, numLayers * 2, 2) {
|
||||
TilesetEditorTileSelector(Tileset *primaryTileset, Tileset *secondaryTileset)
|
||||
: SelectablePixmapItem(16, 16, Metatile::tileWidth(), Metatile::tileWidth()) {
|
||||
this->primaryTileset = primaryTileset;
|
||||
this->secondaryTileset = secondaryTileset;
|
||||
this->numTilesWide = 16;
|
||||
|
|
@ -18,15 +18,16 @@ public:
|
|||
this->paletteChanged = false;
|
||||
setAcceptHoverEvents(true);
|
||||
}
|
||||
QPoint getSelectionDimensions();
|
||||
void draw();
|
||||
QSize getSelectionDimensions() const override;
|
||||
void setMaxSelectionSize(int width, int height) override;
|
||||
void draw() override;
|
||||
void select(uint16_t metatileId);
|
||||
void highlight(uint16_t metatileId);
|
||||
void setTilesets(Tileset*, Tileset*);
|
||||
void setPaletteId(int);
|
||||
void setTileFlips(bool, bool);
|
||||
QList<Tile> getSelectedTiles();
|
||||
void setExternalSelection(int, int, QList<Tile>, QList<int>);
|
||||
void setExternalSelection(int, int, const QList<Tile>&);
|
||||
QPoint getTileCoordsOnWidget(uint16_t);
|
||||
QImage buildPrimaryTilesIndexedImage();
|
||||
QImage buildSecondaryTilesIndexedImage();
|
||||
|
|
@ -36,18 +37,19 @@ public:
|
|||
bool showDivider = false;
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent*);
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent*);
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent*);
|
||||
void hoverMoveEvent(QGraphicsSceneHoverEvent*);
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent*);
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent*) override;
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent*) override;
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent*) override;
|
||||
void hoverMoveEvent(QGraphicsSceneHoverEvent*) override;
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent*) override;
|
||||
|
||||
private:
|
||||
QPixmap basePixmap;
|
||||
bool externalSelection;
|
||||
int externalSelectionWidth;
|
||||
int externalSelectionHeight;
|
||||
QList<Tile> externalSelectedTiles;
|
||||
QList<int> externalSelectedPos;
|
||||
QPoint prevCellPos = QPoint(-1,-1);
|
||||
|
||||
Tileset *primaryTileset;
|
||||
Tileset *secondaryTileset;
|
||||
|
|
@ -61,9 +63,9 @@ private:
|
|||
uint16_t getTileId(int x, int y);
|
||||
QPoint getTileCoords(uint16_t);
|
||||
QList<QRgb> getCurPaletteTable();
|
||||
QList<Tile> buildSelectedTiles(int, int, QList<Tile>);
|
||||
QList<Tile> buildSelectedTiles(int, int, const QList<Tile>&);
|
||||
QImage buildImage(int tileIdStart, int numTiles);
|
||||
|
||||
void updateBasePixmap();
|
||||
void drawUnused();
|
||||
|
||||
signals:
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ public:
|
|||
uint32_t value() const { return m_value; }
|
||||
uint32_t minimum() const { return m_minimum; }
|
||||
uint32_t maximum() const { return m_maximum; }
|
||||
uint32_t singleStep() const { return m_singleStep; }
|
||||
QString prefix() const { return m_prefix; }
|
||||
int displayIntegerBase() const { return m_displayIntegerBase; }
|
||||
bool hasPadding() const { return m_hasPadding; }
|
||||
|
|
@ -28,6 +29,7 @@ public:
|
|||
void setMinimum(uint32_t min);
|
||||
void setMaximum(uint32_t max);
|
||||
void setRange(uint32_t min, uint32_t max);
|
||||
void setSingleStep(uint32_t val);
|
||||
void setPrefix(const QString &prefix);
|
||||
void setDisplayIntegerBase(int base);
|
||||
void setHasPadding(bool enabled);
|
||||
|
|
@ -36,6 +38,7 @@ private:
|
|||
uint32_t m_minimum;
|
||||
uint32_t m_maximum;
|
||||
uint32_t m_value;
|
||||
uint32_t m_singleStep;
|
||||
QString m_prefix;
|
||||
int m_displayIntegerBase;
|
||||
bool m_hasPadding;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef UPDATEPROMOTER_H
|
||||
#define UPDATEPROMOTER_H
|
||||
|
||||
#ifdef QT_NETWORK_LIB
|
||||
|
||||
#include "network.h"
|
||||
|
||||
#include <QDialog>
|
||||
|
|
@ -47,4 +49,6 @@ signals:
|
|||
void changedPreferences();
|
||||
};
|
||||
|
||||
#endif // QT_NETWORK_LIB
|
||||
|
||||
#endif // UPDATEPROMOTER_H
|
||||
|
|
|
|||
|
|
@ -2,24 +2,11 @@
|
|||
#define WILDMONSEARCH_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QTableWidgetItem>
|
||||
#include <QCollator>
|
||||
|
||||
#include "numericsorttableitem.h"
|
||||
|
||||
class Project;
|
||||
|
||||
class NumericSortTableItem : public QTableWidgetItem
|
||||
{
|
||||
public:
|
||||
explicit NumericSortTableItem(const QString &text) : QTableWidgetItem(text) {};
|
||||
|
||||
protected:
|
||||
virtual bool operator<(const QTableWidgetItem &other) const override {
|
||||
QCollator collator;
|
||||
collator.setNumericMode(true);
|
||||
return collator.compare(text(), other.text()) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
namespace Ui {
|
||||
class WildMonSearch;
|
||||
}
|
||||
|
|
|
|||
20
porymap.pro
20
porymap.pro
|
|
@ -4,13 +4,23 @@
|
|||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
QT += core gui qml network
|
||||
QT += core gui
|
||||
|
||||
qtHaveModule(charts) {
|
||||
QT += charts
|
||||
} else {
|
||||
warning("Qt module 'charts' not found, disabling chart features.")
|
||||
}
|
||||
qtHaveModule(qml) {
|
||||
QT += qml
|
||||
} else {
|
||||
warning("Qt module 'qml' not found, disabling plug-in features.")
|
||||
}
|
||||
qtHaveModule(network) {
|
||||
QT += network
|
||||
} else {
|
||||
warning("Qt module 'network' not found, disabling network features.")
|
||||
}
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
|
|
@ -66,6 +76,7 @@ SOURCES += src/core/advancemapparser.cpp \
|
|||
src/scriptapi/apiutility.cpp \
|
||||
src/scriptapi/scripting.cpp \
|
||||
src/ui/aboutporymap.cpp \
|
||||
src/ui/checkeredbgscene.cpp \
|
||||
src/ui/colorinputwidget.cpp \
|
||||
src/ui/connectionslistitem.cpp \
|
||||
src/ui/customattributesdialog.cpp \
|
||||
|
|
@ -115,6 +126,7 @@ SOURCES += src/core/advancemapparser.cpp \
|
|||
src/ui/montabwidget.cpp \
|
||||
src/ui/encountertablemodel.cpp \
|
||||
src/ui/encountertabledelegates.cpp \
|
||||
src/ui/palettecolorsearch.cpp \
|
||||
src/ui/paletteeditor.cpp \
|
||||
src/ui/selectablepixmapitem.cpp \
|
||||
src/ui/tileseteditor.cpp \
|
||||
|
|
@ -124,6 +136,7 @@ SOURCES += src/core/advancemapparser.cpp \
|
|||
src/ui/regionmapeditor.cpp \
|
||||
src/ui/newmapdialog.cpp \
|
||||
src/ui/mapimageexporter.cpp \
|
||||
src/ui/metatileimageexporter.cpp \
|
||||
src/ui/newtilesetdialog.cpp \
|
||||
src/ui/flowlayout.cpp \
|
||||
src/ui/mapruler.cpp \
|
||||
|
|
@ -180,6 +193,7 @@ HEADERS += include/core/advancemapparser.h \
|
|||
include/lib/orderedmap.h \
|
||||
include/lib/orderedjson.h \
|
||||
include/ui/aboutporymap.h \
|
||||
include/ui/checkeredbgscene.h \
|
||||
include/ui/connectionslistitem.h \
|
||||
include/ui/customattributesdialog.h \
|
||||
include/ui/customattributestable.h \
|
||||
|
|
@ -231,6 +245,7 @@ HEADERS += include/core/advancemapparser.h \
|
|||
include/ui/encountertablemodel.h \
|
||||
include/ui/encountertabledelegates.h \
|
||||
include/ui/adjustingstackedwidget.h \
|
||||
include/ui/palettecolorsearch.h \
|
||||
include/ui/paletteeditor.h \
|
||||
include/ui/selectablepixmapitem.h \
|
||||
include/ui/tileseteditor.h \
|
||||
|
|
@ -240,6 +255,7 @@ HEADERS += include/core/advancemapparser.h \
|
|||
include/ui/regionmapeditor.h \
|
||||
include/ui/newmapdialog.h \
|
||||
include/ui/mapimageexporter.h \
|
||||
include/ui/metatileimageexporter.h \
|
||||
include/ui/newtilesetdialog.h \
|
||||
include/ui/overlay.h \
|
||||
include/ui/flowlayout.h \
|
||||
|
|
@ -283,12 +299,14 @@ FORMS += forms/mainwindow.ui \
|
|||
forms/prefabcreationdialog.ui \
|
||||
forms/prefabframe.ui \
|
||||
forms/tileseteditor.ui \
|
||||
forms/palettecolorsearch.ui \
|
||||
forms/paletteeditor.ui \
|
||||
forms/regionmapeditor.ui \
|
||||
forms/newmapdialog.ui \
|
||||
forms/aboutporymap.ui \
|
||||
forms/newtilesetdialog.ui \
|
||||
forms/mapimageexporter.ui \
|
||||
forms/metatileimageexporter.ui \
|
||||
forms/shortcutseditor.ui \
|
||||
forms/preferenceeditor.ui \
|
||||
forms/regionmappropertiesdialog.ui \
|
||||
|
|
|
|||
BIN
resources/icons/swap_cursor.ico
Normal file
BIN
resources/icons/swap_cursor.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
|
|
@ -44,6 +44,7 @@
|
|||
<file>icons/refresh.ico</file>
|
||||
<file>icons/shift_cursor.ico</file>
|
||||
<file>icons/shift.ico</file>
|
||||
<file>icons/swap_cursor.ico</file>
|
||||
<file>icons/tall_grass.ico</file>
|
||||
<file>icons/warning.ico</file>
|
||||
<file>icons/minimap.ico</file>
|
||||
|
|
|
|||
100
src/config.cpp
100
src/config.cpp
|
|
@ -4,6 +4,7 @@
|
|||
#include "map.h"
|
||||
#include "validator.h"
|
||||
#include "utility.h"
|
||||
#include "metatile.h"
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFormLayout>
|
||||
|
|
@ -283,7 +284,7 @@ int KeyValueConfigBase::getConfigInteger(const QString &key, const QString &valu
|
|||
logWarn(QString("Invalid config value for %1: '%2'. Must be an integer. Using default value '%3'.").arg(key).arg(value).arg(defaultValue));
|
||||
result = defaultValue;
|
||||
}
|
||||
return qMin(max, qMax(min, result));
|
||||
return qBound(min, result, max);
|
||||
}
|
||||
|
||||
uint32_t KeyValueConfigBase::getConfigUint32(const QString &key, const QString &value, uint32_t min, uint32_t max, uint32_t defaultValue) {
|
||||
|
|
@ -293,10 +294,13 @@ uint32_t KeyValueConfigBase::getConfigUint32(const QString &key, const QString &
|
|||
logWarn(QString("Invalid config value for %1: '%2'. Must be an integer. Using default value '%3'.").arg(key).arg(value).arg(defaultValue));
|
||||
result = defaultValue;
|
||||
}
|
||||
return qMin(max, qMax(min, result));
|
||||
return qBound(min, result, max);
|
||||
}
|
||||
|
||||
QColor KeyValueConfigBase::getConfigColor(const QString &key, const QString &value, const QColor &defaultValue) {
|
||||
if (value.isEmpty())
|
||||
return QColor();
|
||||
|
||||
QColor color = QColor("#" + value);
|
||||
if (!color.isValid()) {
|
||||
logWarn(QString("Invalid config value for %1: '%2'. Must be a color in the format 'RRGGBB'. Using default value '%3'.").arg(key).arg(value).arg(defaultValue.name()));
|
||||
|
|
@ -305,12 +309,72 @@ QColor KeyValueConfigBase::getConfigColor(const QString &key, const QString &val
|
|||
return color;
|
||||
}
|
||||
|
||||
QString KeyValueConfigBase::toConfigColor(const QColor &color) {
|
||||
return color.isValid() ? color.name().remove("#") : QString(); // Our text config treats '#' as the start of a comment.
|
||||
}
|
||||
|
||||
PorymapConfig porymapConfig;
|
||||
|
||||
PorymapConfig::PorymapConfig() : KeyValueConfigBase(QStringLiteral("porymap.cfg")) {
|
||||
reset();
|
||||
}
|
||||
|
||||
void PorymapConfig::reset() {
|
||||
setRoot(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
|
||||
this->recentProjects.clear();
|
||||
this->projectManuallyClosed = false;
|
||||
this->reopenOnLaunch = true;
|
||||
this->mapListTab = 0;
|
||||
this->mapListEditGroupsEnabled = false;
|
||||
this->mapListHideEmptyEnabled.clear();
|
||||
this->prettyCursors = true;
|
||||
this->mirrorConnectingMaps = true;
|
||||
this->showDiveEmergeMaps = false;
|
||||
this->diveEmergeMapOpacity = 30;
|
||||
this->diveMapOpacity = 15;
|
||||
this->emergeMapOpacity = 15;
|
||||
this->collisionOpacity = 50;
|
||||
this->collisionZoom = 30;
|
||||
this->metatilesZoom = 30;
|
||||
this->tilesetEditorMetatilesZoom = 30;
|
||||
this->tilesetEditorTilesZoom = 30;
|
||||
this->tilesetEditorLayerOrientation = Qt::Vertical;
|
||||
this->showPlayerView = false;
|
||||
this->showCursorTile = true;
|
||||
this->showBorder = true;
|
||||
this->showGrid = false;
|
||||
this->showTilesetEditorMetatileGrid = false;
|
||||
this->showTilesetEditorLayerGrid = true;
|
||||
this->showTilesetEditorDivider = false;
|
||||
this->showTilesetEditorRawAttributes = false;
|
||||
this->showPaletteEditorUnusedColors = false;
|
||||
this->monitorFiles = true;
|
||||
this->tilesetCheckerboardFill = true;
|
||||
this->newMapHeaderSectionExpanded = false;
|
||||
this->theme = "default";
|
||||
this->wildMonChartTheme = "";
|
||||
this->textEditorOpenFolder = "";
|
||||
this->textEditorGotoLine = "";
|
||||
this->paletteEditorBitDepth = 24;
|
||||
this->projectSettingsTab = 0;
|
||||
this->scriptAutocompleteMode = ScriptAutocompleteMode::MapOnly;
|
||||
this->warpBehaviorWarningDisabled = false;
|
||||
this->eventDeleteWarningDisabled = false;
|
||||
this->eventOverlayEnabled = false;
|
||||
this->checkForUpdates = true;
|
||||
this->lastUpdateCheckTime = QDateTime();
|
||||
this->lastUpdateCheckVersion = porymapVersion;
|
||||
this->rateLimitTimes.clear();
|
||||
this->eventSelectionShapeMode = QGraphicsPixmapItem::MaskShape;
|
||||
this->shownInGameReloadMessage = false;
|
||||
this->gridSettings = GridSettings();
|
||||
this->gridSettings.width = Metatile::pixelWidth();
|
||||
this->gridSettings.height = Metatile::pixelHeight();
|
||||
this->statusBarLogTypes = { LogType::LOG_ERROR, LogType::LOG_WARN };
|
||||
this->applicationFont = QFont();
|
||||
this->mapListFont = PorymapConfig::defaultMapListFont();
|
||||
}
|
||||
|
||||
void PorymapConfig::parseConfigKeyValue(QString key, QString value) {
|
||||
if (key == "recent_project") {
|
||||
this->recentProjects = value.split(",", Qt::SkipEmptyParts);
|
||||
|
|
@ -391,6 +455,9 @@ void PorymapConfig::parseConfigKeyValue(QString key, QString value) {
|
|||
this->tilesetEditorMetatilesZoom = getConfigInteger(key, value, 10, 100, 30);
|
||||
} else if (key == "tileset_editor_tiles_zoom") {
|
||||
this->tilesetEditorTilesZoom = getConfigInteger(key, value, 10, 100, 30);
|
||||
} else if (key == "tileset_editor_layer_orientation") {
|
||||
// Being explicit here to avoid casting out-of-range values.
|
||||
this->tilesetEditorLayerOrientation = (getConfigInteger(key, value) == static_cast<int>(Qt::Horizontal)) ? Qt::Horizontal : Qt::Vertical;
|
||||
} else if (key == "show_player_view") {
|
||||
this->showPlayerView = getConfigBool(key, value);
|
||||
} else if (key == "show_cursor_tile") {
|
||||
|
|
@ -407,6 +474,8 @@ void PorymapConfig::parseConfigKeyValue(QString key, QString value) {
|
|||
this->showTilesetEditorDivider = getConfigBool(key, value);
|
||||
} else if (key == "show_tileset_editor_raw_attributes") {
|
||||
this->showTilesetEditorRawAttributes = getConfigBool(key, value);
|
||||
} else if (key == "show_palette_editor_unused_colors") {
|
||||
this->showPaletteEditorUnusedColors = getConfigBool(key, value);
|
||||
} else if (key == "monitor_files") {
|
||||
this->monitorFiles = getConfigBool(key, value);
|
||||
} else if (key == "tileset_checkerboard_fill") {
|
||||
|
|
@ -428,8 +497,13 @@ void PorymapConfig::parseConfigKeyValue(QString key, QString value) {
|
|||
}
|
||||
} else if (key == "project_settings_tab") {
|
||||
this->projectSettingsTab = getConfigInteger(key, value, 0);
|
||||
#ifdef CONFIG_BACKWARDS_COMPATABILITY
|
||||
// Old setting replaced by script_autocomplete_mode
|
||||
} else if (key == "load_all_event_scripts") {
|
||||
this->loadAllEventScripts = getConfigBool(key, value);
|
||||
this->scriptAutocompleteMode = getConfigBool(key, value) ? ScriptAutocompleteMode::All : ScriptAutocompleteMode::MapOnly;
|
||||
#endif
|
||||
} else if (key == "script_autocomplete_mode") {
|
||||
this->scriptAutocompleteMode = static_cast<ScriptAutocompleteMode>(getConfigInteger(key, value, ScriptAutocompleteMode::MapOnly, ScriptAutocompleteMode::All));
|
||||
} else if (key == "warp_behavior_warning_disabled") {
|
||||
this->warpBehaviorWarningDisabled = getConfigBool(key, value);
|
||||
} else if (key == "event_delete_warning_disabled") {
|
||||
|
|
@ -534,6 +608,7 @@ QMap<QString, QString> PorymapConfig::getKeyValueMap() {
|
|||
map.insert("metatiles_zoom", QString::number(this->metatilesZoom));
|
||||
map.insert("tileset_editor_metatiles_zoom", QString::number(this->tilesetEditorMetatilesZoom));
|
||||
map.insert("tileset_editor_tiles_zoom", QString::number(this->tilesetEditorTilesZoom));
|
||||
map.insert("tileset_editor_layer_orientation", QString::number(this->tilesetEditorLayerOrientation));
|
||||
map.insert("show_player_view", this->showPlayerView ? "1" : "0");
|
||||
map.insert("show_cursor_tile", this->showCursorTile ? "1" : "0");
|
||||
map.insert("show_border", this->showBorder ? "1" : "0");
|
||||
|
|
@ -542,6 +617,7 @@ QMap<QString, QString> PorymapConfig::getKeyValueMap() {
|
|||
map.insert("show_tileset_editor_layer_grid", this->showTilesetEditorLayerGrid ? "1" : "0");
|
||||
map.insert("show_tileset_editor_divider", this->showTilesetEditorDivider ? "1" : "0");
|
||||
map.insert("show_tileset_editor_raw_attributes", this->showTilesetEditorRawAttributes ? "1" : "0");
|
||||
map.insert("show_palette_editor_unused_colors", this->showPaletteEditorUnusedColors ? "1" : "0");
|
||||
map.insert("monitor_files", this->monitorFiles ? "1" : "0");
|
||||
map.insert("tileset_checkerboard_fill", this->tilesetCheckerboardFill ? "1" : "0");
|
||||
map.insert("new_map_header_section_expanded", this->newMapHeaderSectionExpanded ? "1" : "0");
|
||||
|
|
@ -551,7 +627,7 @@ QMap<QString, QString> PorymapConfig::getKeyValueMap() {
|
|||
map.insert("text_editor_goto_line", this->textEditorGotoLine);
|
||||
map.insert("palette_editor_bit_depth", QString::number(this->paletteEditorBitDepth));
|
||||
map.insert("project_settings_tab", QString::number(this->projectSettingsTab));
|
||||
map.insert("load_all_event_scripts", QString::number(this->loadAllEventScripts));
|
||||
map.insert("script_autocomplete_mode", QString::number(this->scriptAutocompleteMode));
|
||||
map.insert("warp_behavior_warning_disabled", QString::number(this->warpBehaviorWarningDisabled));
|
||||
map.insert("event_delete_warning_disabled", QString::number(this->eventDeleteWarningDisabled));
|
||||
map.insert("event_overlay_enabled", QString::number(this->eventOverlayEnabled));
|
||||
|
|
@ -571,7 +647,7 @@ QMap<QString, QString> PorymapConfig::getKeyValueMap() {
|
|||
map.insert("grid_x", QString::number(this->gridSettings.offsetX));
|
||||
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.
|
||||
map.insert("grid_color", toConfigColor(this->gridSettings.color));
|
||||
|
||||
QStringList logTypesStrings;
|
||||
for (const auto &type : this->statusBarLogTypes) {
|
||||
|
|
@ -898,8 +974,13 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
|
|||
this->tilesetsHaveCallback = getConfigBool(key, value);
|
||||
} else if (key == "tilesets_have_is_compressed") {
|
||||
this->tilesetsHaveIsCompressed = getConfigBool(key, value);
|
||||
#ifdef CONFIG_BACKWARDS_COMPATABILITY
|
||||
// Old setting replaced by transparency_color
|
||||
} else if (key == "set_transparent_pixels_black") {
|
||||
this->setTransparentPixelsBlack = getConfigBool(key, value);
|
||||
this->transparencyColor = getConfigBool(key, value) ? QColor(Qt::black) : QColor();
|
||||
#endif
|
||||
} else if (key == "transparency_color") {
|
||||
this->transparencyColor = getConfigColor(key, value);
|
||||
} else if (key == "preserve_matching_only_data") {
|
||||
this->preserveMatchingOnlyData = getConfigBool(key, value);
|
||||
} else if (key == "event_icon_path_object") {
|
||||
|
|
@ -940,6 +1021,8 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
|
|||
this->maxEventsPerGroup = getConfigInteger(key, value, 1, INT_MAX, 255);
|
||||
} else if (key == "forced_major_version") {
|
||||
this->forcedMajorVersion = getConfigInteger(key, value);
|
||||
} else if (key == "metatile_selector_width") {
|
||||
this->metatileSelectorWidth = getConfigInteger(key, value, 1, INT_MAX, 8);
|
||||
} else {
|
||||
logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->filepath()).arg(key));
|
||||
}
|
||||
|
|
@ -1005,7 +1088,7 @@ QMap<QString, QString> ProjectConfig::getKeyValueMap() {
|
|||
}
|
||||
map.insert("tilesets_have_callback", QString::number(this->tilesetsHaveCallback));
|
||||
map.insert("tilesets_have_is_compressed", QString::number(this->tilesetsHaveIsCompressed));
|
||||
map.insert("set_transparent_pixels_black", QString::number(this->setTransparentPixelsBlack));
|
||||
map.insert("transparency_color", toConfigColor(this->transparencyColor));
|
||||
map.insert("preserve_matching_only_data", QString::number(this->preserveMatchingOnlyData));
|
||||
map.insert("metatile_attributes_size", QString::number(this->metatileAttributesSize));
|
||||
map.insert("metatile_behavior_mask", Util::toHexString(this->metatileBehaviorMask));
|
||||
|
|
@ -1049,6 +1132,7 @@ QMap<QString, QString> ProjectConfig::getKeyValueMap() {
|
|||
map.insert("warp_behaviors", warpBehaviorStrs.join(","));
|
||||
map.insert("max_events_per_group", QString::number(this->maxEventsPerGroup));
|
||||
map.insert("forced_major_version", QString::number(this->forcedMajorVersion));
|
||||
map.insert("metatile_selector_width", QString::number(this->metatileSelectorWidth));
|
||||
|
||||
return map;
|
||||
}
|
||||
|
|
@ -1182,7 +1266,7 @@ int ProjectConfig::getNumLayersInMetatile() {
|
|||
}
|
||||
|
||||
int ProjectConfig::getNumTilesInMetatile() {
|
||||
return this->tripleLayerMetatilesEnabled ? 12 : 8;
|
||||
return getNumLayersInMetatile() * Metatile::tilesPerLayer();
|
||||
}
|
||||
|
||||
void ProjectConfig::setEventIconPath(Event::Group group, const QString &path) {
|
||||
|
|
|
|||
|
|
@ -73,15 +73,21 @@ Layout *AdvanceMapParser::parseLayout(const QString &filepath, bool *error, cons
|
|||
|
||||
const QList<QString> tilesets = project->tilesetLabelsOrdered;
|
||||
|
||||
if (mapPrimaryTilesetNum > tilesets.size())
|
||||
mapLayout->tileset_primary_label = project->getDefaultPrimaryTilesetLabel();
|
||||
else
|
||||
mapLayout->tileset_primary_label = tilesets.at(mapPrimaryTilesetNum);
|
||||
const QString defaultPrimaryTileset = project->getDefaultPrimaryTilesetLabel();
|
||||
QString primaryTilesetLabel = tilesets.value(mapPrimaryTilesetNum, defaultPrimaryTileset);
|
||||
if (!project->primaryTilesetLabels.contains(primaryTilesetLabel)) {
|
||||
// AdvanceMap's primary tileset value points to a secondary tileset. Ignore it.
|
||||
primaryTilesetLabel = defaultPrimaryTileset;
|
||||
}
|
||||
const QString defaultSecondaryTileset = project->getDefaultSecondaryTilesetLabel();
|
||||
QString secondaryTilesetLabel = tilesets.value(mapSecondaryTilesetNum, defaultSecondaryTileset);
|
||||
if (!project->secondaryTilesetLabels.contains(secondaryTilesetLabel)) {
|
||||
// AdvanceMap's secondary tileset value points to a primary tileset. Ignore it.
|
||||
secondaryTilesetLabel = defaultSecondaryTileset;
|
||||
}
|
||||
|
||||
if (mapSecondaryTilesetNum > tilesets.size())
|
||||
mapLayout->tileset_secondary_label = project->getDefaultSecondaryTilesetLabel();
|
||||
else
|
||||
mapLayout->tileset_secondary_label = tilesets.at(mapSecondaryTilesetNum);
|
||||
mapLayout->tileset_primary_label = primaryTilesetLabel;
|
||||
mapLayout->tileset_secondary_label = secondaryTilesetLabel;
|
||||
|
||||
mapLayout->blockdata = blockdata;
|
||||
|
||||
|
|
@ -131,7 +137,7 @@ QList<Metatile*> AdvanceMapParser::parseMetatiles(const QString &filepath, bool
|
|||
}
|
||||
|
||||
int attrSize = Metatile::getDefaultAttributesSize(version);
|
||||
int maxMetatiles = primaryTileset ? Project::getNumMetatilesPrimary() : Project::getNumMetatilesTotal() - Project::getNumMetatilesPrimary();
|
||||
int maxMetatiles = primaryTileset ? Project::getNumMetatilesPrimary() : Project::getNumMetatilesSecondary();
|
||||
int numMetatiles = static_cast<unsigned char>(in.at(0)) |
|
||||
(static_cast<unsigned char>(in.at(1)) << 8) |
|
||||
(static_cast<unsigned char>(in.at(2)) << 16) |
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "eventframes.h"
|
||||
#include "project.h"
|
||||
#include "config.h"
|
||||
#include "metatile.h"
|
||||
|
||||
Event* Event::create(Event::Type type) {
|
||||
switch (type) {
|
||||
|
|
@ -23,6 +24,14 @@ Event::~Event() {
|
|||
delete this->eventFrame;
|
||||
}
|
||||
|
||||
int Event::getPixelX() const {
|
||||
return (this->x * Metatile::pixelWidth()) - qMax(0, (this->pixmap.width() - Metatile::pixelWidth()) / 2);
|
||||
}
|
||||
|
||||
int Event::getPixelY() const {
|
||||
return (this->y * Metatile::pixelHeight()) - qMax(0, this->pixmap.height() - Metatile::pixelHeight());
|
||||
}
|
||||
|
||||
EventFrame *Event::getEventFrame() {
|
||||
if (!this->eventFrame) createEventFrame();
|
||||
return this->eventFrame;
|
||||
|
|
@ -54,6 +63,16 @@ void Event::modify() {
|
|||
this->map->modify();
|
||||
}
|
||||
|
||||
QString Event::groupToJsonKey(Event::Group group) {
|
||||
static const QMap<Event::Group, QString> map = {
|
||||
{Event::Group::Object, "object_events"},
|
||||
{Event::Group::Warp, "warp_events"},
|
||||
{Event::Group::Coord, "coord_events"},
|
||||
{Event::Group::Bg, "bg_events"},
|
||||
};
|
||||
return map.value(group);
|
||||
}
|
||||
|
||||
const QMap<Event::Group, QString> groupToStringMap = {
|
||||
{Event::Group::Object, "Object"},
|
||||
{Event::Group::Warp, "Warp"},
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "scripting.h"
|
||||
#include "utility.h"
|
||||
#include "editcommands.h"
|
||||
#include "project.h"
|
||||
|
||||
#include <QTime>
|
||||
#include <QPainter>
|
||||
|
|
@ -15,9 +16,6 @@ Map::Map(QObject *parent) : QObject(parent)
|
|||
{
|
||||
m_editHistory = new QUndoStack(this);
|
||||
|
||||
m_scriptFileWatcher = new QFileSystemWatcher(this);
|
||||
connect(m_scriptFileWatcher, &QFileSystemWatcher::fileChanged, this, &Map::invalidateScripts);
|
||||
|
||||
resetEvents();
|
||||
|
||||
m_header = new MapHeader(this);
|
||||
|
|
@ -33,8 +31,6 @@ Map::Map(const Map &other, QObject *parent) : Map(parent) {
|
|||
*m_header = *other.m_header;
|
||||
m_layout = other.m_layout;
|
||||
m_isPersistedToFile = false;
|
||||
m_metatileLayerOrder = other.m_metatileLayerOrder;
|
||||
m_metatileLayerOpacity = other.m_metatileLayerOpacity;
|
||||
|
||||
// Copy events
|
||||
for (auto i = other.m_events.constBegin(); i != other.m_events.constEnd(); i++) {
|
||||
|
|
@ -67,44 +63,28 @@ QString Map::mapConstantFromName(const QString &name) {
|
|||
return projectConfig.getIdentifier(ProjectIdentifier::define_map_prefix) + Util::toDefineCase(name);
|
||||
}
|
||||
|
||||
int Map::getWidth() const {
|
||||
return m_layout ? m_layout->getWidth() : 0;
|
||||
}
|
||||
|
||||
int Map::getHeight() const {
|
||||
return m_layout ? m_layout->getHeight() : 0;
|
||||
}
|
||||
|
||||
int Map::getBorderWidth() const {
|
||||
return m_layout ? m_layout->getBorderWidth() : 0;
|
||||
}
|
||||
|
||||
int Map::getBorderHeight() const {
|
||||
return m_layout ? m_layout->getBorderHeight() : 0;
|
||||
}
|
||||
|
||||
// Get the portion of the map that can be rendered when rendered as a map connection.
|
||||
// Cardinal connections render the nearest segment of their map and within the bounds of the border draw distance,
|
||||
// Dive/Emerge connections are rendered normally within the bounds of their parent map.
|
||||
QRect Map::getConnectionRect(const QString &direction, Layout * fromLayout) const {
|
||||
int x = 0, y = 0;
|
||||
int w = getWidth(), h = getHeight();
|
||||
int w = pixelWidth(), h = pixelHeight();
|
||||
|
||||
QMargins viewDistance = Project::getMetatileViewDistance();
|
||||
QMargins viewDistance = Project::getPixelViewDistance();
|
||||
if (direction == "up") {
|
||||
h = qMin(h, viewDistance.top());
|
||||
y = getHeight() - h;
|
||||
y = pixelHeight() - h;
|
||||
} else if (direction == "down") {
|
||||
h = qMin(h, viewDistance.bottom());
|
||||
} else if (direction == "left") {
|
||||
w = qMin(w, viewDistance.left());
|
||||
x = getWidth() - w;
|
||||
x = pixelWidth() - w;
|
||||
} else if (direction == "right") {
|
||||
w = qMin(w, viewDistance.right());
|
||||
} else if (MapConnection::isDiving(direction)) {
|
||||
if (fromLayout) {
|
||||
w = qMin(w, fromLayout->getWidth());
|
||||
h = qMin(h, fromLayout->getHeight());
|
||||
w = qMin(w, fromLayout->pixelWidth());
|
||||
h = qMin(h, fromLayout->pixelHeight());
|
||||
}
|
||||
} else {
|
||||
// Unknown direction
|
||||
|
|
@ -127,7 +107,7 @@ QPixmap Map::renderConnection(const QString &direction, Layout * fromLayout) {
|
|||
fromLayout = nullptr;
|
||||
|
||||
QPixmap connectionPixmap = m_layout->render(true, fromLayout, bounds);
|
||||
return connectionPixmap.copy(bounds.x() * 16, bounds.y() * 16, bounds.width() * 16, bounds.height() * 16);
|
||||
return connectionPixmap.copy(bounds);
|
||||
}
|
||||
|
||||
void Map::openScript(const QString &label) {
|
||||
|
|
@ -143,7 +123,12 @@ void Map::setSharedScriptsMap(const QString &sharedScriptsMap) {
|
|||
|
||||
void Map::invalidateScripts() {
|
||||
m_scriptsLoaded = false;
|
||||
m_scriptFileWatcher->removePaths(m_scriptFileWatcher->files());
|
||||
|
||||
// m_scriptFileWatcher is a QPointer so clearing it shouldn't be necessary,
|
||||
// but it's possible that Map::getScriptLabels will be called before events are processed.
|
||||
delete m_scriptFileWatcher;
|
||||
m_scriptFileWatcher = nullptr;
|
||||
|
||||
emit scriptsModified();
|
||||
}
|
||||
|
||||
|
|
@ -158,14 +143,32 @@ QStringList Map::getScriptLabels(Event::Group group) {
|
|||
.arg(Util::stripPrefix(scriptsFilepath, projectConfig.projectDir() + "/"))
|
||||
.arg(m_name)
|
||||
.arg(error));
|
||||
|
||||
// Setting this flag here (and below) lets us skip some steps and logging if we already know it failed.
|
||||
// Script labels may be re-requested often, so we don't want to fill the log with warnings.
|
||||
m_loggedScriptsFileError = true;
|
||||
}
|
||||
|
||||
if (!m_scriptFileWatcher->files().contains(scriptsFilepath) && !m_scriptFileWatcher->addPath(scriptsFilepath) && !m_loggedScriptsFileError) {
|
||||
logWarn(QString("Failed to add scripts file '%1' to file watcher for %2.")
|
||||
.arg(Util::stripPrefix(scriptsFilepath, projectConfig.projectDir() + "/"))
|
||||
.arg(m_name));
|
||||
m_loggedScriptsFileError = true;
|
||||
if (porymapConfig.monitorFiles && !m_loggedScriptsFileError) {
|
||||
if (!m_scriptFileWatcher) {
|
||||
// Only create the file watcher when it's first needed (even an empty QFileSystemWatcher will consume system resources).
|
||||
// The other option would be for Porymap to have a single global QFileSystemWatcher, but that has complications of its own.
|
||||
m_scriptFileWatcher = new QFileSystemWatcher(this);
|
||||
connect(m_scriptFileWatcher, &QFileSystemWatcher::fileChanged, this, &Map::invalidateScripts);
|
||||
}
|
||||
// m_scriptFileWatcher can stil be nullptr here if the inotify limit was reached on Linux.
|
||||
// Porymap isn't using enough resources in general for this to be a problem, but the user may have lowered the inotify limit.
|
||||
if (!m_scriptFileWatcher) {
|
||||
logWarn(QString("Failed to add scripts file '%1' to file watcher for %2: Reached system resource limit.")
|
||||
.arg(Util::stripPrefix(scriptsFilepath, projectConfig.projectDir() + "/"))
|
||||
.arg(m_name));
|
||||
m_loggedScriptsFileError = true;
|
||||
} else if (!m_scriptFileWatcher->files().contains(scriptsFilepath) && !m_scriptFileWatcher->addPath(scriptsFilepath)) {
|
||||
logWarn(QString("Failed to add scripts file '%1' to file watcher for %2.")
|
||||
.arg(Util::stripPrefix(scriptsFilepath, projectConfig.projectDir() + "/"))
|
||||
.arg(m_name));
|
||||
m_loggedScriptsFileError = true;
|
||||
}
|
||||
}
|
||||
|
||||
m_scriptsLoaded = true;
|
||||
|
|
@ -278,14 +281,23 @@ int Map::getNumEvents(Event::Group group) const {
|
|||
if (group == Event::Group::None) {
|
||||
// Total number of events
|
||||
int numEvents = 0;
|
||||
for (auto i = m_events.constBegin(); i != m_events.constEnd(); i++) {
|
||||
numEvents += i.value().length();
|
||||
for (auto it = m_events.constBegin(); it != m_events.constEnd(); it++) {
|
||||
numEvents += it.value().length();
|
||||
}
|
||||
return numEvents;
|
||||
}
|
||||
return m_events[group].length();
|
||||
}
|
||||
|
||||
bool Map::hasEvents() const {
|
||||
for (auto it = m_events.constBegin(); it != m_events.constEnd(); it++) {
|
||||
if (!it.value().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Map::removeEvent(Event *event) {
|
||||
for (auto i = m_events.begin(); i != m_events.end(); i++) {
|
||||
i.value().removeAll(event);
|
||||
|
|
|
|||
|
|
@ -72,20 +72,20 @@ QPixmap MapConnection::render() const {
|
|||
// For right/down connections this is offset by the dimensions of the parent map.
|
||||
// For left/up connections this is offset by the dimensions of the target map.
|
||||
// If 'clipped' is true, only the rendered dimensions of the target map will be used, rather than its full dimensions.
|
||||
QPoint MapConnection::relativePos(bool clipped) const {
|
||||
QPoint MapConnection::relativePixelPos(bool clipped) const {
|
||||
int x = 0, y = 0;
|
||||
if (m_direction == "right") {
|
||||
if (m_parentMap) x = m_parentMap->getWidth();
|
||||
y = m_offset;
|
||||
if (m_parentMap) x = m_parentMap->pixelWidth();
|
||||
y = m_offset * Metatile::pixelHeight();
|
||||
} else if (m_direction == "down") {
|
||||
x = m_offset;
|
||||
if (m_parentMap) y = m_parentMap->getHeight();
|
||||
x = m_offset * Metatile::pixelWidth();
|
||||
if (m_parentMap) y = m_parentMap->pixelHeight();
|
||||
} else if (m_direction == "left") {
|
||||
if (targetMap()) x = !clipped ? -targetMap()->getWidth() : -targetMap()->getConnectionRect(m_direction).width();
|
||||
y = m_offset;
|
||||
if (targetMap()) x = !clipped ? -targetMap()->pixelWidth() : -targetMap()->getConnectionRect(m_direction).width();
|
||||
y = m_offset * Metatile::pixelHeight();
|
||||
} else if (m_direction == "up") {
|
||||
x = m_offset;
|
||||
if (targetMap()) y = !clipped ? -targetMap()->getHeight() : -targetMap()->getConnectionRect(m_direction).height();
|
||||
x = m_offset * Metatile::pixelWidth();
|
||||
if (targetMap()) y = !clipped ? -targetMap()->pixelHeight() : -targetMap()->getConnectionRect(m_direction).height();
|
||||
}
|
||||
return QPoint(x, y);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,11 @@
|
|||
#include "scripting.h"
|
||||
#include "imageproviders.h"
|
||||
#include "utility.h"
|
||||
#include "project.h"
|
||||
#include "layoutpixmapitem.h"
|
||||
|
||||
QList<int> Layout::s_globalMetatileLayerOrder;
|
||||
QList<float> Layout::s_globalMetatileLayerOpacity;
|
||||
|
||||
Layout::Layout(const Layout &other) : Layout() {
|
||||
copyFrom(&other);
|
||||
|
|
@ -55,6 +60,10 @@ bool Layout::isWithinBounds(int x, int y) const {
|
|||
return (x >= 0 && x < this->getWidth() && y >= 0 && y < this->getHeight());
|
||||
}
|
||||
|
||||
bool Layout::isWithinBounds(const QPoint &pos) const {
|
||||
return isWithinBounds(pos.x(), pos.y());
|
||||
}
|
||||
|
||||
bool Layout::isWithinBounds(const QRect &rect) const {
|
||||
return rect.left() >= 0 && rect.right() < this->getWidth() && rect.top() >= 0 && rect.bottom() < this->getHeight();
|
||||
}
|
||||
|
|
@ -85,15 +94,14 @@ QMargins Layout::getBorderMargins() const {
|
|||
return distance;
|
||||
}
|
||||
|
||||
// Get a rectangle that represents (in pixels) the layout's map area and the visible area of its border.
|
||||
// At maximum, this is equal to the map size plus the border margins.
|
||||
// If the border is large (and so beyond player the view) it may be smaller than that.
|
||||
// Get a rectangle that represents (in pixels) the layout's map area + the distance the player can see.
|
||||
// Note that this may be smaller than the map area + the size of the border for layouts with large border dimensions.
|
||||
QRect Layout::getVisibleRect() const {
|
||||
QRect area = QRect(0, 0, this->width * 16, this->height * 16);
|
||||
return area += (Project::getMetatileViewDistance() * 16);
|
||||
QRect area = QRect(0, 0, this->pixelWidth(), this->pixelHeight());
|
||||
return area += Project::getPixelViewDistance();
|
||||
}
|
||||
|
||||
bool Layout::getBlock(int x, int y, Block *out) {
|
||||
bool Layout::getBlock(int x, int y, Block *out) const {
|
||||
if (isWithinBounds(x, y)) {
|
||||
int i = y * getWidth() + x;
|
||||
*out = this->blockdata.value(i);
|
||||
|
|
@ -128,6 +136,20 @@ void Layout::setBlockdata(Blockdata newBlockdata, bool enableScriptCallback) {
|
|||
}
|
||||
}
|
||||
|
||||
uint16_t Layout::getMetatileId(int x, int y) const {
|
||||
Block block;
|
||||
return getBlock(x, y, &block) ? block.metatileId() : 0;
|
||||
}
|
||||
|
||||
bool Layout::setMetatileId(int x, int y, uint16_t metatileId, bool enableScriptCallback) {
|
||||
Block block;
|
||||
if (!getBlock(x, y, &block)) {
|
||||
return false;
|
||||
}
|
||||
setBlock(x, y, Block(metatileId, block.collision(), block.elevation()), enableScriptCallback);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Layout::clearBorderCache() {
|
||||
this->cached_border.clear();
|
||||
}
|
||||
|
|
@ -337,15 +359,13 @@ void Layout::magicFillCollisionElevation(int initialX, int initialY, uint16_t co
|
|||
}
|
||||
}
|
||||
|
||||
QPixmap Layout::render(bool ignoreCache, Layout *fromLayout, QRect bounds) {
|
||||
QPixmap Layout::render(bool ignoreCache, Layout *fromLayout, const QRect &bounds) {
|
||||
bool changed_any = false;
|
||||
int width_ = getWidth();
|
||||
int height_ = getHeight();
|
||||
if (this->image.isNull() || this->image.width() != width_ * 16 || this->image.height() != height_ * 16) {
|
||||
this->image = QImage(width_ * 16, height_ * 16, QImage::Format_RGBA8888);
|
||||
if (this->image.isNull() || this->image.width() != pixelWidth() || this->image.height() != pixelHeight()) {
|
||||
this->image = QImage(pixelWidth(), pixelHeight(), QImage::Format_RGBA8888);
|
||||
changed_any = true;
|
||||
}
|
||||
if (this->blockdata.isEmpty() || !width_ || !height_) {
|
||||
if (this->blockdata.isEmpty() || this->width == 0 || this->height == 0) {
|
||||
this->pixmap = this->pixmap.fromImage(this->image);
|
||||
return this->pixmap;
|
||||
}
|
||||
|
|
@ -361,9 +381,9 @@ QPixmap Layout::render(bool ignoreCache, Layout *fromLayout, QRect bounds) {
|
|||
if (!ignoreCache && !layoutBlockChanged(i, this->blockdata, this->cached_blockdata)) {
|
||||
continue;
|
||||
}
|
||||
int map_y = width_ ? i / width_ : 0;
|
||||
int map_x = width_ ? i % width_ : 0;
|
||||
if (bounds.isValid() && !bounds.contains(map_x, map_y)) {
|
||||
int x = this->width ? ((i % this->width) * Metatile::pixelWidth()) : 0;
|
||||
int y = this->width ? ((i / this->width) * Metatile::pixelHeight()) : 0;
|
||||
if (bounds.isValid() && !bounds.contains(x, y)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -376,14 +396,12 @@ QPixmap Layout::render(bool ignoreCache, Layout *fromLayout, QRect bounds) {
|
|||
metatileId,
|
||||
fromLayout ? fromLayout->tileset_primary : this->tileset_primary,
|
||||
fromLayout ? fromLayout->tileset_secondary : this->tileset_secondary,
|
||||
metatileLayerOrder,
|
||||
metatileLayerOpacity
|
||||
metatileLayerOrder(),
|
||||
metatileLayerOpacity()
|
||||
);
|
||||
imageCache.insert(metatileId, metatileImage);
|
||||
}
|
||||
|
||||
QPoint metatileOrigin = QPoint(map_x * 16, map_y * 16);
|
||||
painter.drawImage(metatileOrigin, metatileImage);
|
||||
painter.drawImage(x, y, metatileImage);
|
||||
changed_any = true;
|
||||
}
|
||||
painter.end();
|
||||
|
|
@ -397,13 +415,11 @@ QPixmap Layout::render(bool ignoreCache, Layout *fromLayout, QRect bounds) {
|
|||
|
||||
QPixmap Layout::renderCollision(bool ignoreCache) {
|
||||
bool changed_any = false;
|
||||
int width_ = getWidth();
|
||||
int height_ = getHeight();
|
||||
if (collision_image.isNull() || collision_image.width() != width_ * 16 || collision_image.height() != height_ * 16) {
|
||||
collision_image = QImage(width_ * 16, height_ * 16, QImage::Format_RGBA8888);
|
||||
if (collision_image.isNull() || collision_image.width() != pixelWidth() || collision_image.height() != pixelHeight()) {
|
||||
collision_image = QImage(pixelWidth(), pixelHeight(), QImage::Format_RGBA8888);
|
||||
changed_any = true;
|
||||
}
|
||||
if (this->blockdata.isEmpty() || !width_ || !height_) {
|
||||
if (this->blockdata.isEmpty() || this->width == 0 || this->height == 0) {
|
||||
collision_pixmap = collision_pixmap.fromImage(collision_image);
|
||||
return collision_pixmap;
|
||||
}
|
||||
|
|
@ -415,10 +431,9 @@ QPixmap Layout::renderCollision(bool ignoreCache) {
|
|||
changed_any = true;
|
||||
Block block = this->blockdata.at(i);
|
||||
QImage collision_metatile_image = getCollisionMetatileImage(block);
|
||||
int map_y = width_ ? i / width_ : 0;
|
||||
int map_x = width_ ? i % width_ : 0;
|
||||
QPoint metatile_origin = QPoint(map_x * 16, map_y * 16);
|
||||
painter.drawImage(metatile_origin, collision_metatile_image);
|
||||
int x = this->width ? ((i % this->width) * Metatile::pixelWidth()) : 0;
|
||||
int y = this->width ? ((i / this->width) * Metatile::pixelHeight()) : 0;
|
||||
painter.drawImage(x, y, collision_metatile_image);
|
||||
}
|
||||
painter.end();
|
||||
cacheCollision();
|
||||
|
|
@ -430,14 +445,14 @@ QPixmap Layout::renderCollision(bool ignoreCache) {
|
|||
|
||||
QPixmap Layout::renderBorder(bool ignoreCache) {
|
||||
bool changed_any = false, border_resized = false;
|
||||
int width_ = getBorderWidth();
|
||||
int height_ = getBorderHeight();
|
||||
int pixelWidth = this->border_width * Metatile::pixelWidth();
|
||||
int pixelHeight = this->border_height * Metatile::pixelHeight();
|
||||
if (this->border_image.isNull()) {
|
||||
this->border_image = QImage(width_ * 16, height_ * 16, QImage::Format_RGBA8888);
|
||||
this->border_image = QImage(pixelWidth, pixelHeight, QImage::Format_RGBA8888);
|
||||
changed_any = true;
|
||||
}
|
||||
if (this->border_image.width() != width_ * 16 || this->border_image.height() != height_ * 16) {
|
||||
this->border_image = QImage(width_ * 16, height_ * 16, QImage::Format_RGBA8888);
|
||||
if (this->border_image.width() != pixelWidth || this->border_image.height() != pixelHeight) {
|
||||
this->border_image = QImage(pixelWidth, pixelHeight, QImage::Format_RGBA8888);
|
||||
border_resized = true;
|
||||
}
|
||||
if (this->border.isEmpty()) {
|
||||
|
|
@ -453,10 +468,10 @@ QPixmap Layout::renderBorder(bool ignoreCache) {
|
|||
changed_any = true;
|
||||
Block block = this->border.at(i);
|
||||
uint16_t metatileId = block.metatileId();
|
||||
QImage metatile_image = getMetatileImage(metatileId, this->tileset_primary, this->tileset_secondary, metatileLayerOrder, metatileLayerOpacity);
|
||||
int map_y = width_ ? i / width_ : 0;
|
||||
int map_x = width_ ? i % width_ : 0;
|
||||
painter.drawImage(QPoint(map_x * 16, map_y * 16), metatile_image);
|
||||
QImage metatile_image = getMetatileImage(metatileId, this);
|
||||
int x = this->border_width ? ((i % this->border_width) * Metatile::pixelWidth()) : 0;
|
||||
int y = this->border_width ? ((i / this->border_width) * Metatile::pixelHeight()) : 0;
|
||||
painter.drawImage(x, y, metatile_image);
|
||||
}
|
||||
painter.end();
|
||||
if (changed_any) {
|
||||
|
|
@ -531,6 +546,7 @@ bool Layout::loadBorder(const QString &root) {
|
|||
logError(QString("Failed to load border for %1 from '%2': %3").arg(this->name).arg(path).arg(error));
|
||||
return false;
|
||||
}
|
||||
this->border = blockdata;
|
||||
|
||||
// 0 is an expected border width/height that should be handled, GF used it for the RS layouts in FRLG
|
||||
if (this->border_width <= 0) {
|
||||
|
|
@ -540,10 +556,6 @@ bool Layout::loadBorder(const QString &root) {
|
|||
this->border_height = DEFAULT_BORDER_HEIGHT;
|
||||
}
|
||||
|
||||
this->border = blockdata;
|
||||
this->lastCommitBlocks.border = blockdata;
|
||||
this->lastCommitBlocks.borderDimensions = QSize(this->border_width, this->border_height);
|
||||
|
||||
int expectedSize = this->border_width * this->border_height;
|
||||
if (this->border.count() != expectedSize) {
|
||||
logWarn(QString("%1 border blockdata length %2 does not match dimensions %3x%4 (should be %5). Resizing border blockdata.")
|
||||
|
|
@ -554,6 +566,10 @@ bool Layout::loadBorder(const QString &root) {
|
|||
.arg(expectedSize));
|
||||
this->border.resize(expectedSize);
|
||||
}
|
||||
|
||||
this->lastCommitBlocks.border = this->border;
|
||||
this->lastCommitBlocks.borderDimensions = QSize(this->border_width, this->border_height);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -570,10 +586,7 @@ bool Layout::loadBlockdata(const QString &root) {
|
|||
logError(QString("Failed to load blockdata for %1 from '%2': %3").arg(this->name).arg(path).arg(error));
|
||||
return false;
|
||||
}
|
||||
|
||||
this->blockdata = blockdata;
|
||||
this->lastCommitBlocks.blocks = blockdata;
|
||||
this->lastCommitBlocks.layoutDimensions = QSize(this->width, this->height);
|
||||
|
||||
int expectedSize = this->width * this->height;
|
||||
if (expectedSize <= 0) {
|
||||
|
|
@ -589,6 +602,10 @@ bool Layout::loadBlockdata(const QString &root) {
|
|||
.arg(expectedSize));
|
||||
this->blockdata.resize(expectedSize);
|
||||
}
|
||||
|
||||
this->lastCommitBlocks.blocks = this->blockdata;
|
||||
this->lastCommitBlocks.layoutDimensions = QSize(this->width, this->height);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,8 +36,10 @@ int Metatile::getIndexInTileset(int metatileId) {
|
|||
}
|
||||
|
||||
QPoint Metatile::coordFromPixmapCoord(const QPointF &pixelCoord) {
|
||||
int x = static_cast<int>(pixelCoord.x()) / 16;
|
||||
int y = static_cast<int>(pixelCoord.y()) / 16;
|
||||
int x = static_cast<int>(pixelCoord.x()) / pixelWidth();
|
||||
int y = static_cast<int>(pixelCoord.y()) / pixelHeight();
|
||||
if (pixelCoord.x() < 0) x--;
|
||||
if (pixelCoord.y() < 0) y--;
|
||||
return QPoint(x, y);
|
||||
}
|
||||
|
||||
|
|
@ -46,13 +48,18 @@ QString Metatile::getMetatileIdString(uint16_t metatileId) {
|
|||
return Util::toHexString(metatileId, numMetatileIdChars);
|
||||
};
|
||||
|
||||
QString Metatile::getMetatileIdStrings(const QList<uint16_t> metatileIds) {
|
||||
QString Metatile::getMetatileIdStrings(const QList<uint16_t> &metatileIds) {
|
||||
QStringList metatiles;
|
||||
for (auto metatileId : metatileIds)
|
||||
metatiles << Metatile::getMetatileIdString(metatileId);
|
||||
return metatiles.join(",");
|
||||
};
|
||||
|
||||
QString Metatile::getLayerName(int layerNum) {
|
||||
static const QStringList layerTitles = { "Bottom", "Middle", "Top"};
|
||||
return layerTitles.value(layerNum);
|
||||
}
|
||||
|
||||
// Read and pack together this metatile's attributes.
|
||||
uint32_t Metatile::getAttributes() const {
|
||||
uint32_t data = 0;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#ifdef QT_NETWORK_LIB
|
||||
#include "network.h"
|
||||
#include "config.h"
|
||||
|
||||
|
|
@ -148,3 +149,5 @@ void NetworkAccessManager::processReply(QNetworkReply * reply, NetworkReplyData
|
|||
|
||||
cacheEntry->data = data->m_body = reply->readAll();
|
||||
}
|
||||
|
||||
#endif // QT_NETWORK_LIB
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <QPainter>
|
||||
#include <QImage>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
Tileset::Tileset(const Tileset &other)
|
||||
|
|
@ -20,15 +21,15 @@ Tileset::Tileset(const Tileset &other)
|
|||
metatile_attrs_label(other.metatile_attrs_label),
|
||||
metatile_attrs_path(other.metatile_attrs_path),
|
||||
tilesImagePath(other.tilesImagePath),
|
||||
tilesImage(other.tilesImage.copy()),
|
||||
palettePaths(other.palettePaths),
|
||||
metatileLabels(other.metatileLabels),
|
||||
palettes(other.palettes),
|
||||
palettePreviews(other.palettePreviews),
|
||||
m_tilesImage(other.m_tilesImage.copy()),
|
||||
m_hasUnsavedTilesImage(other.m_hasUnsavedTilesImage)
|
||||
{
|
||||
for (auto tile : other.tiles) {
|
||||
tiles.append(tile.copy());
|
||||
for (auto tile : other.m_tiles) {
|
||||
m_tiles.append(tile.copy());
|
||||
}
|
||||
|
||||
for (auto *metatile : other.m_metatiles) {
|
||||
|
|
@ -46,15 +47,15 @@ Tileset &Tileset::operator=(const Tileset &other) {
|
|||
metatile_attrs_label = other.metatile_attrs_label;
|
||||
metatile_attrs_path = other.metatile_attrs_path;
|
||||
tilesImagePath = other.tilesImagePath;
|
||||
tilesImage = other.tilesImage.copy();
|
||||
m_tilesImage = other.m_tilesImage.copy();
|
||||
palettePaths = other.palettePaths;
|
||||
metatileLabels = other.metatileLabels;
|
||||
palettes = other.palettes;
|
||||
palettePreviews = other.palettePreviews;
|
||||
|
||||
tiles.clear();
|
||||
for (auto tile : other.tiles) {
|
||||
tiles.append(tile.copy());
|
||||
m_tiles.clear();
|
||||
for (auto tile : other.m_tiles) {
|
||||
m_tiles.append(tile.copy());
|
||||
}
|
||||
|
||||
clearMetatiles();
|
||||
|
|
@ -94,7 +95,50 @@ void Tileset::resizeMetatiles(int newNumMetatiles) {
|
|||
}
|
||||
}
|
||||
|
||||
uint16_t Tileset::firstMetatileId() const {
|
||||
return this->is_secondary ? Project::getNumMetatilesPrimary() : 0;
|
||||
}
|
||||
|
||||
uint16_t Tileset::lastMetatileId() const {
|
||||
return qMax(1, firstMetatileId() + m_metatiles.length()) - 1;
|
||||
}
|
||||
|
||||
int Tileset::maxMetatiles() const {
|
||||
return this->is_secondary ? Project::getNumMetatilesSecondary() : Project::getNumMetatilesPrimary();
|
||||
}
|
||||
|
||||
uint16_t Tileset::firstTileId() const {
|
||||
return this->is_secondary ? Project::getNumTilesPrimary() : 0;
|
||||
}
|
||||
|
||||
uint16_t Tileset::lastTileId() const {
|
||||
return qMax(1, firstMetatileId() + m_tiles.length()) - 1;
|
||||
}
|
||||
|
||||
int Tileset::maxTiles() const {
|
||||
return this->is_secondary ? Project::getNumTilesSecondary() : Project::getNumTilesPrimary();
|
||||
}
|
||||
|
||||
Tileset* Tileset::getPaletteTileset(int paletteId, Tileset *primaryTileset, Tileset *secondaryTileset) {
|
||||
return const_cast<Tileset*>(getPaletteTileset(paletteId, static_cast<const Tileset*>(primaryTileset), static_cast<const Tileset*>(secondaryTileset)));
|
||||
}
|
||||
|
||||
const Tileset* Tileset::getPaletteTileset(int paletteId, const Tileset *primaryTileset, const Tileset *secondaryTileset) {
|
||||
if (paletteId < Project::getNumPalettesPrimary()) {
|
||||
return primaryTileset;
|
||||
} else if (paletteId < Project::getNumPalettesTotal()) {
|
||||
return secondaryTileset;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Tileset* Tileset::getTileTileset(int tileId, Tileset *primaryTileset, Tileset *secondaryTileset) {
|
||||
return const_cast<Tileset*>(getTileTileset(tileId, static_cast<const Tileset*>(primaryTileset), static_cast<const Tileset*>(secondaryTileset)));
|
||||
}
|
||||
|
||||
// Get the tileset *expected* to contain the given 'tileId'. Note that this does not mean the tile actually exists in that tileset.
|
||||
const Tileset* Tileset::getTileTileset(int tileId, const Tileset *primaryTileset, const Tileset *secondaryTileset) {
|
||||
if (tileId < Project::getNumTilesPrimary()) {
|
||||
return primaryTileset;
|
||||
} else if (tileId < Project::getNumTilesTotal()) {
|
||||
|
|
@ -105,6 +149,11 @@ Tileset* Tileset::getTileTileset(int tileId, Tileset *primaryTileset, Tileset *s
|
|||
}
|
||||
|
||||
Tileset* Tileset::getMetatileTileset(int metatileId, Tileset *primaryTileset, Tileset *secondaryTileset) {
|
||||
return const_cast<Tileset*>(getMetatileTileset(metatileId, static_cast<const Tileset*>(primaryTileset), static_cast<const Tileset*>(secondaryTileset)));
|
||||
}
|
||||
|
||||
// Get the tileset *expected* to contain the given 'metatileId'. Note that this does not mean the metatile actually exists in that tileset.
|
||||
const Tileset* Tileset::getMetatileTileset(int metatileId, const Tileset *primaryTileset, const Tileset *secondaryTileset) {
|
||||
if (metatileId < Project::getNumMetatilesPrimary()) {
|
||||
return primaryTileset;
|
||||
} else if (metatileId < Project::getNumMetatilesTotal()) {
|
||||
|
|
@ -115,7 +164,11 @@ Tileset* Tileset::getMetatileTileset(int metatileId, Tileset *primaryTileset, Ti
|
|||
}
|
||||
|
||||
Metatile* Tileset::getMetatile(int metatileId, Tileset *primaryTileset, Tileset *secondaryTileset) {
|
||||
Tileset *tileset = Tileset::getMetatileTileset(metatileId, primaryTileset, secondaryTileset);
|
||||
return const_cast<Metatile*>(getMetatile(metatileId, static_cast<const Tileset*>(primaryTileset), static_cast<const Tileset*>(secondaryTileset)));
|
||||
}
|
||||
|
||||
const Metatile* Tileset::getMetatile(int metatileId, const Tileset *primaryTileset, const Tileset *secondaryTileset) {
|
||||
const Tileset *tileset = Tileset::getMetatileTileset(metatileId, primaryTileset, secondaryTileset);
|
||||
if (!tileset) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -200,46 +253,48 @@ QString Tileset::getMetatileLabelPrefix()
|
|||
QString Tileset::getMetatileLabelPrefix(const QString &name)
|
||||
{
|
||||
// Default is "gTileset_Name" --> "METATILE_Name_"
|
||||
const QString tilesetPrefix = projectConfig.getIdentifier(ProjectIdentifier::symbol_tilesets_prefix);
|
||||
const QString labelPrefix = projectConfig.getIdentifier(ProjectIdentifier::define_metatile_label_prefix);
|
||||
return QString("%1%2_").arg(labelPrefix).arg(QString(name).replace(tilesetPrefix, ""));
|
||||
return QString("%1%2_").arg(labelPrefix).arg(Tileset::stripPrefix(name));
|
||||
}
|
||||
|
||||
bool Tileset::metatileIsValid(uint16_t metatileId, Tileset *primaryTileset, Tileset *secondaryTileset) {
|
||||
if (metatileId >= Project::getNumMetatilesTotal())
|
||||
return false;
|
||||
|
||||
if (metatileId < Project::getNumMetatilesPrimary() && metatileId >= primaryTileset->numMetatiles())
|
||||
return false;
|
||||
|
||||
if (metatileId >= Project::getNumMetatilesPrimary() + secondaryTileset->numMetatiles())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
bool Tileset::metatileIsValid(uint16_t metatileId, const Tileset *primaryTileset, const Tileset *secondaryTileset) {
|
||||
return (primaryTileset && primaryTileset->containsMetatileId(metatileId))
|
||||
|| (secondaryTileset && secondaryTileset->containsMetatileId(metatileId));
|
||||
}
|
||||
|
||||
QList<QList<QRgb>> Tileset::getBlockPalettes(Tileset *primaryTileset, Tileset *secondaryTileset, bool useTruePalettes) {
|
||||
QList<QList<QRgb>> Tileset::getBlockPalettes(const Tileset *primaryTileset, const Tileset *secondaryTileset, bool useTruePalettes) {
|
||||
QList<QList<QRgb>> palettes;
|
||||
auto primaryPalettes = useTruePalettes ? primaryTileset->palettes : primaryTileset->palettePreviews;
|
||||
|
||||
QList<QList<QRgb>> primaryPalettes;
|
||||
if (primaryTileset) {
|
||||
primaryPalettes = useTruePalettes ? primaryTileset->palettes : primaryTileset->palettePreviews;
|
||||
}
|
||||
for (int i = 0; i < Project::getNumPalettesPrimary(); i++) {
|
||||
palettes.append(primaryPalettes.at(i));
|
||||
palettes.append(primaryPalettes.value(i));
|
||||
}
|
||||
|
||||
QList<QList<QRgb>> secondaryPalettes;
|
||||
if (secondaryTileset) {
|
||||
secondaryPalettes = useTruePalettes ? secondaryTileset->palettes : secondaryTileset->palettePreviews;
|
||||
}
|
||||
auto secondaryPalettes = useTruePalettes ? secondaryTileset->palettes : secondaryTileset->palettePreviews;
|
||||
for (int i = Project::getNumPalettesPrimary(); i < Project::getNumPalettesTotal(); i++) {
|
||||
palettes.append(secondaryPalettes.at(i));
|
||||
palettes.append(secondaryPalettes.value(i));
|
||||
}
|
||||
|
||||
return palettes;
|
||||
}
|
||||
|
||||
QList<QRgb> Tileset::getPalette(int paletteId, Tileset *primaryTileset, Tileset *secondaryTileset, bool useTruePalettes) {
|
||||
QList<QRgb> Tileset::getPalette(int paletteId, const Tileset *primaryTileset, const Tileset *secondaryTileset, bool useTruePalettes) {
|
||||
QList<QRgb> paletteTable;
|
||||
Tileset *tileset = paletteId < Project::getNumPalettesPrimary()
|
||||
const Tileset *tileset = paletteId < Project::getNumPalettesPrimary()
|
||||
? primaryTileset
|
||||
: secondaryTileset;
|
||||
auto palettes = useTruePalettes ? tileset->palettes : tileset->palettePreviews;
|
||||
if (!tileset) {
|
||||
return paletteTable;
|
||||
}
|
||||
|
||||
if (paletteId < 0 || paletteId >= palettes.length()){
|
||||
logError(QString("Invalid tileset palette id '%1' requested.").arg(paletteId));
|
||||
auto palettes = useTruePalettes ? tileset->palettes : tileset->palettePreviews;
|
||||
if (paletteId < 0 || paletteId >= palettes.length()) {
|
||||
return paletteTable;
|
||||
}
|
||||
|
||||
|
|
@ -316,7 +371,7 @@ bool Tileset::appendToGraphics(const QString &filepath, const QString &friendlyN
|
|||
dataString.append(QString("\t.incbin \"%1\"\n").arg(tilesPath));
|
||||
} else {
|
||||
// Append to C file
|
||||
dataString.append(QString("const u16 gTilesetPalettes_%1[][16] =\n{\n").arg(friendlyName));
|
||||
dataString.append(QString("const u16 gTilesetPalettes_%1[][%2] =\n{\n").arg(friendlyName).arg(Tileset::numColorsPerPalette()));
|
||||
for (int i = 0; i < Project::getNumPalettesTotal(); i++)
|
||||
dataString.append(QString(" INCBIN_U16(\"%1%2%3\"),\n").arg(palettesPath).arg(i, 2, 10, QLatin1Char('0')).arg(palettesExt));
|
||||
dataString.append("};\n");
|
||||
|
|
@ -373,8 +428,7 @@ QString Tileset::getExpectedDir(QString tilesetName, bool isSecondary)
|
|||
: projectConfig.getFilePath(ProjectFilePath::data_primary_tilesets_folders);
|
||||
|
||||
static const QRegularExpression re("([a-z])([A-Z0-9])");
|
||||
const QString prefix = projectConfig.getIdentifier(ProjectIdentifier::symbol_tilesets_prefix);
|
||||
return basePath + tilesetName.replace(prefix, "").replace(re, "\\1_\\2").toLower();
|
||||
return basePath + Tileset::stripPrefix(tilesetName).replace(re, "\\1_\\2").toLower();
|
||||
}
|
||||
|
||||
// Get the expected positions of the members in struct Tileset.
|
||||
|
|
@ -400,17 +454,25 @@ QHash<int, QString> Tileset::getHeaderMemberMap(bool usingAsm)
|
|||
bool Tileset::loadMetatiles() {
|
||||
clearMetatiles();
|
||||
|
||||
QFile metatiles_file(this->metatiles_path);
|
||||
if (!metatiles_file.open(QIODevice::ReadOnly)) {
|
||||
logError(QString("Could not open '%1' for reading: %2").arg(this->metatiles_path).arg(metatiles_file.errorString()));
|
||||
QFile file(this->metatiles_path);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
logError(QString("Could not open '%1' for reading: %2").arg(this->metatiles_path).arg(file.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray data = metatiles_file.readAll();
|
||||
QByteArray data = file.readAll();
|
||||
int tilesPerMetatile = projectConfig.getNumTilesInMetatile();
|
||||
int bytesPerMetatile = 2 * tilesPerMetatile;
|
||||
int num_metatiles = data.length() / bytesPerMetatile;
|
||||
for (int i = 0; i < num_metatiles; i++) {
|
||||
int bytesPerMetatile = Tile::sizeInBytes() * tilesPerMetatile;
|
||||
int numMetatiles = data.length() / bytesPerMetatile;
|
||||
if (numMetatiles > maxMetatiles()) {
|
||||
logWarn(QString("%1 metatile count %2 exceeds limit of %3. Additional metatiles will be ignored.")
|
||||
.arg(this->name)
|
||||
.arg(numMetatiles)
|
||||
.arg(maxMetatiles()));
|
||||
numMetatiles = maxMetatiles();
|
||||
}
|
||||
|
||||
for (int i = 0; i < numMetatiles; i++) {
|
||||
auto metatile = new Metatile;
|
||||
int index = i * bytesPerMetatile;
|
||||
for (int j = 0; j < tilesPerMetatile; j++) {
|
||||
|
|
@ -424,9 +486,9 @@ bool Tileset::loadMetatiles() {
|
|||
}
|
||||
|
||||
bool Tileset::saveMetatiles() {
|
||||
QFile metatiles_file(this->metatiles_path);
|
||||
if (!metatiles_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
logError(QString("Could not open '%1' for writing: %2").arg(this->metatiles_path).arg(metatiles_file.errorString()));
|
||||
QFile file(this->metatiles_path);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
logError(QString("Could not open '%1' for writing: %2").arg(this->metatiles_path).arg(file.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -434,31 +496,40 @@ bool Tileset::saveMetatiles() {
|
|||
int numTiles = projectConfig.getNumTilesInMetatile();
|
||||
for (const auto &metatile : m_metatiles) {
|
||||
for (int i = 0; i < numTiles; i++) {
|
||||
uint16_t tile = metatile->tiles.at(i).rawValue();
|
||||
uint16_t tile = metatile->tiles.value(i).rawValue();
|
||||
data.append(static_cast<char>(tile));
|
||||
data.append(static_cast<char>(tile >> 8));
|
||||
}
|
||||
}
|
||||
metatiles_file.write(data);
|
||||
file.write(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Tileset::loadMetatileAttributes() {
|
||||
QFile attrs_file(this->metatile_attrs_path);
|
||||
if (!attrs_file.open(QIODevice::ReadOnly)) {
|
||||
logError(QString("Could not open '%1' for reading: %2").arg(this->metatile_attrs_path).arg(attrs_file.errorString()));
|
||||
QFile file(this->metatile_attrs_path);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
logError(QString("Could not open '%1' for reading: %2").arg(this->metatile_attrs_path).arg(file.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray data = attrs_file.readAll();
|
||||
QByteArray data = file.readAll();
|
||||
int attrSize = projectConfig.metatileAttributesSize;
|
||||
int numMetatiles = m_metatiles.length();
|
||||
int numMetatileAttrs = data.length() / attrSize;
|
||||
if (numMetatiles != numMetatileAttrs) {
|
||||
logWarn(QString("Metatile count %1 does not match metatile attribute count %2 in %3").arg(numMetatiles).arg(numMetatileAttrs).arg(this->name));
|
||||
if (numMetatileAttrs > numMetatiles) {
|
||||
logWarn(QString("%1 metatile attributes count %2 exceeds metatile count of %3. Additional attributes will be ignored.")
|
||||
.arg(this->name)
|
||||
.arg(numMetatileAttrs)
|
||||
.arg(numMetatiles));
|
||||
numMetatileAttrs = numMetatiles;
|
||||
} else if (numMetatileAttrs < numMetatiles) {
|
||||
logWarn(QString("%1 metatile attributes count %2 is fewer than the metatile count of %3. Missing attributes will default to 0.")
|
||||
.arg(this->name)
|
||||
.arg(numMetatileAttrs)
|
||||
.arg(numMetatiles));
|
||||
}
|
||||
|
||||
for (int i = 0; i < qMin(numMetatiles, numMetatileAttrs); i++) {
|
||||
for (int i = 0; i < numMetatileAttrs; i++) {
|
||||
uint32_t attributes = 0;
|
||||
for (int j = 0; j < attrSize; j++)
|
||||
attributes |= static_cast<unsigned char>(data.at(i * attrSize + j)) << (8 * j);
|
||||
|
|
@ -468,9 +539,9 @@ bool Tileset::loadMetatileAttributes() {
|
|||
}
|
||||
|
||||
bool Tileset::saveMetatileAttributes() {
|
||||
QFile attrs_file(this->metatile_attrs_path);
|
||||
if (!attrs_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
logError(QString("Could not open '%1' for writing: %2").arg(this->metatile_attrs_path).arg(attrs_file.errorString()));
|
||||
QFile file(this->metatile_attrs_path);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
logError(QString("Could not open '%1' for writing: %2").arg(this->metatile_attrs_path).arg(file.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -480,45 +551,74 @@ bool Tileset::saveMetatileAttributes() {
|
|||
for (int i = 0; i < projectConfig.metatileAttributesSize; i++)
|
||||
data.append(static_cast<char>(attributes >> (8 * i)));
|
||||
}
|
||||
attrs_file.write(data);
|
||||
file.write(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Tileset::loadTilesImage(QImage *importedImage) {
|
||||
QImage image;
|
||||
bool imported = false;
|
||||
if (importedImage) {
|
||||
image = *importedImage;
|
||||
m_hasUnsavedTilesImage = true;
|
||||
imported = true;
|
||||
} else if (QFile::exists(this->tilesImagePath)) {
|
||||
// No image provided, load from file path.
|
||||
image = QImage(this->tilesImagePath).convertToFormat(QImage::Format_Indexed8, Qt::ThresholdDither);
|
||||
} else {
|
||||
// Use default image
|
||||
image = QImage(8, 8, QImage::Format_Indexed8);
|
||||
}
|
||||
|
||||
// Validate image contains 16 colors.
|
||||
if (image.isNull()) {
|
||||
logWarn(QString("Failed to load tiles image for %1. Using default tiles image.").arg(this->name));
|
||||
image = QImage(Tile::pixelWidth(), Tile::pixelHeight(), QImage::Format_Indexed8);
|
||||
image.fill(0);
|
||||
}
|
||||
|
||||
// Validate image dimensions
|
||||
if (image.width() % Tile::pixelWidth() || image.height() % Tile::pixelHeight()) {
|
||||
logError(QString("%1 tiles image has invalid dimensions %2x%3. Dimensions must be a multiple of %4x%5.")
|
||||
.arg(this->name)
|
||||
.arg(image.width())
|
||||
.arg(image.height())
|
||||
.arg(Tile::pixelWidth())
|
||||
.arg(Tile::pixelHeight()));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate the number of colors in the image.
|
||||
int colorCount = image.colorCount();
|
||||
if (colorCount > 16) {
|
||||
if (colorCount > Tileset::numColorsPerPalette()) {
|
||||
flattenTo4bppImage(&image);
|
||||
} else if (colorCount < 16) {
|
||||
} else if (colorCount < Tileset::numColorsPerPalette()) {
|
||||
QVector<QRgb> colorTable = image.colorTable();
|
||||
for (int i = colorTable.length(); i < 16; i++) {
|
||||
for (int i = colorTable.length(); i < Tileset::numColorsPerPalette(); i++) {
|
||||
colorTable.append(0);
|
||||
}
|
||||
image.setColorTable(colorTable);
|
||||
}
|
||||
m_tilesImage = image;
|
||||
|
||||
QList<QImage> tiles;
|
||||
int w = 8;
|
||||
int h = 8;
|
||||
for (int y = 0; y < image.height(); y += h)
|
||||
for (int x = 0; x < image.width(); x += w) {
|
||||
QImage tile = image.copy(x, y, w, h);
|
||||
tiles.append(tile);
|
||||
// Cut up the full tiles image into individual tile images.
|
||||
m_tiles.clear();
|
||||
for (int y = 0; y < image.height(); y += Tile::pixelHeight())
|
||||
for (int x = 0; x < image.width(); x += Tile::pixelWidth()) {
|
||||
m_tiles.append(image.copy(x, y, Tile::pixelWidth(), Tile::pixelHeight()));
|
||||
}
|
||||
this->tilesImage = image;
|
||||
this->tiles = tiles;
|
||||
|
||||
if (m_tiles.length() > maxTiles()) {
|
||||
logWarn(QString("%1 tile count of %2 exceeds limit of %3. Additional tiles will not be displayed.")
|
||||
.arg(this->name)
|
||||
.arg(m_tiles.length())
|
||||
.arg(maxTiles()));
|
||||
|
||||
// Just resize m_tiles so that numTiles() reports the correct tile count.
|
||||
// We'll leave m_tilesImage alone (it doesn't get displayed, and we don't want to delete the user's image data).
|
||||
m_tiles = m_tiles.mid(0, maxTiles());
|
||||
}
|
||||
|
||||
if (imported) {
|
||||
// Only set this flag once we've successfully loaded the tiles image.
|
||||
m_hasUnsavedTilesImage = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -528,7 +628,7 @@ bool Tileset::saveTilesImage() {
|
|||
if (!m_hasUnsavedTilesImage)
|
||||
return true;
|
||||
|
||||
if (!this->tilesImage.save(this->tilesImagePath, "PNG")) {
|
||||
if (!m_tilesImage.save(this->tilesImagePath, "PNG")) {
|
||||
logError(QString("Failed to save tiles image '%1'").arg(this->tilesImagePath));
|
||||
return false;
|
||||
}
|
||||
|
|
@ -553,8 +653,9 @@ bool Tileset::loadPalettes() {
|
|||
// Either the palette failed to load, or no palette exists.
|
||||
// We expect tilesets to have a certain number of palettes,
|
||||
// so fill this palette with dummy colors.
|
||||
for (int j = 0; j < 16; j++) {
|
||||
palette.append(qRgb(j * 16, j * 16, j * 16));
|
||||
for (int j = 0; j < Tileset::numColorsPerPalette(); j++) {
|
||||
int colorComponent = j * (256 / Tileset::numColorsPerPalette());
|
||||
palette.append(qRgb(colorComponent, colorComponent, colorComponent));
|
||||
}
|
||||
}
|
||||
this->palettes.append(palette);
|
||||
|
|
@ -567,7 +668,7 @@ bool Tileset::savePalettes() {
|
|||
bool success = true;
|
||||
int numPalettes = qMin(this->palettePaths.length(), this->palettes.length());
|
||||
for (int i = 0; i < numPalettes; i++) {
|
||||
if (!PaletteUtil::writeJASC(this->palettePaths.at(i), this->palettes.at(i).toVector(), 0, 16))
|
||||
if (!PaletteUtil::writeJASC(this->palettePaths.at(i), this->palettes.at(i).toVector(), 0, Tileset::numColorsPerPalette()))
|
||||
success = false;
|
||||
}
|
||||
return success;
|
||||
|
|
@ -575,19 +676,105 @@ bool Tileset::savePalettes() {
|
|||
|
||||
bool Tileset::load() {
|
||||
bool success = true;
|
||||
if (!loadPalettes()) success = false;
|
||||
if (!loadTilesImage()) success = false;
|
||||
if (!loadMetatiles()) success = false;
|
||||
if (!loadMetatileAttributes()) success = false;
|
||||
if (!loadTilesImage()) success = false;
|
||||
if (!loadPalettes()) success = false;
|
||||
return success;
|
||||
}
|
||||
|
||||
// Because metatile labels are global (and handled by the project) we don't save them here.
|
||||
bool Tileset::save() {
|
||||
bool success = true;
|
||||
if (!savePalettes()) success = false;
|
||||
if (!saveTilesImage()) success = false;
|
||||
if (!saveMetatiles()) success = false;
|
||||
if (!saveMetatileAttributes()) success = false;
|
||||
if (!saveTilesImage()) success = false;
|
||||
if (!savePalettes()) success = false;
|
||||
return success;
|
||||
}
|
||||
|
||||
QString Tileset::stripPrefix(const QString &fullName) {
|
||||
return QString(fullName).replace(projectConfig.getIdentifier(ProjectIdentifier::symbol_tilesets_prefix), "");
|
||||
}
|
||||
|
||||
// Find which of the specified color IDs in 'searchColors' are not used by any of this tileset's metatiles.
|
||||
// The 'pairedTileset' may be used to get the tile images for any tiles that don't belong to this tileset.
|
||||
// If 'searchColors' is empty, it will for search for all unused colors.
|
||||
QSet<int> Tileset::getUnusedColorIds(int paletteId, const Tileset *pairedTileset, const QSet<int> &searchColors) const {
|
||||
QSet<int> unusedColors = searchColors;
|
||||
if (unusedColors.isEmpty()) {
|
||||
// Search for all colors
|
||||
for (int i = 0; i < Tileset::numColorsPerPalette(); i++) {
|
||||
unusedColors.insert(i);
|
||||
}
|
||||
}
|
||||
const Tileset *primaryTileset = this->is_secondary ? pairedTileset : this;
|
||||
const Tileset *secondaryTileset = this->is_secondary ? this : pairedTileset;
|
||||
QSet<uint16_t> seenTileIds;
|
||||
for (const auto &metatile : m_metatiles)
|
||||
for (const auto &tile : metatile->tiles) {
|
||||
if (tile.palette != paletteId)
|
||||
continue;
|
||||
|
||||
// Save time by ignoring tiles we've already inspected.
|
||||
if (seenTileIds.contains(tile.tileId))
|
||||
continue;
|
||||
seenTileIds.insert(tile.tileId);
|
||||
|
||||
QImage image = getTileImage(tile.tileId, primaryTileset, secondaryTileset);
|
||||
if (image.isNull() || image.sizeInBytes() < Tile::numPixels())
|
||||
continue;
|
||||
|
||||
const uchar * pixels = image.constBits();
|
||||
for (int i = 0; i < Tile::numPixels(); i++) {
|
||||
auto it = unusedColors.constFind(pixels[i]);
|
||||
if (it != unusedColors.constEnd()) {
|
||||
unusedColors.erase(it);
|
||||
if (unusedColors.isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return unusedColors;
|
||||
}
|
||||
|
||||
// Returns the list of metatile IDs representing all the metatiles in this tileset that use the specified color ID.
|
||||
QList<uint16_t> Tileset::findMetatilesUsingColor(int paletteId, int colorId, const Tileset *pairedTileset) const {
|
||||
const Tileset *primaryTileset = this->is_secondary ? pairedTileset : this;
|
||||
const Tileset *secondaryTileset = this->is_secondary ? this : pairedTileset;
|
||||
QSet<uint16_t> metatileIdSet;
|
||||
QHash<uint16_t, bool> tileContainsColor;
|
||||
uint16_t metatileIdBase = firstMetatileId();
|
||||
for (int i = 0; i < m_metatiles.length(); i++) {
|
||||
uint16_t metatileId = i + metatileIdBase;
|
||||
for (const auto &tile : m_metatiles.at(i)->tiles) {
|
||||
if (tile.palette != paletteId)
|
||||
continue;
|
||||
|
||||
// Save time on tiles we've already inspected by getting the cached result.
|
||||
auto tileIt = tileContainsColor.constFind(tile.tileId);
|
||||
if (tileIt != tileContainsColor.constEnd()) {
|
||||
if (tileIt.value()) metatileIdSet.insert(metatileId);
|
||||
continue;
|
||||
}
|
||||
tileContainsColor[tile.tileId] = false;
|
||||
|
||||
QImage image = getTileImage(tile.tileId, primaryTileset, secondaryTileset);
|
||||
if (image.isNull() || image.sizeInBytes() < Tile::numPixels())
|
||||
continue;
|
||||
|
||||
const uchar * pixels = image.constBits();
|
||||
for (int j = 0; j < Tile::numPixels(); j++) {
|
||||
if (pixels[j] == colorId) {
|
||||
metatileIdSet.insert(metatileId);
|
||||
tileContainsColor[tile.tileId] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
QList<uint16_t> metatileIds(metatileIdSet.constBegin(), metatileIdSet.constEnd());
|
||||
std::sort(metatileIds.begin(), metatileIds.end());
|
||||
return metatileIds;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ void Util::numericalModeSort(QStringList &list) {
|
|||
std::sort(list.begin(), list.end(), collator);
|
||||
}
|
||||
|
||||
int Util::roundUp(int numToRound, int multiple) {
|
||||
int Util::roundUpToMultiple(int numToRound, int multiple) {
|
||||
if (multiple <= 0)
|
||||
return numToRound;
|
||||
|
||||
|
|
@ -112,3 +112,16 @@ void Util::setErrorStylesheet(QLineEdit *lineEdit, bool isError) {
|
|||
static const QString stylesheet = QStringLiteral("QLineEdit { background-color: rgba(255, 0, 0, 25%) }");
|
||||
lineEdit->setStyleSheet(isError ? stylesheet : "");
|
||||
}
|
||||
|
||||
void Util::show(QWidget *w) {
|
||||
if (!w) return;
|
||||
|
||||
if (!w->isVisible()) {
|
||||
w->show();
|
||||
} else if (w->isMinimized()) {
|
||||
w->showNormal();
|
||||
} else {
|
||||
w->raise();
|
||||
w->activateWindow();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
412
src/editor.cpp
412
src/editor.cpp
|
|
@ -30,7 +30,7 @@ Editor::Editor(Ui::MainWindow* ui)
|
|||
{
|
||||
this->ui = ui;
|
||||
this->settings = new Settings();
|
||||
this->cursorMapTileRect = new CursorTileRect(&this->settings->cursorTileRectEnabled, qRgb(255, 255, 255));
|
||||
this->cursorMapTileRect = new CursorTileRect(Metatile::pixelSize(), qRgb(255, 255, 255));
|
||||
this->map_ruler = new MapRuler(4);
|
||||
connect(this->map_ruler, &MapRuler::statusChanged, this, &Editor::mapRulerStatusChanged);
|
||||
|
||||
|
|
@ -125,7 +125,7 @@ void Editor::closeProject() {
|
|||
delete this->project;
|
||||
}
|
||||
|
||||
bool Editor::getEditingLayout() {
|
||||
bool Editor::getEditingLayout() const {
|
||||
return this->editMode == EditMode::Metatiles || this->editMode == EditMode::Collision;
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +155,6 @@ void Editor::setEditMode(EditMode editMode) {
|
|||
break;
|
||||
}
|
||||
|
||||
map_item->setEditsEnabled(this->editMode != EditMode::Connections);
|
||||
map_item->draw();
|
||||
collision_item->draw();
|
||||
|
||||
|
|
@ -169,18 +168,26 @@ void Editor::setEditMode(EditMode editMode) {
|
|||
editStack = &this->layout->editHistory;
|
||||
}
|
||||
|
||||
this->cursorMapTileRect->setActive(editingLayout);
|
||||
this->playerViewRect->setActive(editingLayout);
|
||||
this->editGroup.setActiveStack(editStack);
|
||||
this->ui->toolButton_Fill->setEnabled(editingLayout);
|
||||
this->ui->toolButton_Dropper->setEnabled(editingLayout);
|
||||
this->ui->pushButton_ChangeDimensions->setEnabled(editingLayout);
|
||||
this->ui->checkBox_smartPaths->setEnabled(editingLayout);
|
||||
|
||||
if (this->editMode == EditMode::Events || oldEditMode == EditMode::Events) {
|
||||
if (this->editMode != oldEditMode) {
|
||||
// When switching to or from the Connections tab we sync up the two separate map graphics views.
|
||||
if (this->editMode == EditMode::Connections) {
|
||||
ui->graphicsView_Connections->centerOn(ui->graphicsView_Map);
|
||||
} else if (oldEditMode == EditMode::Connections) {
|
||||
ui->graphicsView_Map->centerOn(ui->graphicsView_Connections);
|
||||
}
|
||||
|
||||
// When switching to or from the Events tab the opacity of the events changes. Redraw the events to reflect that change.
|
||||
redrawAllEvents();
|
||||
if (this->editMode == EditMode::Events || oldEditMode == EditMode::Events) {
|
||||
redrawAllEvents();
|
||||
}
|
||||
}
|
||||
|
||||
if (this->editMode == EditMode::Events){
|
||||
updateWarpEventWarnings();
|
||||
}
|
||||
|
|
@ -204,18 +211,40 @@ void Editor::setEditAction(EditAction editAction) {
|
|||
this->map_ruler->setEnabled(false);
|
||||
}
|
||||
|
||||
updateCursorRectVisibility();
|
||||
|
||||
// The tile cursor can only grow while painting metatiles
|
||||
this->cursorMapTileRect->setSingleTileMode(!(editAction == EditAction::Paint && this->editMode == EditMode::Metatiles));
|
||||
|
||||
auto dragMode = (editAction == EditAction::Move) ? QGraphicsView::ScrollHandDrag : QGraphicsView::NoDrag;
|
||||
ui->graphicsView_Map->setDragMode(dragMode);
|
||||
ui->graphicsView_Connections->setDragMode(dragMode);
|
||||
|
||||
// Update cursor
|
||||
static const QMap<EditAction, QCursor> cursors = {
|
||||
{EditAction::Paint, QCursor(QPixmap(":/icons/pencil_cursor.ico"), 10, 10)},
|
||||
{EditAction::Select, QCursor()},
|
||||
{EditAction::Fill, QCursor(QPixmap(":/icons/fill_color_cursor.ico"), 10, 10)},
|
||||
{EditAction::Pick, QCursor(QPixmap(":/icons/pipette_cursor.ico"), 10, 10)},
|
||||
{EditAction::Move, QCursor(QPixmap(":/icons/move.ico"), 7, 7)},
|
||||
{EditAction::Shift, QCursor(QPixmap(":/icons/shift_cursor.ico"), 10, 10)},
|
||||
};
|
||||
this->settings->mapCursor = cursors.value(editAction);
|
||||
if (this->settings->betterCursors) {
|
||||
static const QMap<EditAction, QCursor> cursors = {
|
||||
{EditAction::Paint, QCursor(QPixmap(":/icons/pencil_cursor.ico"), 10, 10)},
|
||||
{EditAction::Fill, QCursor(QPixmap(":/icons/fill_color_cursor.ico"), 10, 10)},
|
||||
{EditAction::Pick, QCursor(QPixmap(":/icons/pipette_cursor.ico"), 10, 10)},
|
||||
{EditAction::Shift, QCursor(QPixmap(":/icons/shift_cursor.ico"), 10, 10)},
|
||||
};
|
||||
|
||||
// Paint tools don't apply on the Connections tab, so don't show the cursor.
|
||||
// We specifically unset the cursor for Move rather than explicitly set Qt::OpenHandCursor
|
||||
// because otherwise the cursor may persist outside the map after the tool changes.
|
||||
if (this->editMode == EditMode::Connections || editAction == EditAction::Move) {
|
||||
if (this->map_item)
|
||||
this->map_item->unsetCursor();
|
||||
if (this->collision_item)
|
||||
this->collision_item->unsetCursor();
|
||||
} else {
|
||||
auto cursor = cursors.value(editAction);
|
||||
if (this->map_item)
|
||||
this->map_item->setCursor(cursor);
|
||||
if (this->collision_item)
|
||||
this->collision_item->setCursor(cursor);
|
||||
}
|
||||
}
|
||||
emit editActionSet(editAction);
|
||||
}
|
||||
|
||||
|
|
@ -498,7 +527,7 @@ void Editor::configureEncounterJSON(QWidget *window) {
|
|||
auto createNewSlot = [&fieldSlots, &tempFields, &updateTotal](int index, EncounterField ¤tField) {
|
||||
QLabel *indexLabel = new QLabel(QString("Index: %1").arg(QString::number(index)));
|
||||
QSpinBox *chanceSpinner = new QSpinBox;
|
||||
int chance = currentField.encounterRates.at(index);
|
||||
int chance = currentField.encounterRates.value(index);
|
||||
chanceSpinner->setMinimum(1);
|
||||
chanceSpinner->setMaximum(9999);
|
||||
chanceSpinner->setValue(chance);
|
||||
|
|
@ -1091,8 +1120,7 @@ void Editor::onHoveredMetatileSelectionCleared() {
|
|||
}
|
||||
|
||||
void Editor::onSelectedMetatilesChanged() {
|
||||
QPoint size = this->metatile_selector_item->getSelectionDimensions();
|
||||
this->cursorMapTileRect->updateSelectionSize(size.x(), size.y());
|
||||
this->cursorMapTileRect->updateSelectionSize(this->metatile_selector_item->getSelectionDimensions());
|
||||
this->redrawCurrentMetatilesSelection();
|
||||
}
|
||||
|
||||
|
|
@ -1136,15 +1164,20 @@ void Editor::scaleMapView(int s) {
|
|||
ui->graphicsView_Connections->setTransform(transform);
|
||||
}
|
||||
|
||||
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();
|
||||
bool Editor::isMouseInMap() const {
|
||||
return (this->map_item && this->map_item->has_mouse) || (this->collision_item && this->collision_item->has_mouse);
|
||||
}
|
||||
|
||||
void Editor::updateCursorRectPos(int x, int y) {
|
||||
void Editor::setPlayerViewRect(const QRectF &rect) {
|
||||
delete this->playerViewRect;
|
||||
this->playerViewRect = new MovableRect(rect, Metatile::pixelSize(), qRgb(255, 255, 255));
|
||||
updateCursorRectVisibility();
|
||||
}
|
||||
|
||||
void Editor::setCursorRectPos(const QPoint &pos) {
|
||||
int x = qBound(0, pos.x(), this->layout ? this->layout->getWidth() - 1 : 0);
|
||||
int y = qBound(0, pos.y(), this->layout ? this->layout->getHeight() - 1 : 0);
|
||||
|
||||
if (this->playerViewRect)
|
||||
this->playerViewRect->updateLocation(x, y);
|
||||
if (this->cursorMapTileRect)
|
||||
|
|
@ -1153,23 +1186,67 @@ void Editor::updateCursorRectPos(int x, int y) {
|
|||
ui->graphicsView_Map->scene()->update();
|
||||
}
|
||||
|
||||
void Editor::setCursorRectVisible(bool visible) {
|
||||
if (this->playerViewRect)
|
||||
this->playerViewRect->setVisible(visible);
|
||||
if (this->cursorMapTileRect)
|
||||
this->cursorMapTileRect->setVisible(visible);
|
||||
if (ui->graphicsView_Map->scene())
|
||||
void Editor::updateCursorRectVisibility() {
|
||||
bool mouseInMap = isMouseInMap();
|
||||
bool changed = false;
|
||||
|
||||
if (this->playerViewRect) {
|
||||
bool visible = this->settings->playerViewRectEnabled
|
||||
&& mouseInMap
|
||||
&& this->editMode != EditMode::Connections;
|
||||
|
||||
if (visible != this->playerViewRect->isVisible()) {
|
||||
this->playerViewRect->setVisible(visible);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->cursorMapTileRect) {
|
||||
auto editAction = getEditAction();
|
||||
bool visible = this->settings->cursorTileRectEnabled
|
||||
&& mouseInMap
|
||||
// Only show the tile cursor for tools that apply at a specific tile
|
||||
&& editAction != EditAction::Select
|
||||
&& editAction != EditAction::Move;
|
||||
|
||||
if (visible != this->cursorMapTileRect->isVisible()) {
|
||||
this->cursorMapTileRect->setVisible(visible);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Investigate whether it'd be worth limiting the scene update to the old and new areas of the cursor rectangles.
|
||||
if (ui->graphicsView_Map->scene() && changed) {
|
||||
ui->graphicsView_Map->scene()->update();
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::onHoveredMapMetatileChanged(const QPoint &pos) {
|
||||
int x = pos.x();
|
||||
int y = pos.y();
|
||||
if (!layout || !layout->isWithinBounds(x, y))
|
||||
void Editor::onMapHoverEntered(const QPoint &pos) {
|
||||
updateCursorRectVisibility();
|
||||
onMapHoverChanged(pos);
|
||||
}
|
||||
|
||||
void Editor::onMapHoverChanged(const QPoint &pos) {
|
||||
this->setCursorRectPos(pos);
|
||||
if (!layout || !layout->isWithinBounds(pos))
|
||||
return;
|
||||
|
||||
this->updateCursorRectPos(x, y);
|
||||
if (this->getEditingLayout()) {
|
||||
setStatusFromMapPos(pos);
|
||||
Scripting::cb_BlockHoverChanged(pos.x(), pos.y());
|
||||
}
|
||||
|
||||
void Editor::onMapHoverCleared() {
|
||||
updateCursorRectVisibility();
|
||||
if (getEditingLayout()) {
|
||||
ui->statusBar->clearMessage();
|
||||
}
|
||||
Scripting::cb_BlockHoverCleared();
|
||||
}
|
||||
|
||||
void Editor::setStatusFromMapPos(const QPoint &pos) {
|
||||
int x = pos.x();
|
||||
int y = pos.y();
|
||||
if (this->editMode == EditMode::Metatiles) {
|
||||
int blockIndex = y * layout->getWidth() + x;
|
||||
int metatileId = layout->blockdata.at(blockIndex).metatileId();
|
||||
this->ui->statusBar->showMessage(QString("X: %1, Y: %2, %3, Scale = %4x")
|
||||
|
|
@ -1177,49 +1254,20 @@ void Editor::onHoveredMapMetatileChanged(const QPoint &pos) {
|
|||
.arg(y)
|
||||
.arg(getMetatileDisplayMessage(metatileId))
|
||||
.arg(QString::number(zoomLevels[this->scaleIndex], 'g', 2)));
|
||||
}
|
||||
else if (this->editMode == EditMode::Events) {
|
||||
} else if (this->editMode == EditMode::Collision) {
|
||||
int blockIndex = y * layout->getWidth() + x;
|
||||
uint16_t collision = layout->blockdata.at(blockIndex).collision();
|
||||
uint16_t elevation = layout->blockdata.at(blockIndex).elevation();
|
||||
this->ui->statusBar->showMessage(QString("X: %1, Y: %2, %3")
|
||||
.arg(x)
|
||||
.arg(y)
|
||||
.arg(this->getMovementPermissionText(collision, elevation)));
|
||||
} else if (this->editMode == EditMode::Events) {
|
||||
this->ui->statusBar->showMessage(QString("X: %1, Y: %2, Scale = %3x")
|
||||
.arg(x)
|
||||
.arg(y)
|
||||
.arg(QString::number(zoomLevels[this->scaleIndex], 'g', 2)));
|
||||
}
|
||||
|
||||
Scripting::cb_BlockHoverChanged(x, y);
|
||||
}
|
||||
|
||||
void Editor::onHoveredMapMetatileCleared() {
|
||||
this->setCursorRectVisible(false);
|
||||
if (map_item->getEditsEnabled()) {
|
||||
this->ui->statusBar->clearMessage();
|
||||
}
|
||||
Scripting::cb_BlockHoverCleared();
|
||||
}
|
||||
|
||||
void Editor::onHoveredMapMovementPermissionChanged(int x, int y) {
|
||||
if (!layout || !layout->isWithinBounds(x, y))
|
||||
return;
|
||||
|
||||
this->updateCursorRectPos(x, y);
|
||||
if (this->getEditingLayout()) {
|
||||
int blockIndex = y * layout->getWidth() + x;
|
||||
uint16_t collision = layout->blockdata.at(blockIndex).collision();
|
||||
uint16_t elevation = layout->blockdata.at(blockIndex).elevation();
|
||||
QString message = QString("X: %1, Y: %2, %3")
|
||||
.arg(x)
|
||||
.arg(y)
|
||||
.arg(this->getMovementPermissionText(collision, elevation));
|
||||
this->ui->statusBar->showMessage(message);
|
||||
}
|
||||
Scripting::cb_BlockHoverChanged(x, y);
|
||||
}
|
||||
|
||||
void Editor::onHoveredMapMovementPermissionCleared() {
|
||||
this->setCursorRectVisible(false);
|
||||
if (this->getEditingLayout()) {
|
||||
this->ui->statusBar->clearMessage();
|
||||
}
|
||||
Scripting::cb_BlockHoverCleared();
|
||||
}
|
||||
|
||||
QString Editor::getMovementPermissionText(uint16_t collision, uint16_t elevation) {
|
||||
|
|
@ -1311,12 +1359,13 @@ bool Editor::setLayout(QString layoutId) {
|
|||
map_ruler->setMapDimensions(QSize(this->layout->getWidth(), this->layout->getHeight()));
|
||||
connect(this->layout, &Layout::dimensionsChanged, map_ruler, &MapRuler::setMapDimensions);
|
||||
|
||||
ui->comboBox_PrimaryTileset->blockSignals(true);
|
||||
ui->comboBox_SecondaryTileset->blockSignals(true);
|
||||
QString prevPrimaryTileset = ui->comboBox_PrimaryTileset->currentText();
|
||||
QString prevSecondaryTileset = ui->comboBox_SecondaryTileset->currentText();
|
||||
|
||||
const QSignalBlocker b_PrimaryTilest(ui->comboBox_PrimaryTileset);
|
||||
const QSignalBlocker b_SecondaryTilest(ui->comboBox_SecondaryTileset);
|
||||
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);
|
||||
|
||||
const QSignalBlocker b0(this->ui->comboBox_LayoutSelector);
|
||||
int index = this->ui->comboBox_LayoutSelector->findText(layoutId);
|
||||
|
|
@ -1325,17 +1374,25 @@ bool Editor::setLayout(QString layoutId) {
|
|||
|
||||
if (this->layout->name != prevLayoutName)
|
||||
Scripting::cb_LayoutOpened(this->layout->name);
|
||||
if (this->layout->tileset_primary_label != prevPrimaryTileset)
|
||||
Scripting::cb_TilesetUpdated(this->layout->tileset_primary_label);
|
||||
if (this->layout->tileset_secondary_label != prevSecondaryTileset)
|
||||
Scripting::cb_TilesetUpdated(this->layout->tileset_secondary_label);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Editor::canPaintMetatiles() const {
|
||||
return this->editMode == EditMode::Metatiles && this->mapEditAction != EditAction::Select && this->mapEditAction != EditAction::Move;
|
||||
}
|
||||
|
||||
void Editor::onMapStartPaint(QGraphicsSceneMouseEvent *event, LayoutPixmapItem *) {
|
||||
if (!this->getEditingLayout()) {
|
||||
if (!canPaintMetatiles()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QPoint pos = Metatile::coordFromPixmapCoord(event->pos());
|
||||
if (event->buttons() & Qt::RightButton && (mapEditAction == EditAction::Paint || mapEditAction == EditAction::Fill)) {
|
||||
if (event->buttons() & Qt::RightButton && (this->mapEditAction == EditAction::Paint || this->mapEditAction == EditAction::Fill)) {
|
||||
this->cursorMapTileRect->initRightClickSelectionAnchor(pos.x(), pos.y());
|
||||
} else {
|
||||
this->cursorMapTileRect->initAnchor(pos.x(), pos.y());
|
||||
|
|
@ -1343,7 +1400,7 @@ void Editor::onMapStartPaint(QGraphicsSceneMouseEvent *event, LayoutPixmapItem *
|
|||
}
|
||||
|
||||
void Editor::onMapEndPaint(QGraphicsSceneMouseEvent *, LayoutPixmapItem *) {
|
||||
if (!this->getEditingLayout()) {
|
||||
if (!canPaintMetatiles()) {
|
||||
return;
|
||||
}
|
||||
this->cursorMapTileRect->stopRightClickSelectionAnchor();
|
||||
|
|
@ -1368,25 +1425,31 @@ void Editor::setSmartPathCursorMode(QGraphicsSceneMouseEvent *event)
|
|||
}
|
||||
}
|
||||
|
||||
void Editor::setStraightPathCursorMode(QGraphicsSceneMouseEvent *event) {
|
||||
void Editor::adjustStraightPathPos(QGraphicsSceneMouseEvent *event, LayoutPixmapItem *item, QPoint *pos) const {
|
||||
if (event->modifiers() & Qt::ControlModifier) {
|
||||
this->cursorMapTileRect->setStraightPathMode(true);
|
||||
} else {
|
||||
this->cursorMapTileRect->setStraightPathMode(false);
|
||||
item->lockNondominantAxis(event);
|
||||
*pos = item->adjustCoords(*pos);
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::mouseEvent_map(QGraphicsSceneMouseEvent *event, LayoutPixmapItem *item) {
|
||||
if (!item->getEditsEnabled()) {
|
||||
auto editAction = getEditAction();
|
||||
if (editAction == EditAction::Move) {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
|
||||
QPoint pos = Metatile::coordFromPixmapCoord(event->pos());
|
||||
|
||||
if (this->getEditingLayout()) {
|
||||
if (mapEditAction == EditAction::Paint) {
|
||||
if (this->editMode == EditMode::Metatiles || this->editMode == EditMode::Collision) {
|
||||
if (editAction == EditAction::Paint) {
|
||||
if (event->buttons() & Qt::RightButton) {
|
||||
item->updateMetatileSelection(event);
|
||||
if (this->editMode == EditMode::Collision) {
|
||||
auto collisionItem = dynamic_cast<CollisionPixmapItem*>(item);
|
||||
if (collisionItem) collisionItem->updateMovementPermissionSelection(event);
|
||||
} else {
|
||||
item->updateMetatileSelection(event);
|
||||
}
|
||||
} else if (event->buttons() & Qt::MiddleButton) {
|
||||
if (event->modifiers() & Qt::ControlModifier) {
|
||||
item->magicFill(event);
|
||||
|
|
@ -1396,42 +1459,40 @@ void Editor::mouseEvent_map(QGraphicsSceneMouseEvent *event, LayoutPixmapItem *i
|
|||
} else {
|
||||
if (event->type() == QEvent::GraphicsSceneMouseRelease) {
|
||||
// Update the tile rectangle at the end of a click-drag selection
|
||||
this->updateCursorRectPos(pos.x(), pos.y());
|
||||
}
|
||||
this->setSmartPathCursorMode(event);
|
||||
this->setStraightPathCursorMode(event);
|
||||
if (this->cursorMapTileRect->getStraightPathMode()) {
|
||||
item->lockNondominantAxis(event);
|
||||
pos = item->adjustCoords(pos);
|
||||
setCursorRectPos(pos);
|
||||
}
|
||||
setSmartPathCursorMode(event);
|
||||
adjustStraightPathPos(event, item, &pos);
|
||||
item->paint(event);
|
||||
}
|
||||
} else if (mapEditAction == EditAction::Select) {
|
||||
setStatusFromMapPos(pos);
|
||||
} else if (editAction == EditAction::Select) {
|
||||
item->select(event);
|
||||
} else if (mapEditAction == EditAction::Fill) {
|
||||
} else if (editAction == EditAction::Fill) {
|
||||
if (event->buttons() & Qt::RightButton) {
|
||||
item->updateMetatileSelection(event);
|
||||
if (this->editMode == EditMode::Metatiles) {
|
||||
item->updateMetatileSelection(event);
|
||||
} else {
|
||||
item->pick(event);
|
||||
}
|
||||
} else if (event->modifiers() & Qt::ControlModifier) {
|
||||
item->magicFill(event);
|
||||
} else {
|
||||
item->floodFill(event);
|
||||
}
|
||||
} else if (mapEditAction == EditAction::Pick) {
|
||||
if (event->buttons() & Qt::RightButton) {
|
||||
setStatusFromMapPos(pos);
|
||||
} else if (editAction == EditAction::Pick) {
|
||||
if (this->editMode == EditMode::Metatiles && (event->buttons() & Qt::RightButton)) {
|
||||
item->updateMetatileSelection(event);
|
||||
} else if (event->type() != QEvent::GraphicsSceneMouseRelease) {
|
||||
item->pick(event);
|
||||
}
|
||||
} else if (mapEditAction == EditAction::Shift) {
|
||||
this->setStraightPathCursorMode(event);
|
||||
if (this->cursorMapTileRect->getStraightPathMode()) {
|
||||
item->lockNondominantAxis(event);
|
||||
pos = item->adjustCoords(pos);
|
||||
}
|
||||
} else if (editAction == EditAction::Shift) {
|
||||
adjustStraightPathPos(event, item, &pos);
|
||||
item->shift(event);
|
||||
}
|
||||
} else if (this->editMode == EditMode::Events) {
|
||||
if (eventEditAction == EditAction::Paint && event->type() == QEvent::GraphicsSceneMousePress) {
|
||||
if (editAction == EditAction::Paint && event->type() == QEvent::GraphicsSceneMousePress) {
|
||||
// Right-clicking while in paint mode will change mode to select.
|
||||
if (event->buttons() & Qt::RightButton) {
|
||||
setEditAction(EditAction::Select);
|
||||
|
|
@ -1446,12 +1507,12 @@ void Editor::mouseEvent_map(QGraphicsSceneMouseEvent *event, LayoutPixmapItem *i
|
|||
if (event && event->getPixmapItem())
|
||||
event->getPixmapItem()->moveTo(pos);
|
||||
}
|
||||
} else if (eventEditAction == EditAction::Select && event->type() == QEvent::GraphicsSceneMousePress) {
|
||||
} else if (editAction == EditAction::Select && event->type() == QEvent::GraphicsSceneMousePress) {
|
||||
if (!(event->modifiers() & Qt::ControlModifier) && this->selectedEvents.length() > 1) {
|
||||
// User is clearing group selection by clicking on the background
|
||||
selectMapEvent(this->selectedEvents.first());
|
||||
}
|
||||
} else if (eventEditAction == EditAction::Shift) {
|
||||
} else if (editAction == EditAction::Shift) {
|
||||
static QPoint selection_origin;
|
||||
|
||||
if (event->type() == QEvent::GraphicsSceneMouseRelease) {
|
||||
|
|
@ -1473,52 +1534,6 @@ void Editor::mouseEvent_map(QGraphicsSceneMouseEvent *event, LayoutPixmapItem *i
|
|||
}
|
||||
}
|
||||
|
||||
void Editor::mouseEvent_collision(QGraphicsSceneMouseEvent *event, CollisionPixmapItem *item) {
|
||||
if (!item->getEditsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QPoint pos = Metatile::coordFromPixmapCoord(event->pos());
|
||||
|
||||
if (mapEditAction == EditAction::Paint) {
|
||||
if (event->buttons() & Qt::RightButton) {
|
||||
item->updateMovementPermissionSelection(event);
|
||||
} else if (event->buttons() & Qt::MiddleButton) {
|
||||
if (event->modifiers() & Qt::ControlModifier) {
|
||||
item->magicFill(event);
|
||||
} else {
|
||||
item->floodFill(event);
|
||||
}
|
||||
} else {
|
||||
this->setStraightPathCursorMode(event);
|
||||
if (this->cursorMapTileRect->getStraightPathMode()) {
|
||||
item->lockNondominantAxis(event);
|
||||
pos = item->adjustCoords(pos);
|
||||
}
|
||||
item->paint(event);
|
||||
}
|
||||
} else if (mapEditAction == EditAction::Select) {
|
||||
item->select(event);
|
||||
} else if (mapEditAction == EditAction::Fill) {
|
||||
if (event->buttons() & Qt::RightButton) {
|
||||
item->pick(event);
|
||||
} else if (event->modifiers() & Qt::ControlModifier) {
|
||||
item->magicFill(event);
|
||||
} else {
|
||||
item->floodFill(event);
|
||||
}
|
||||
} else if (mapEditAction == EditAction::Pick) {
|
||||
item->pick(event);
|
||||
} else if (mapEditAction == EditAction::Shift) {
|
||||
this->setStraightPathCursorMode(event);
|
||||
if (this->cursorMapTileRect->getStraightPathMode()) {
|
||||
item->lockNondominantAxis(event);
|
||||
pos = item->adjustCoords(pos);
|
||||
}
|
||||
item->shift(event);
|
||||
}
|
||||
}
|
||||
|
||||
// On project close we want to leave the editor view empty.
|
||||
// Otherwise a map is normally only cleared when a new one is being displayed.
|
||||
void Editor::clearMap() {
|
||||
|
|
@ -1604,7 +1619,7 @@ void Editor::displayMetatileSelector() {
|
|||
|
||||
scene_metatiles = new QGraphicsScene;
|
||||
if (!metatile_selector_item) {
|
||||
metatile_selector_item = new MetatileSelector(8, this->layout);
|
||||
metatile_selector_item = new MetatileSelector(projectConfig.metatileSelectorWidth, this->layout);
|
||||
connect(metatile_selector_item, &MetatileSelector::hoveredMetatileSelectionChanged,
|
||||
this, &Editor::onHoveredMetatileSelectionChanged);
|
||||
connect(metatile_selector_item, &MetatileSelector::hoveredMetatileSelectionCleared,
|
||||
|
|
@ -1614,13 +1629,6 @@ void Editor::displayMetatileSelector() {
|
|||
metatile_selector_item->select(0);
|
||||
} else {
|
||||
metatile_selector_item->setLayout(this->layout);
|
||||
if (metatile_selector_item->primaryTileset
|
||||
&& metatile_selector_item->primaryTileset != this->layout->tileset_primary)
|
||||
emit tilesetUpdated(this->layout->tileset_primary->name);
|
||||
if (metatile_selector_item->secondaryTileset
|
||||
&& metatile_selector_item->secondaryTileset != this->layout->tileset_secondary)
|
||||
emit tilesetUpdated(this->layout->tileset_secondary->name);
|
||||
metatile_selector_item->setTilesets(this->layout->tileset_primary, this->layout->tileset_secondary);
|
||||
}
|
||||
|
||||
scene_metatiles->addItem(metatile_selector_item);
|
||||
|
|
@ -1640,8 +1648,9 @@ void Editor::displayMapMetatiles() {
|
|||
connect(map_item, &LayoutPixmapItem::mouseEvent, this, &Editor::mouseEvent_map);
|
||||
connect(map_item, &LayoutPixmapItem::startPaint, this, &Editor::onMapStartPaint);
|
||||
connect(map_item, &LayoutPixmapItem::endPaint, this, &Editor::onMapEndPaint);
|
||||
connect(map_item, &LayoutPixmapItem::hoveredMapMetatileChanged, this, &Editor::onHoveredMapMetatileChanged);
|
||||
connect(map_item, &LayoutPixmapItem::hoveredMapMetatileCleared, this, &Editor::onHoveredMapMetatileCleared);
|
||||
connect(map_item, &LayoutPixmapItem::hoverEntered, this, &Editor::onMapHoverEntered);
|
||||
connect(map_item, &LayoutPixmapItem::hoverChanged, this, &Editor::onMapHoverChanged);
|
||||
connect(map_item, &LayoutPixmapItem::hoverCleared, this, &Editor::onMapHoverCleared);
|
||||
|
||||
map_item->draw(true);
|
||||
scene->addItem(map_item);
|
||||
|
|
@ -1662,11 +1671,10 @@ void Editor::displayMapMovementPermissions() {
|
|||
|
||||
collision_item = new CollisionPixmapItem(this->layout, ui->spinBox_SelectedCollision, ui->spinBox_SelectedElevation,
|
||||
this->metatile_selector_item, this->settings, &this->collisionOpacity);
|
||||
connect(collision_item, &CollisionPixmapItem::mouseEvent, this, &Editor::mouseEvent_collision);
|
||||
connect(collision_item, &CollisionPixmapItem::hoveredMapMovementPermissionChanged,
|
||||
this, &Editor::onHoveredMapMovementPermissionChanged);
|
||||
connect(collision_item, &CollisionPixmapItem::hoveredMapMovementPermissionCleared,
|
||||
this, &Editor::onHoveredMapMovementPermissionCleared);
|
||||
connect(collision_item, &CollisionPixmapItem::mouseEvent, this, &Editor::mouseEvent_map);
|
||||
connect(collision_item, &CollisionPixmapItem::hoverEntered, this, &Editor::onMapHoverEntered);
|
||||
connect(collision_item, &CollisionPixmapItem::hoverChanged, this, &Editor::onMapHoverChanged);
|
||||
connect(collision_item, &CollisionPixmapItem::hoverCleared, this, &Editor::onMapHoverCleared);
|
||||
|
||||
collision_item->draw(true);
|
||||
scene->addItem(collision_item);
|
||||
|
|
@ -1739,8 +1747,8 @@ void Editor::displayMovementPermissionSelector() {
|
|||
this, &Editor::onHoveredMovementPermissionChanged);
|
||||
connect(movement_permissions_selector_item, &MovementPermissionsSelector::hoveredMovementPermissionCleared,
|
||||
this, &Editor::onHoveredMovementPermissionCleared);
|
||||
connect(movement_permissions_selector_item, &SelectablePixmapItem::selectionChanged, [this](int x, int y, int, int) {
|
||||
this->setCollisionTabSpinBoxes(x, y);
|
||||
connect(movement_permissions_selector_item, &SelectablePixmapItem::selectionChanged, [this](const QPoint &pos, const QSize&) {
|
||||
this->setCollisionTabSpinBoxes(pos.x(), pos.y());
|
||||
});
|
||||
movement_permissions_selector_item->select(projectConfig.defaultCollision, projectConfig.defaultElevation);
|
||||
}
|
||||
|
|
@ -1880,8 +1888,8 @@ void Editor::displayMapBorder() {
|
|||
for (int y = -borderMargins.top(); y < this->layout->getHeight() + borderMargins.bottom(); y += this->layout->getBorderHeight())
|
||||
for (int x = -borderMargins.left(); x < this->layout->getWidth() + borderMargins.right(); x += this->layout->getBorderWidth()) {
|
||||
QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
|
||||
item->setX(x * 16);
|
||||
item->setY(y * 16);
|
||||
item->setX(x * Metatile::pixelWidth());
|
||||
item->setY(y * Metatile::pixelHeight());
|
||||
item->setZValue(ZValue::MapBorder);
|
||||
scene->addItem(item);
|
||||
borderItems.append(item);
|
||||
|
|
@ -1929,8 +1937,8 @@ void Editor::displayMapGrid() {
|
|||
// elements of the scripting API, so they're painted manually in MapView::drawForeground.
|
||||
this->mapGrid = new QGraphicsItemGroup();
|
||||
|
||||
const int pixelMapWidth = this->layout->getWidth() * 16;
|
||||
const int pixelMapHeight = this->layout->getHeight() * 16;
|
||||
const int pixelMapWidth = this->layout->pixelWidth();
|
||||
const int pixelMapHeight = this->layout->pixelHeight();
|
||||
|
||||
// The grid can be moved with a user-specified x/y offset. The grid's dash patterns will only wrap in full pattern increments,
|
||||
// so we draw an additional row/column outside the map that can be revealed as the offset changes.
|
||||
|
|
@ -2025,12 +2033,6 @@ void Editor::updateCustomMapAttributes()
|
|||
map->modify();
|
||||
}
|
||||
|
||||
Tileset* Editor::getCurrentMapPrimaryTileset()
|
||||
{
|
||||
QString tilesetLabel = this->layout->tileset_primary_label;
|
||||
return project->getTileset(tilesetLabel);
|
||||
}
|
||||
|
||||
void Editor::redrawAllEvents() {
|
||||
if (this->map) redrawEvents(this->map->getEvents());
|
||||
}
|
||||
|
|
@ -2089,7 +2091,7 @@ void Editor::onEventDragged(Event *event, const QPoint &oldPosition, const QPoin
|
|||
if (!this->map || !this->map_item)
|
||||
return;
|
||||
|
||||
this->map_item->hoveredMapMetatileChanged(newPosition);
|
||||
this->map_item->hoverChanged(newPosition);
|
||||
|
||||
// Drag all the other selected events (if any) with it
|
||||
QList<Event*> draggedEvents;
|
||||
|
|
@ -2196,7 +2198,7 @@ bool Editor::canAddEvents(const QList<Event*> &events) {
|
|||
}
|
||||
|
||||
void Editor::duplicateSelectedEvents() {
|
||||
if (this->selectedEvents.isEmpty() || !project || !map || !current_view || this->getEditingLayout())
|
||||
if (this->selectedEvents.isEmpty() || !project || !map || !current_view || this->editMode != EditMode::Events)
|
||||
return;
|
||||
|
||||
QList<Event *> duplicatedEvents;
|
||||
|
|
@ -2318,21 +2320,29 @@ void Editor::openMapScripts() const {
|
|||
openInTextEditor(map->getScriptsFilepath());
|
||||
}
|
||||
|
||||
void Editor::openScript(const QString &scriptLabel) const {
|
||||
bool Editor::openScript(const QString &scriptLabel) const {
|
||||
// Find the location of scriptLabel.
|
||||
QStringList scriptPaths(map->getScriptsFilepath());
|
||||
scriptPaths << project->getEventScriptsFilepaths();
|
||||
int lineNum = 0;
|
||||
QString scriptPath = scriptPaths.first();
|
||||
for (const auto &path : scriptPaths) {
|
||||
lineNum = ParseUtil::getScriptLineNumber(path, scriptLabel);
|
||||
if (lineNum != 0) {
|
||||
scriptPath = path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// First, try the current map's scripts file.
|
||||
if (openScriptInFile(scriptLabel, map->getScriptsFilepath()))
|
||||
return true;
|
||||
|
||||
openInTextEditor(scriptPath, lineNum);
|
||||
// Script is not in the current map's scripts file.
|
||||
// Search all possible script files.
|
||||
const QStringList paths = project->getAllEventScriptsFilepaths();
|
||||
for (const auto &path : paths) {
|
||||
if (openScriptInFile(scriptLabel, path))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Editor::openScriptInFile(const QString &scriptLabel, const QString &filepath) const {
|
||||
int lineNum = ParseUtil::getScriptLineNumber(filepath, scriptLabel);
|
||||
if (lineNum == 0)
|
||||
return false;
|
||||
|
||||
openInTextEditor(filepath, lineNum);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Editor::openMapJson(const QString &mapName) const {
|
||||
|
|
@ -2443,7 +2453,7 @@ void Editor::setCollisionGraphics() {
|
|||
|
||||
// Use the image sheet to create an icon for each collision/elevation combination.
|
||||
// Any icons for combinations that aren't provided by the image sheet are also created now using default graphics.
|
||||
const int w = 16, h = 16;
|
||||
const int w = Metatile::pixelWidth(), h = Metatile::pixelHeight();
|
||||
imgSheet = imgSheet.scaled(w * imgColumns, h * imgRows);
|
||||
for (int collision = 0; collision <= Block::getMaxCollision(); collision++) {
|
||||
// If (collision >= imgColumns) here, it's a valid collision value, but it is not represented with an icon on the image sheet.
|
||||
|
|
|
|||
|
|
@ -196,8 +196,9 @@ void logInit() {
|
|||
clearLogDisplays();
|
||||
});
|
||||
|
||||
Log::initialized = true;
|
||||
|
||||
if (cleanupLargeLog()) {
|
||||
logWarn(QString("Previous log file %1 was cleared due to being over 20MB in size.").arg(Log::path));
|
||||
}
|
||||
Log::initialized = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
int main(int argc, char *argv[])
|
||||
{
|
||||
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Round);
|
||||
QCoreApplication::setAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles, true);
|
||||
|
||||
QApplication a(argc, argv);
|
||||
a.setStyle("fusion");
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@
|
|||
#if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
|
||||
#define RELEASE_PLATFORM
|
||||
#endif
|
||||
#if defined(QT_NETWORK_LIB) && defined(RELEASE_PLATFORM)
|
||||
#define USE_UPDATE_PROMOTER
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
|
@ -72,7 +75,8 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
ui->setupUi(this);
|
||||
|
||||
logInit();
|
||||
logInfo(QString("Launching Porymap v%1").arg(QCoreApplication::applicationVersion()));
|
||||
logInfo(QString("Launching Porymap v%1 (%2)").arg(QCoreApplication::applicationVersion()).arg(QStringLiteral(PORYMAP_LATEST_COMMIT)));
|
||||
logInfo(QString("Using Qt v%2 (%3)").arg(QStringLiteral(QT_VERSION_STR)).arg(QSysInfo::buildCpuArchitecture()));
|
||||
}
|
||||
|
||||
void MainWindow::initialize() {
|
||||
|
|
@ -155,14 +159,33 @@ void MainWindow::initWindow() {
|
|||
this->initMapList();
|
||||
this->initShortcuts();
|
||||
|
||||
#ifndef RELEASE_PLATFORM
|
||||
QStringList missingModules;
|
||||
|
||||
#ifndef USE_UPDATE_PROMOTER
|
||||
ui->actionCheck_for_Updates->setVisible(false);
|
||||
#ifdef RELEASE_PLATFORM
|
||||
// Only report the network module missing if we would
|
||||
// have otherwise used it (we don't on non-release platforms).
|
||||
missingModules.append(" 'network'");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef QT_CHARTS_LIB
|
||||
ui->pushButton_SummaryChart->setVisible(false);
|
||||
missingModules.append(" 'charts'");
|
||||
#endif
|
||||
|
||||
#ifndef QT_QML_LIB
|
||||
ui->actionCustom_Scripts->setVisible(false);
|
||||
missingModules.append(" 'qml'");
|
||||
#endif
|
||||
|
||||
if (!missingModules.isEmpty()) {
|
||||
logWarn(QString("Qt module%1%2 not found. Some features will be disabled.")
|
||||
.arg(missingModules.length() > 1 ? "s" : "")
|
||||
.arg(missingModules.join(",")));
|
||||
}
|
||||
|
||||
setWindowDisabled(true);
|
||||
}
|
||||
|
||||
|
|
@ -320,17 +343,19 @@ void MainWindow::initExtraSignals() {
|
|||
connect(ui->action_NewMap, &QAction::triggered, this, &MainWindow::openNewMapDialog);
|
||||
connect(ui->action_NewLayout, &QAction::triggered, this, &MainWindow::openNewLayoutDialog);
|
||||
connect(ui->actionDuplicate_Current_Map_Layout, &QAction::triggered, this, &MainWindow::openDuplicateMapOrLayoutDialog);
|
||||
connect(ui->comboBox_LayoutSelector->lineEdit(), &QLineEdit::editingFinished, this, &MainWindow::onLayoutSelectorEditingFinished);
|
||||
connect(ui->comboBox_LayoutSelector, &NoScrollComboBox::editingFinished, this, &MainWindow::onLayoutSelectorEditingFinished);
|
||||
connect(ui->checkBox_smartPaths, &QCheckBox::toggled, this, &MainWindow::setSmartPathsEnabled);
|
||||
connect(ui->checkBox_ToggleBorder, &QCheckBox::toggled, this, &MainWindow::setBorderVisibility);
|
||||
connect(ui->checkBox_MirrorConnections, &QCheckBox::toggled, this, &MainWindow::setMirrorConnectionsEnabled);
|
||||
connect(ui->comboBox_PrimaryTileset, &NoScrollComboBox::editingFinished, [this] { setPrimaryTileset(ui->comboBox_PrimaryTileset->currentText()); });
|
||||
connect(ui->comboBox_SecondaryTileset, &NoScrollComboBox::editingFinished, [this] { setSecondaryTileset(ui->comboBox_SecondaryTileset->currentText()); });
|
||||
}
|
||||
|
||||
void MainWindow::on_actionCheck_for_Updates_triggered() {
|
||||
checkForUpdates(true);
|
||||
}
|
||||
|
||||
#ifdef RELEASE_PLATFORM
|
||||
#ifdef USE_UPDATE_PROMOTER
|
||||
void MainWindow::checkForUpdates(bool requestedByUser) {
|
||||
if (!this->networkAccessManager)
|
||||
this->networkAccessManager = new NetworkAccessManager(this);
|
||||
|
|
@ -345,7 +370,7 @@ void MainWindow::checkForUpdates(bool requestedByUser) {
|
|||
|
||||
|
||||
if (requestedByUser) {
|
||||
openSubWindow(this->updatePromoter);
|
||||
Util::show(this->updatePromoter);
|
||||
} else {
|
||||
// This is an automatic update check. Only run if we haven't done one in the last 5 minutes
|
||||
QDateTime lastCheck = porymapConfig.lastUpdateCheckTime;
|
||||
|
|
@ -367,7 +392,6 @@ void MainWindow::initEditor() {
|
|||
connect(this->editor, &Editor::currentMetatilesSelectionChanged, this, &MainWindow::currentMetatilesSelectionChanged);
|
||||
connect(this->editor, &Editor::wildMonTableEdited, [this] { markMapEdited(this->editor->map); });
|
||||
connect(this->editor, &Editor::mapRulerStatusChanged, this, &MainWindow::onMapRulerStatusChanged);
|
||||
connect(this->editor, &Editor::tilesetUpdated, this, &Scripting::cb_TilesetUpdated);
|
||||
connect(this->editor, &Editor::editActionSet, this, &MainWindow::setEditActionUi);
|
||||
connect(ui->newEventToolButton, &NewEventToolButton::newEventAdded, this->editor, &Editor::addNewEvent);
|
||||
connect(ui->toolButton_deleteEvent, &QAbstractButton::clicked, this->editor, &Editor::deleteSelectedEvents);
|
||||
|
|
@ -420,7 +444,7 @@ void MainWindow::initEditor() {
|
|||
}
|
||||
|
||||
void MainWindow::openEditHistory() {
|
||||
openSubWindow(this->undoView);
|
||||
Util::show(this->undoView);
|
||||
}
|
||||
|
||||
void MainWindow::initMiscHeapObjects() {
|
||||
|
|
@ -937,19 +961,6 @@ void MainWindow::refreshRecentProjectsMenu() {
|
|||
clearAction->setEnabled(!recentProjects.isEmpty());
|
||||
}
|
||||
|
||||
void MainWindow::openSubWindow(QWidget * window) {
|
||||
if (!window) return;
|
||||
|
||||
if (!window->isVisible()) {
|
||||
window->show();
|
||||
} else if (window->isMinimized()) {
|
||||
window->showNormal();
|
||||
} else {
|
||||
window->raise();
|
||||
window->activateWindow();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::showFileWatcherWarning() {
|
||||
if (!porymapConfig.monitorFiles || !isProjectOpen())
|
||||
return;
|
||||
|
|
@ -1409,7 +1420,7 @@ bool MainWindow::setProjectUI() {
|
|||
ui->newEventToolButton->setEventTypeVisible(Event::Type::SecretBase, projectConfig.eventSecretBaseEnabled);
|
||||
ui->newEventToolButton->setEventTypeVisible(Event::Type::CloneObject, projectConfig.eventCloneObjectEnabled);
|
||||
|
||||
this->editor->setPlayerViewRect(QRectF(0, 0, 16, 16).marginsAdded(projectConfig.playerViewDistance));
|
||||
this->editor->setPlayerViewRect(QRectF(QPoint(0,0), Metatile::pixelSize()).marginsAdded(projectConfig.playerViewDistance));
|
||||
|
||||
editor->setCollisionGraphics();
|
||||
ui->spinBox_SelectedElevation->setMaximum(Block::getMaxElevation());
|
||||
|
|
@ -1475,6 +1486,7 @@ void MainWindow::clearProjectUI() {
|
|||
ui->comboBox_LayoutSelector->clear();
|
||||
|
||||
this->mapHeaderForm->clear();
|
||||
ui->label_NoEvents->setText("");
|
||||
|
||||
prefab.clearPrefabUi();
|
||||
|
||||
|
|
@ -1801,7 +1813,7 @@ void MainWindow::redrawMetatileSelection() {
|
|||
|
||||
void MainWindow::scrollMetatileSelectorToSelection() {
|
||||
// Internal selections or 1x1 external selections can be scrolled to
|
||||
if (!editor->metatile_selector_item->isInternalSelection() && editor->metatile_selector_item->getSelectionDimensions() != QPoint(1, 1))
|
||||
if (!editor->metatile_selector_item->isInternalSelection() && editor->metatile_selector_item->getSelectionDimensions() != QSize(1, 1))
|
||||
return;
|
||||
|
||||
MetatileSelection selection = editor->metatile_selector_item->getMetatileSelection();
|
||||
|
|
@ -1809,8 +1821,8 @@ void MainWindow::scrollMetatileSelectorToSelection() {
|
|||
return;
|
||||
|
||||
QPoint pos = editor->metatile_selector_item->getMetatileIdCoordsOnWidget(selection.metatileItems.first().metatileId);
|
||||
QPoint size = editor->metatile_selector_item->getSelectionDimensions();
|
||||
pos += QPoint(size.x() - 1, size.y() - 1) * 16 / 2; // We want to focus on the center of the whole selection
|
||||
QSize size = editor->metatile_selector_item->getSelectionDimensions();
|
||||
pos += QPoint((size.width() - 1) * Metatile::pixelWidth(), (size.height() - 1) * Metatile::pixelHeight()) / 2; // We want to focus on the center of the whole selection
|
||||
pos *= getMetatilesZoomScale();
|
||||
|
||||
auto viewport = ui->scrollArea_MetatileSelector->viewport();
|
||||
|
|
@ -1821,7 +1833,9 @@ void MainWindow::currentMetatilesSelectionChanged() {
|
|||
redrawMetatileSelection();
|
||||
if (this->tilesetEditor) {
|
||||
MetatileSelection selection = editor->metatile_selector_item->getMetatileSelection();
|
||||
this->tilesetEditor->selectMetatile(selection.metatileItems.first().metatileId);
|
||||
if (!selection.metatileItems.isEmpty()) {
|
||||
this->tilesetEditor->selectMetatile(selection.metatileItems.first().metatileId);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't scroll to internal selections here, it will disrupt the user while they make their selection.
|
||||
|
|
@ -1982,8 +1996,8 @@ void MainWindow::copy() {
|
|||
}
|
||||
copyObject["metatile_selection"] = metatiles;
|
||||
copyObject["collision_selection"] = collisions;
|
||||
copyObject["width"] = editor->metatile_selector_item->getSelectionDimensions().x();
|
||||
copyObject["height"] = editor->metatile_selector_item->getSelectionDimensions().y();
|
||||
copyObject["width"] = editor->metatile_selector_item->getSelectionDimensions().width();
|
||||
copyObject["height"] = editor->metatile_selector_item->getSelectionDimensions().height();
|
||||
setClipboardData(copyObject);
|
||||
logInfo("Copied metatile selection to clipboard");
|
||||
}
|
||||
|
|
@ -2176,7 +2190,6 @@ void MainWindow::on_mapViewTab_tabBarClicked(int index)
|
|||
prefab.updatePrefabUi(this->editor->layout);
|
||||
}
|
||||
}
|
||||
editor->setCursorRectVisible(false);
|
||||
}
|
||||
|
||||
void MainWindow::on_mainTabBar_tabBarClicked(int index)
|
||||
|
|
@ -2240,11 +2253,7 @@ void MainWindow::on_actionPlayer_View_Rectangle_triggered()
|
|||
bool enabled = ui->actionPlayer_View_Rectangle->isChecked();
|
||||
porymapConfig.showPlayerView = enabled;
|
||||
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->getActive());
|
||||
ui->graphicsView_Map->scene()->update();
|
||||
}
|
||||
this->editor->updateCursorRectVisibility();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionCursor_Tile_Outline_triggered()
|
||||
|
|
@ -2252,11 +2261,7 @@ void MainWindow::on_actionCursor_Tile_Outline_triggered()
|
|||
bool enabled = ui->actionCursor_Tile_Outline->isChecked();
|
||||
porymapConfig.showCursorTile = enabled;
|
||||
this->editor->settings->cursorTileRectEnabled = enabled;
|
||||
if ((this->editor->map_item && this->editor->map_item->has_mouse)
|
||||
|| (this->editor->collision_item && this->editor->collision_item->has_mouse)) {
|
||||
this->editor->cursorMapTileRect->setVisible(enabled && this->editor->cursorMapTileRect->getActive());
|
||||
ui->graphicsView_Map->scene()->update();
|
||||
}
|
||||
this->editor->updateCursorRectVisibility();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionShow_Events_In_Map_View_triggered() {
|
||||
|
|
@ -2274,7 +2279,7 @@ void MainWindow::on_actionGrid_Settings_triggered() {
|
|||
connect(this->gridSettingsDialog, &GridSettingsDialog::changedGridSettings, this->editor, &Editor::updateMapGrid);
|
||||
connect(this->gridSettingsDialog, &GridSettingsDialog::accepted, [this] { porymapConfig.gridSettings = this->editor->gridSettings; });
|
||||
}
|
||||
openSubWindow(this->gridSettingsDialog);
|
||||
Util::show(this->gridSettingsDialog);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionShortcuts_triggered()
|
||||
|
|
@ -2282,7 +2287,7 @@ void MainWindow::on_actionShortcuts_triggered()
|
|||
if (!shortcutsEditor)
|
||||
initShortcutsEditor();
|
||||
|
||||
openSubWindow(shortcutsEditor);
|
||||
Util::show(shortcutsEditor);
|
||||
}
|
||||
|
||||
void MainWindow::initShortcutsEditor() {
|
||||
|
|
@ -2292,27 +2297,40 @@ void MainWindow::initShortcutsEditor() {
|
|||
|
||||
connectSubEditorsToShortcutsEditor();
|
||||
|
||||
shortcutsEditor->setShortcutableObjects(shortcutableObjects());
|
||||
auto objectList = shortcutableObjects();
|
||||
for (auto *menu : findChildren<QMenu *>()) {
|
||||
if (!menu->objectName().isEmpty())
|
||||
objectList.append(qobject_cast<QObject *>(menu));
|
||||
}
|
||||
shortcutsEditor->setShortcutableObjects(objectList);
|
||||
}
|
||||
|
||||
void MainWindow::connectSubEditorsToShortcutsEditor() {
|
||||
/* Initialize sub-editors so that their children are added to MainWindow's object tree and will
|
||||
* be returned by shortcutableObjects() to be passed to ShortcutsEditor. */
|
||||
if (!tilesetEditor)
|
||||
if (!this->tilesetEditor) {
|
||||
initTilesetEditor();
|
||||
connect(shortcutsEditor, &ShortcutsEditor::shortcutsSaved,
|
||||
tilesetEditor, &TilesetEditor::applyUserShortcuts);
|
||||
}
|
||||
if (this->tilesetEditor) {
|
||||
connect(this->shortcutsEditor, &ShortcutsEditor::shortcutsSaved,
|
||||
this->tilesetEditor, &TilesetEditor::applyUserShortcuts);
|
||||
}
|
||||
|
||||
if (!regionMapEditor)
|
||||
if (!this->regionMapEditor){
|
||||
initRegionMapEditor(true);
|
||||
if (regionMapEditor)
|
||||
connect(shortcutsEditor, &ShortcutsEditor::shortcutsSaved,
|
||||
regionMapEditor, &RegionMapEditor::applyUserShortcuts);
|
||||
}
|
||||
if (this->regionMapEditor) {
|
||||
connect(this->shortcutsEditor, &ShortcutsEditor::shortcutsSaved,
|
||||
this->regionMapEditor, &RegionMapEditor::applyUserShortcuts);
|
||||
}
|
||||
|
||||
if (!customScriptsEditor)
|
||||
if (!this->customScriptsEditor) {
|
||||
initCustomScriptsEditor();
|
||||
connect(shortcutsEditor, &ShortcutsEditor::shortcutsSaved,
|
||||
customScriptsEditor, &CustomScriptsEditor::applyUserShortcuts);
|
||||
}
|
||||
if (this->customScriptsEditor) {
|
||||
connect(this->shortcutsEditor, &ShortcutsEditor::shortcutsSaved,
|
||||
this->customScriptsEditor, &CustomScriptsEditor::applyUserShortcuts);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::resetMapViewScale() {
|
||||
|
|
@ -2495,6 +2513,14 @@ void MainWindow::updateSelectedEvents() {
|
|||
}
|
||||
else {
|
||||
ui->tabWidget_EventType->hide();
|
||||
|
||||
if (this->editor->map && this->editor->map->isInheritingEvents()) {
|
||||
QString message = QString("<span style=\"color:red;\">NOTE:</span> This map inherits events from %1."
|
||||
"<br>Adding any events will separate it from that map.").arg(this->editor->map->sharedEventsMap());
|
||||
ui->label_NoEvents->setText(message);
|
||||
} else {
|
||||
ui->label_NoEvents->setText(QStringLiteral("There are no events on the current map."));
|
||||
}
|
||||
ui->label_NoEvents->show();
|
||||
}
|
||||
}
|
||||
|
|
@ -2588,19 +2614,6 @@ void MainWindow::on_toolButton_Move_clicked() { editor->setEditAction(Editor:
|
|||
void MainWindow::on_toolButton_Shift_clicked() { editor->setEditAction(Editor::EditAction::Shift); }
|
||||
|
||||
void MainWindow::setEditActionUi(Editor::EditAction editAction) {
|
||||
if (editAction == Editor::EditAction::Move) {
|
||||
ui->graphicsView_Map->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
ui->graphicsView_Map->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
QScroller::grabGesture(ui->graphicsView_Map, QScroller::LeftMouseButtonGesture);
|
||||
ui->graphicsView_Map->setViewportUpdateMode(QGraphicsView::ViewportUpdateMode::FullViewportUpdate);
|
||||
} else {
|
||||
ui->graphicsView_Map->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
ui->graphicsView_Map->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
QScroller::ungrabGesture(ui->graphicsView_Map);
|
||||
ui->graphicsView_Map->setViewportUpdateMode(QGraphicsView::ViewportUpdateMode::MinimalViewportUpdate);
|
||||
}
|
||||
ui->graphicsView_Map->setFocus();
|
||||
|
||||
ui->toolButton_Paint->setChecked(editAction == Editor::EditAction::Paint);
|
||||
ui->toolButton_Select->setChecked(editAction == Editor::EditAction::Select);
|
||||
ui->toolButton_Fill->setChecked(editAction == Editor::EditAction::Fill);
|
||||
|
|
@ -2719,7 +2732,7 @@ void MainWindow::showExportMapImageWindow(ImageExporterMode mode) {
|
|||
}
|
||||
}
|
||||
|
||||
openSubWindow(this->mapImageExporter);
|
||||
Util::show(this->mapImageExporter);
|
||||
}
|
||||
|
||||
void MainWindow::on_pushButton_AddConnection_clicked() {
|
||||
|
|
@ -2747,7 +2760,7 @@ void MainWindow::on_pushButton_SummaryChart_clicked() {
|
|||
connect(this->editor, &Editor::wildMonTableClosed, this->wildMonChart, &WildMonChart::clearTable);
|
||||
connect(this->editor, &Editor::wildMonTableEdited, this->wildMonChart, &WildMonChart::refresh);
|
||||
}
|
||||
openSubWindow(this->wildMonChart);
|
||||
Util::show(this->wildMonChart);
|
||||
}
|
||||
|
||||
void MainWindow::on_toolButton_WildMonSearch_clicked() {
|
||||
|
|
@ -2756,7 +2769,7 @@ void MainWindow::on_toolButton_WildMonSearch_clicked() {
|
|||
connect(this->wildMonSearch, &WildMonSearch::openWildMonTableRequested, this, &MainWindow::openWildMonTable);
|
||||
connect(this->editor, &Editor::wildMonTableEdited, this->wildMonSearch, &WildMonSearch::refresh);
|
||||
}
|
||||
openSubWindow(this->wildMonSearch);
|
||||
Util::show(this->wildMonSearch);
|
||||
}
|
||||
|
||||
void MainWindow::openWildMonTable(const QString &mapName, const QString &groupName, const QString &fieldName) {
|
||||
|
|
@ -2781,26 +2794,38 @@ void MainWindow::on_button_OpenEmergeMap_clicked() {
|
|||
userSetMap(ui->comboBox_EmergeMap->currentText());
|
||||
}
|
||||
|
||||
void MainWindow::on_comboBox_PrimaryTileset_currentTextChanged(const QString &tilesetLabel)
|
||||
{
|
||||
if (editor->project->primaryTilesetLabels.contains(tilesetLabel) && editor->layout) {
|
||||
void MainWindow::setPrimaryTileset(const QString &tilesetLabel) {
|
||||
if (!this->editor->layout || this->editor->layout->tileset_primary_label == tilesetLabel)
|
||||
return;
|
||||
|
||||
if (editor->project->primaryTilesetLabels.contains(tilesetLabel)) {
|
||||
editor->updatePrimaryTileset(tilesetLabel);
|
||||
redrawMapScene();
|
||||
updateTilesetEditor();
|
||||
prefab.updatePrefabUi(editor->layout);
|
||||
markLayoutEdited();
|
||||
}
|
||||
|
||||
// Restore valid text if input was invalid, or sync combo box with new valid setting.
|
||||
const QSignalBlocker b(ui->comboBox_PrimaryTileset);
|
||||
ui->comboBox_PrimaryTileset->setTextItem(this->editor->layout->tileset_primary_label);
|
||||
}
|
||||
|
||||
void MainWindow::on_comboBox_SecondaryTileset_currentTextChanged(const QString &tilesetLabel)
|
||||
{
|
||||
if (editor->project->secondaryTilesetLabels.contains(tilesetLabel) && editor->layout) {
|
||||
void MainWindow::setSecondaryTileset(const QString &tilesetLabel) {
|
||||
if (!this->editor->layout || this->editor->layout->tileset_secondary_label == tilesetLabel)
|
||||
return;
|
||||
|
||||
if (editor->project->secondaryTilesetLabels.contains(tilesetLabel)) {
|
||||
editor->updateSecondaryTileset(tilesetLabel);
|
||||
redrawMapScene();
|
||||
updateTilesetEditor();
|
||||
prefab.updatePrefabUi(editor->layout);
|
||||
markLayoutEdited();
|
||||
}
|
||||
|
||||
// Restore valid text if input was invalid, or sync combo box with new valid setting.
|
||||
const QSignalBlocker b(ui->comboBox_SecondaryTileset);
|
||||
ui->comboBox_SecondaryTileset->setTextItem(this->editor->layout->tileset_secondary_label);
|
||||
}
|
||||
|
||||
void MainWindow::on_pushButton_ChangeDimensions_clicked() {
|
||||
|
|
@ -2864,10 +2889,12 @@ void MainWindow::on_actionTileset_Editor_triggered()
|
|||
initTilesetEditor();
|
||||
}
|
||||
|
||||
openSubWindow(this->tilesetEditor);
|
||||
Util::show(this->tilesetEditor);
|
||||
|
||||
MetatileSelection selection = this->editor->metatile_selector_item->getMetatileSelection();
|
||||
this->tilesetEditor->selectMetatile(selection.metatileItems.first().metatileId);
|
||||
if (!selection.metatileItems.isEmpty()) {
|
||||
this->tilesetEditor->selectMetatile(selection.metatileItems.first().metatileId);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::initTilesetEditor() {
|
||||
|
|
@ -2914,7 +2941,7 @@ void MainWindow::on_actionAbout_Porymap_triggered()
|
|||
{
|
||||
if (!this->aboutWindow)
|
||||
this->aboutWindow = new AboutPorymap(this);
|
||||
openSubWindow(this->aboutWindow);
|
||||
Util::show(this->aboutWindow);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionOpen_Log_File_triggered() {
|
||||
|
|
@ -2927,6 +2954,11 @@ void MainWindow::on_actionOpen_Config_Folder_triggered() {
|
|||
QDesktopServices::openUrl(QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)));
|
||||
}
|
||||
|
||||
void MainWindow::on_actionOpen_Manual_triggered() {
|
||||
static const QUrl url("https://huderlem.github.io/porymap/");
|
||||
QDesktopServices::openUrl(url);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionPreferences_triggered() {
|
||||
if (!preferenceEditor) {
|
||||
preferenceEditor = new PreferenceEditor(this);
|
||||
|
|
@ -2938,16 +2970,19 @@ void MainWindow::on_actionPreferences_triggered() {
|
|||
// require us to repopulate the EventFrames and redraw event pixmaps, respectively.
|
||||
connect(preferenceEditor, &PreferenceEditor::preferencesSaved, editor, &Editor::updateEvents);
|
||||
connect(preferenceEditor, &PreferenceEditor::scriptSettingsChanged, editor->project, &Project::readEventScriptLabels);
|
||||
connect(preferenceEditor, &PreferenceEditor::reloadProjectRequested, this, &MainWindow::on_action_Reload_Project_triggered);
|
||||
}
|
||||
|
||||
openSubWindow(preferenceEditor);
|
||||
Util::show(preferenceEditor);
|
||||
}
|
||||
|
||||
void MainWindow::togglePreferenceSpecificUi() {
|
||||
ui->actionOpen_Project_in_Text_Editor->setEnabled(!porymapConfig.textEditorOpenFolder.isEmpty());
|
||||
|
||||
#ifdef USE_UPDATE_PROMOTER
|
||||
if (this->updatePromoter)
|
||||
this->updatePromoter->updatePreferences();
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::openProjectSettingsEditor(int tab) {
|
||||
|
|
@ -2957,7 +2992,7 @@ void MainWindow::openProjectSettingsEditor(int tab) {
|
|||
this, &MainWindow::on_action_Reload_Project_triggered);
|
||||
}
|
||||
this->projectSettingsEditor->setTab(tab);
|
||||
openSubWindow(this->projectSettingsEditor);
|
||||
Util::show(this->projectSettingsEditor);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionProject_Settings_triggered() {
|
||||
|
|
@ -2992,16 +3027,20 @@ void MainWindow::onWarpBehaviorWarningClicked() {
|
|||
}
|
||||
|
||||
void MainWindow::on_actionCustom_Scripts_triggered() {
|
||||
if (!this->customScriptsEditor)
|
||||
if (!this->customScriptsEditor) {
|
||||
initCustomScriptsEditor();
|
||||
|
||||
openSubWindow(this->customScriptsEditor);
|
||||
}
|
||||
if (this->customScriptsEditor) {
|
||||
Util::show(this->customScriptsEditor);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::initCustomScriptsEditor() {
|
||||
#ifdef QT_QML_LIB
|
||||
this->customScriptsEditor = new CustomScriptsEditor(this);
|
||||
connect(this->customScriptsEditor, &CustomScriptsEditor::reloadScriptEngine,
|
||||
this, &MainWindow::reloadScriptEngine);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::reloadScriptEngine() {
|
||||
|
|
@ -3075,7 +3114,7 @@ void MainWindow::on_actionRegion_Map_Editor_triggered() {
|
|||
}
|
||||
}
|
||||
|
||||
openSubWindow(this->regionMapEditor);
|
||||
Util::show(this->regionMapEditor);
|
||||
}
|
||||
|
||||
void MainWindow::on_pushButton_CreatePrefab_clicked() {
|
||||
|
|
@ -3133,7 +3172,7 @@ bool MainWindow::closeSupplementaryWindows() {
|
|||
if (widget != this && widget->isWindow()) {
|
||||
// Make sure the window is raised and activated before closing in case it has a confirmation prompt.
|
||||
if (widget->isVisible()) {
|
||||
openSubWindow(widget);
|
||||
Util::show(widget);
|
||||
}
|
||||
if (!widget->close()) {
|
||||
QString message = QStringLiteral("Aborted project close");
|
||||
|
|
|
|||
363
src/project.cpp
363
src/project.cpp
|
|
@ -32,9 +32,7 @@ int Project::num_pals_total = 13;
|
|||
|
||||
Project::Project(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
QObject::connect(&this->fileWatcher, &QFileSystemWatcher::fileChanged, this, &Project::recordFileChange);
|
||||
}
|
||||
{ }
|
||||
|
||||
Project::~Project()
|
||||
{
|
||||
|
|
@ -186,7 +184,10 @@ int Project::getSupportedMajorVersion(QString *errorOut) {
|
|||
|
||||
bool Project::load() {
|
||||
this->parser.setUpdatesSplashScreen(true);
|
||||
resetFileWatcher();
|
||||
resetFileCache();
|
||||
QPixmapCache::clear();
|
||||
|
||||
this->disabledSettingsNames.clear();
|
||||
bool success = readGlobalConstants()
|
||||
&& readMapLayouts()
|
||||
|
|
@ -225,6 +226,7 @@ bool Project::load() {
|
|||
initNewLayoutSettings();
|
||||
initNewMapSettings();
|
||||
applyParsedLimits();
|
||||
logFileWatchStatus();
|
||||
}
|
||||
this->parser.setUpdatesSplashScreen(false);
|
||||
return success;
|
||||
|
|
@ -232,7 +234,6 @@ bool Project::load() {
|
|||
|
||||
void Project::resetFileCache() {
|
||||
this->parser.clearFileCache();
|
||||
this->failedFileWatchPaths.clear();
|
||||
|
||||
const QSet<QString> filepaths = {
|
||||
// Whenever we load a tileset we'll need to parse some data from these files, so we cache them to avoid the overhead of opening the files.
|
||||
|
|
@ -274,6 +275,17 @@ void Project::clearTilesetCache() {
|
|||
this->tilesetCache.clear();
|
||||
}
|
||||
|
||||
void Project::cacheTileset(const QString &name, Tileset *tileset) {
|
||||
auto it = this->tilesetCache.constFind(name);
|
||||
if (it != this->tilesetCache.constEnd() && it.value() && tileset != it.value()) {
|
||||
// Callers of this function should ensure this doesn't happen,
|
||||
// but in case it does we should avoid leaking memory.
|
||||
logWarn(QString("New tileset %1 overwrote existing tileset.").arg(name));
|
||||
delete it.value();
|
||||
}
|
||||
this->tilesetCache.insert(name, tileset);
|
||||
}
|
||||
|
||||
Map* Project::loadMap(const QString &mapName) {
|
||||
if (mapName == getDynamicMapName()) {
|
||||
// Silently ignored, caller is expected to handle this if they want this to be an error.
|
||||
|
|
@ -348,10 +360,10 @@ QSet<QString> Project::getTopLevelMapFields() const {
|
|||
"show_map_name",
|
||||
"battle_scene",
|
||||
"connections",
|
||||
"object_events",
|
||||
"warp_events",
|
||||
"coord_events",
|
||||
"bg_events",
|
||||
Event::groupToJsonKey(Event::Group::Object),
|
||||
Event::groupToJsonKey(Event::Group::Warp),
|
||||
Event::groupToJsonKey(Event::Group::Coord),
|
||||
Event::groupToJsonKey(Event::Group::Bg),
|
||||
"shared_events_map",
|
||||
"shared_scripts_map",
|
||||
};
|
||||
|
|
@ -450,10 +462,10 @@ bool Project::loadMapData(Map* map) {
|
|||
static const QMap<QString, Event::Type> defaultEventTypes = {
|
||||
// Map of the expected keys for each event group, and the default type of that group.
|
||||
// If the default type is Type::None then each event must specify its type, or its an error.
|
||||
{"object_events", Event::Type::Object},
|
||||
{"warp_events", Event::Type::Warp},
|
||||
{"coord_events", Event::Type::None},
|
||||
{"bg_events", Event::Type::None},
|
||||
{Event::groupToJsonKey(Event::Group::Object), Event::Type::Object},
|
||||
{Event::groupToJsonKey(Event::Group::Warp), Event::Type::Warp},
|
||||
{Event::groupToJsonKey(Event::Group::Coord), Event::Type::None},
|
||||
{Event::groupToJsonKey(Event::Group::Bg), Event::Type::None},
|
||||
};
|
||||
for (auto i = defaultEventTypes.constBegin(); i != defaultEventTypes.constEnd(); i++) {
|
||||
QString eventGroupKey = i.key();
|
||||
|
|
@ -749,16 +761,21 @@ bool Project::saveMapLayouts() {
|
|||
}
|
||||
|
||||
bool Project::watchFile(const QString &filename) {
|
||||
if (!porymapConfig.monitorFiles)
|
||||
return true;
|
||||
|
||||
if (!this->fileWatcher) {
|
||||
// Only create the file watcher when it's first needed (even an empty QFileSystemWatcher will consume system resources).
|
||||
this->fileWatcher = new QFileSystemWatcher(this);
|
||||
QObject::connect(this->fileWatcher, &QFileSystemWatcher::fileChanged, this, &Project::recordFileChange);
|
||||
}
|
||||
|
||||
QString filepath = filename.startsWith(this->root) ? filename : QString("%1/%2").arg(this->root).arg(filename);
|
||||
if (!this->fileWatcher.addPath(filepath) && !this->fileWatcher.files().contains(filepath)) {
|
||||
if (!this->fileWatcher->addPath(filepath) && !this->fileWatcher->files().contains(filepath)) {
|
||||
// We failed to watch the file, and this wasn't a file we were already watching.
|
||||
// Log a warning, but only if A. we actually care that we failed, because 'monitor files' is enabled,
|
||||
// B. we haven't logged a warning for this file yet, and C. we would have otherwise been able to watch it, because the file exists.
|
||||
if (porymapConfig.monitorFiles && !this->failedFileWatchPaths.contains(filepath) && QFileInfo::exists(filepath)) {
|
||||
// Record the filepath for logging later, assuming we should have been able to watch the file.
|
||||
if (QFileInfo::exists(filepath)) {
|
||||
this->failedFileWatchPaths.insert(filepath);
|
||||
logWarn(QString("Failed to add '%1' to file watcher. Currently watching %2 files.")
|
||||
.arg(Util::stripPrefix(filepath, this->root))
|
||||
.arg(this->fileWatcher.files().length()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -774,8 +791,11 @@ bool Project::watchFiles(const QStringList &filenames) {
|
|||
}
|
||||
|
||||
bool Project::stopFileWatch(const QString &filename) {
|
||||
if (!this->fileWatcher)
|
||||
return true;
|
||||
|
||||
QString filepath = filename.startsWith(this->root) ? filename : QString("%1/%2").arg(this->root).arg(filename);
|
||||
return this->fileWatcher.removePath(filepath);
|
||||
return this->fileWatcher->removePath(filepath);
|
||||
}
|
||||
|
||||
void Project::ignoreWatchedFileTemporarily(const QString &filepath) {
|
||||
|
|
@ -794,8 +814,8 @@ void Project::recordFileChange(const QString &filepath) {
|
|||
// Note: As a safety measure, many applications save an open file by writing a new file and then deleting the old one.
|
||||
// In your slot function, you can check watcher.files().contains(path).
|
||||
// If it returns false, check whether the file still exists and then call addPath() to continue watching it.
|
||||
if (!this->fileWatcher.files().contains(filepath) && QFileInfo::exists(filepath)) {
|
||||
this->fileWatcher.addPath(filepath);
|
||||
if (this->fileWatcher && !this->fileWatcher->files().contains(filepath) && QFileInfo::exists(filepath)) {
|
||||
this->fileWatcher->addPath(filepath);
|
||||
}
|
||||
|
||||
if (this->modifiedFiles.contains(filepath)) {
|
||||
|
|
@ -815,6 +835,38 @@ void Project::recordFileChange(const QString &filepath) {
|
|||
emit fileChanged(filepath);
|
||||
}
|
||||
|
||||
// When calling 'watchFile' we record failures rather than log them immediately.
|
||||
// We do this primarily to condense the warning if we fail to monitor any files.
|
||||
void Project::logFileWatchStatus() {
|
||||
if (!this->fileWatcher)
|
||||
return;
|
||||
|
||||
int numSuccessful = this->fileWatcher->files().length();
|
||||
int numAttempted = numSuccessful + this->failedFileWatchPaths.count();
|
||||
if (numAttempted == 0)
|
||||
return;
|
||||
|
||||
if (numSuccessful == 0) {
|
||||
// We failed to watch every file we tried. As of writing this happens if Porymap is running
|
||||
// on Windows and the project files are in WSL2. Rather than filling the log by
|
||||
// outputting a warning for every file, just log that we failed to monitor any of them.
|
||||
logWarn(QString("Failed to monitor project files"));
|
||||
return;
|
||||
} else {
|
||||
logInfo(QString("Successfully monitoring %1/%2 project files").arg(numSuccessful).arg(numAttempted));
|
||||
}
|
||||
|
||||
for (const auto &failedPath : this->failedFileWatchPaths) {
|
||||
logWarn(QString("Failed to monitor project file '%1'").arg(failedPath));
|
||||
}
|
||||
}
|
||||
|
||||
void Project::resetFileWatcher() {
|
||||
this->failedFileWatchPaths.clear();
|
||||
delete this->fileWatcher;
|
||||
this->fileWatcher = nullptr;
|
||||
}
|
||||
|
||||
bool Project::saveMapGroups() {
|
||||
QString mapGroupsFilepath = QString("%1/%2").arg(root).arg(projectConfig.getFilePath(ProjectFilePath::json_map_groups));
|
||||
QFile mapGroupsFile(mapGroupsFilepath);
|
||||
|
|
@ -1135,13 +1187,44 @@ bool Project::loadLayoutTilesets(Layout *layout) {
|
|||
logError(QString("Failed to load %1: missing secondary tileset label.").arg(layout->name));
|
||||
return false;
|
||||
}
|
||||
if (!this->primaryTilesetLabels.contains(layout->tileset_primary_label)) {
|
||||
logError(QString("Failed to load %1: unknown primary tileset label '%2'.")
|
||||
.arg(layout->name)
|
||||
.arg(layout->tileset_primary_label));
|
||||
return false;
|
||||
}
|
||||
if (!this->secondaryTilesetLabels.contains(layout->tileset_secondary_label)) {
|
||||
logError(QString("Failed to load %1: unknown secondary tileset label '%2'.")
|
||||
.arg(layout->name)
|
||||
.arg(layout->tileset_secondary_label));
|
||||
return false;
|
||||
}
|
||||
|
||||
layout->tileset_primary = getTileset(layout->tileset_primary_label);
|
||||
layout->tileset_secondary = getTileset(layout->tileset_secondary_label);
|
||||
return layout->tileset_primary && layout->tileset_secondary;
|
||||
}
|
||||
|
||||
Tileset* Project::loadTileset(QString label, Tileset *tileset) {
|
||||
Tileset* Project::getTileset(const QString &label, bool forceLoad) {
|
||||
if (!this->tilesetLabelsOrdered.contains(label)) {
|
||||
logError(QString("Unknown tileset name '%1'.").arg(label));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Tileset *tileset = nullptr;
|
||||
|
||||
auto it = this->tilesetCache.constFind(label);
|
||||
if (it != this->tilesetCache.constEnd()) {
|
||||
tileset = it.value();
|
||||
if (!forceLoad) {
|
||||
return tileset;
|
||||
}
|
||||
} else {
|
||||
// Create a cache entry even if we don't end up loading the tileset successfully.
|
||||
// This will prevent repeated file reads if the tileset fails to load.
|
||||
cacheTileset(label, nullptr);
|
||||
}
|
||||
|
||||
auto memberMap = Tileset::getHeaderMemberMap(this->usingAsmTilesets);
|
||||
if (this->usingAsmTilesets) {
|
||||
// Read asm tileset header. Backwards compatibility
|
||||
|
|
@ -1186,7 +1269,7 @@ Tileset* Project::loadTileset(QString label, Tileset *tileset) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
tilesetCache.insert(label, tileset);
|
||||
cacheTileset(tileset->name, tileset);
|
||||
return tileset;
|
||||
}
|
||||
|
||||
|
|
@ -1216,7 +1299,7 @@ void Project::setNewLayoutBorder(Layout *layout) {
|
|||
} else {
|
||||
// Fill the border with the default metatiles from the config.
|
||||
for (int i = 0; i < width * height; i++) {
|
||||
layout->border.append(projectConfig.newMapBorderMetatileIds.at(i));
|
||||
layout->border.append(projectConfig.newMapBorderMetatileIds.value(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1313,43 +1396,27 @@ bool Project::saveMap(Map *map, bool skipLayout) {
|
|||
mapObj["connections"] = OrderedJson();
|
||||
}
|
||||
|
||||
if (map->sharedEventsMap().isEmpty()) {
|
||||
// Object events
|
||||
OrderedJson::array objectEventsArr;
|
||||
for (const auto &event : map->getEvents(Event::Group::Object)){
|
||||
objectEventsArr.push_back(event->buildEventJson(this));
|
||||
}
|
||||
mapObj["object_events"] = objectEventsArr;
|
||||
|
||||
|
||||
// Warp events
|
||||
OrderedJson::array warpEventsArr;
|
||||
for (const auto &event : map->getEvents(Event::Group::Warp)) {
|
||||
warpEventsArr.push_back(event->buildEventJson(this));
|
||||
}
|
||||
mapObj["warp_events"] = warpEventsArr;
|
||||
|
||||
// Coord events
|
||||
OrderedJson::array coordEventsArr;
|
||||
for (const auto &event : map->getEvents(Event::Group::Coord)) {
|
||||
coordEventsArr.push_back(event->buildEventJson(this));
|
||||
}
|
||||
mapObj["coord_events"] = coordEventsArr;
|
||||
|
||||
// Bg Events
|
||||
OrderedJson::array bgEventsArr;
|
||||
for (const auto &event : map->getEvents(Event::Group::Bg)) {
|
||||
bgEventsArr.push_back(event->buildEventJson(this));
|
||||
}
|
||||
mapObj["bg_events"] = bgEventsArr;
|
||||
} else {
|
||||
if (map->isInheritingEvents()) {
|
||||
mapObj["shared_events_map"] = map->sharedEventsMap();
|
||||
}
|
||||
|
||||
if (!map->sharedScriptsMap().isEmpty()) {
|
||||
if (map->isInheritingScripts()) {
|
||||
mapObj["shared_scripts_map"] = map->sharedScriptsMap();
|
||||
}
|
||||
|
||||
if (!map->isInheritingEvents()) {
|
||||
auto buildEventsJson = [this, map](Event::Group group, OrderedJson::object *json) {
|
||||
OrderedJson::array arr;
|
||||
for (const auto &event : map->getEvents(group)){
|
||||
arr.push_back(event->buildEventJson(this));
|
||||
}
|
||||
(*json)[Event::groupToJsonKey(group)] = arr;
|
||||
};
|
||||
buildEventsJson(Event::Group::Object, &mapObj);
|
||||
buildEventsJson(Event::Group::Warp, &mapObj);
|
||||
buildEventsJson(Event::Group::Coord, &mapObj);
|
||||
buildEventsJson(Event::Group::Bg, &mapObj);
|
||||
}
|
||||
|
||||
// Update the global heal locations array using the Map's heal location events.
|
||||
// This won't get saved to disc until Project::saveHealLocations is called.
|
||||
QList<HealLocationEvent*> hlEvents;
|
||||
|
|
@ -1478,7 +1545,7 @@ void Project::readTilesetPaths(Tileset* tileset) {
|
|||
tileset->metatile_attrs_path = defaultPath + "/metatile_attributes.bin";
|
||||
if (tileset->palettePaths.isEmpty()) {
|
||||
QString palettes_dir_path = defaultPath + "/palettes/";
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int i = 0; i < Tileset::maxPalettes(); i++) {
|
||||
tileset->palettePaths.append(palettes_dir_path + QString("%1").arg(i, 2, 10, QLatin1Char('0')) + ".pal");
|
||||
}
|
||||
}
|
||||
|
|
@ -1519,9 +1586,8 @@ Tileset *Project::createNewTileset(QString name, bool secondary, bool checkerboa
|
|||
tileset->loadTilesImage(&tilesImage);
|
||||
|
||||
// Create default metatiles
|
||||
const int numMetatiles = tileset->is_secondary ? (Project::getNumMetatilesTotal() - Project::getNumMetatilesPrimary()) : Project::getNumMetatilesPrimary();
|
||||
const int tilesPerMetatile = projectConfig.getNumTilesInMetatile();
|
||||
for (int i = 0; i < numMetatiles; ++i) {
|
||||
for (int i = 0; i < tileset->maxMetatiles(); ++i) {
|
||||
auto metatile = new Metatile();
|
||||
for(int j = 0; j < tilesPerMetatile; ++j){
|
||||
Tile tile = Tile();
|
||||
|
|
@ -1541,9 +1607,9 @@ Tileset *Project::createNewTileset(QString name, bool secondary, bool checkerboa
|
|||
}
|
||||
|
||||
// Create default palettes
|
||||
for(int i = 0; i < 16; ++i) {
|
||||
for(int i = 0; i < Tileset::maxPalettes(); ++i) {
|
||||
QList<QRgb> currentPal;
|
||||
for(int i = 0; i < 16;++i) {
|
||||
for(int i = 0; i < Tileset::numColorsPerPalette();++i) {
|
||||
currentPal.append(qRgb(0,0,0));
|
||||
}
|
||||
tileset->palettes.append(currentPal);
|
||||
|
|
@ -1579,15 +1645,14 @@ Tileset *Project::createNewTileset(QString name, bool secondary, bool checkerboa
|
|||
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);
|
||||
QString baseName = Tileset::stripPrefix(name);
|
||||
tileset->appendToHeaders(headersFilepath, baseName, this->usingAsmTilesets);
|
||||
tileset->appendToGraphics(graphicsFilepath, baseName, this->usingAsmTilesets);
|
||||
tileset->appendToMetatiles(metatilesFilepath, baseName, this->usingAsmTilesets);
|
||||
|
||||
tileset->save();
|
||||
|
||||
this->tilesetCache.insert(tileset->name, tileset);
|
||||
|
||||
cacheTileset(tileset->name, tileset);
|
||||
emit tilesetCreated(tileset);
|
||||
return tileset;
|
||||
}
|
||||
|
|
@ -1636,26 +1701,13 @@ void Project::loadTilesetMetatileLabels(Tileset* tileset) {
|
|||
QString metatileLabelPrefix = tileset->getMetatileLabelPrefix();
|
||||
|
||||
// Reverse map for faster lookup by metatile id
|
||||
tileset->metatileLabels.clear();
|
||||
for (auto it = this->metatileLabelsMap[tileset->name].constBegin(); it != this->metatileLabelsMap[tileset->name].constEnd(); it++) {
|
||||
QString labelName = it.key();
|
||||
tileset->metatileLabels[it.value()] = labelName.replace(metatileLabelPrefix, "");
|
||||
}
|
||||
}
|
||||
|
||||
Tileset* Project::getTileset(QString label, bool forceLoad) {
|
||||
Tileset *existingTileset = nullptr;
|
||||
if (tilesetCache.contains(label)) {
|
||||
existingTileset = tilesetCache.value(label);
|
||||
}
|
||||
|
||||
if (existingTileset && !forceLoad) {
|
||||
return existingTileset;
|
||||
} else {
|
||||
Tileset *tileset = loadTileset(label, existingTileset);
|
||||
return tileset;
|
||||
}
|
||||
}
|
||||
|
||||
bool Project::saveTextFile(const QString &path, const QString &text) {
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
|
|
@ -2228,6 +2280,7 @@ bool Project::readTilesetLabels() {
|
|||
this->primaryTilesetLabels.clear();
|
||||
this->secondaryTilesetLabels.clear();
|
||||
this->tilesetLabelsOrdered.clear();
|
||||
clearTilesetCache();
|
||||
|
||||
QString filename = projectConfig.getFilePath(ProjectFilePath::tilesets_headers);
|
||||
QFileInfo fileInfo(this->root + "/" + filename);
|
||||
|
|
@ -2309,7 +2362,7 @@ bool Project::readFieldmapProperties() {
|
|||
logWarn(QString("Value for '%1' not found. Using default (%2) instead.").arg(name).arg(*dest));
|
||||
}
|
||||
};
|
||||
loadDefine(numPalsTotalName, &Project::num_pals_total, 2, INT_MAX); // In reality the max would be 16, but as far as Porymap is concerned it doesn't matter.
|
||||
loadDefine(numPalsTotalName, &Project::num_pals_total, 2, Tileset::maxPalettes());
|
||||
loadDefine(numTilesTotalName, &Project::num_tiles_total, 2, 1024); // 1024 is fixed because we store tile IDs in a 10-bit field.
|
||||
loadDefine(numPalsPrimaryName, &Project::num_pals_primary, 1, Project::num_pals_total - 1);
|
||||
loadDefine(numTilesPrimaryName, &Project::num_tiles_primary, 1, Project::num_tiles_total - 1);
|
||||
|
|
@ -2361,12 +2414,11 @@ bool Project::readFieldmapProperties() {
|
|||
// We can determine whether triple-layer metatiles are in-use by reading this constant.
|
||||
// If the constant is missing (or is using a value other than 8 or 12) the user must tell
|
||||
// us whether they're using triple-layer metatiles under Project Settings.
|
||||
static const int numTilesPerLayer = 4;
|
||||
int numTilesPerMetatile = it.value();
|
||||
if (numTilesPerMetatile == 2 * numTilesPerLayer) {
|
||||
if (numTilesPerMetatile == 2 * Metatile::tilesPerLayer()) {
|
||||
projectConfig.tripleLayerMetatilesEnabled = false;
|
||||
this->disabledSettingsNames.insert(numTilesPerMetatileName);
|
||||
} else if (numTilesPerMetatile == 3 * numTilesPerLayer) {
|
||||
} else if (numTilesPerMetatile == 3 * Metatile::tilesPerLayer()) {
|
||||
projectConfig.tripleLayerMetatilesEnabled = true;
|
||||
this->disabledSettingsNames.insert(numTilesPerMetatileName);
|
||||
}
|
||||
|
|
@ -2423,6 +2475,7 @@ bool Project::readFieldmapMasks() {
|
|||
projectConfig.blockCollisionMask = blockMask;
|
||||
if (readBlockMask(elevationMaskName, &blockMask))
|
||||
projectConfig.blockElevationMask = blockMask;
|
||||
Block::setLayout();
|
||||
|
||||
// Read RSE metatile attribute masks
|
||||
auto it = defines.find(behaviorMaskName);
|
||||
|
|
@ -2602,7 +2655,10 @@ void Project::setRegionMapEntries(const QHash<QString, MapSectionEntry> &entries
|
|||
QHash<QString, MapSectionEntry> Project::getRegionMapEntries() const {
|
||||
QHash<QString, MapSectionEntry> entries;
|
||||
for (auto it = this->locationData.constBegin(); it != this->locationData.constEnd(); it++) {
|
||||
entries[it.key()] = it.value().map;
|
||||
const MapSectionEntry regionMapData = it.value().map;
|
||||
if (regionMapData.valid) {
|
||||
entries[it.key()] = regionMapData;
|
||||
}
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
|
@ -2928,13 +2984,19 @@ bool Project::readGlobalConstants() {
|
|||
bool Project::readEventScriptLabels() {
|
||||
this->globalScriptLabels.clear();
|
||||
|
||||
if (porymapConfig.loadAllEventScripts) {
|
||||
for (const auto &filePath : getEventScriptsFilepaths())
|
||||
this->globalScriptLabels << ParseUtil::getGlobalScriptLabels(filePath);
|
||||
|
||||
this->globalScriptLabels.sort(Qt::CaseInsensitive);
|
||||
this->globalScriptLabels.removeDuplicates();
|
||||
QStringList paths;
|
||||
if (porymapConfig.scriptAutocompleteMode == ScriptAutocompleteMode::All) {
|
||||
paths = getAllEventScriptsFilepaths();
|
||||
} else if (porymapConfig.scriptAutocompleteMode == ScriptAutocompleteMode::MapAndCommon) {
|
||||
paths = getCommonEventScriptsFilepaths();
|
||||
}
|
||||
|
||||
for (const auto &path : paths) {
|
||||
this->globalScriptLabels << ParseUtil::getGlobalScriptLabels(path);
|
||||
}
|
||||
this->globalScriptLabels.sort(Qt::CaseInsensitive);
|
||||
this->globalScriptLabels.removeDuplicates();
|
||||
|
||||
emit eventScriptLabelsRead();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -2970,30 +3032,46 @@ QString Project::getScriptDefaultString(bool usePoryScript, QString mapName) con
|
|||
return QString("%1_MapScripts::\n\t.byte 0\n").arg(mapName);
|
||||
}
|
||||
|
||||
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));
|
||||
QStringList Project::getAllEventScriptsFilepaths() const {
|
||||
return getMapScriptsFilepaths() + getCommonEventScriptsFilepaths();
|
||||
}
|
||||
|
||||
if (projectConfig.usePoryScript) {
|
||||
QDirIterator it_pory_shared(scriptsDir, {"*.pory"}, QDir::Files);
|
||||
while (it_pory_shared.hasNext())
|
||||
filePaths << it_pory_shared.next();
|
||||
// Get the paths for all "scripts.inc" / "scripts.pory" files in the data/maps/*/ folders.
|
||||
QStringList Project::getMapScriptsFilepaths() const {
|
||||
return findScriptsFiles(projectConfig.getFilePath(ProjectFilePath::data_map_folders), {"scripts"});
|
||||
}
|
||||
|
||||
QDirIterator it_pory_maps(mapsDir, {"scripts.pory"}, QDir::Files, QDirIterator::Subdirectories);
|
||||
while (it_pory_maps.hasNext())
|
||||
filePaths << it_pory_maps.next();
|
||||
// Get the paths for all "*.inc" / "*.pory" files in the data/scripts/ folder, + data/event_scripts.s.
|
||||
QStringList Project::getCommonEventScriptsFilepaths() const {
|
||||
QStringList paths = { QDir::cleanPath(this->root + "/" + projectConfig.getFilePath(ProjectFilePath::data_event_scripts)) };
|
||||
return paths + findScriptsFiles(projectConfig.getFilePath(ProjectFilePath::data_scripts_folders));
|
||||
}
|
||||
|
||||
QStringList Project::findScriptsFiles(const QString &searchDir, const QStringList &fileNames) const {
|
||||
QStringList paths;
|
||||
|
||||
QString dir = searchDir;
|
||||
if (!dir.startsWith(this->root)) {
|
||||
dir = QDir::cleanPath(this->root + "/" + dir);
|
||||
}
|
||||
|
||||
QDirIterator it_inc_shared(scriptsDir, {"*.inc"}, QDir::Files);
|
||||
while (it_inc_shared.hasNext())
|
||||
filePaths << it_inc_shared.next();
|
||||
QStringList filters;
|
||||
for (const auto &s : fileNames) {
|
||||
filters.append(s + getScriptFileExtension(false));
|
||||
if (projectConfig.usePoryScript) {
|
||||
filters.append(s + getScriptFileExtension(true));
|
||||
}
|
||||
}
|
||||
|
||||
QDirIterator it_inc_maps(mapsDir, {"scripts.inc"}, QDir::Files, QDirIterator::Subdirectories);
|
||||
while (it_inc_maps.hasNext())
|
||||
filePaths << it_inc_maps.next();
|
||||
|
||||
return filePaths;
|
||||
// TODO: Filter out .inc files that are generated by a .pory file.
|
||||
// They won't cause problems for the user, but it'll create extra parsing work later.
|
||||
if (!filters.isEmpty()) {
|
||||
QDirIterator it(dir, filters, QDir::Files, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
|
||||
while (it.hasNext()) {
|
||||
paths.append(it.next());
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
void Project::loadEventPixmap(Event *event, bool forceLoad) {
|
||||
|
|
@ -3380,14 +3458,25 @@ QString Project::getEmptySpeciesName() {
|
|||
return projectConfig.getIdentifier(ProjectIdentifier::define_species_prefix) + projectConfig.getIdentifier(ProjectIdentifier::define_species_empty);
|
||||
}
|
||||
|
||||
// Get the distance in metatiles (rounded up) that the player is able to see in each direction in-game.
|
||||
// Get the distance in pixels that the player is able to see in each direction in-game,
|
||||
// rounded up to a multiple of a metatile's pixel size.
|
||||
QMargins Project::getPixelViewDistance() {
|
||||
QMargins viewDistance = projectConfig.playerViewDistance;
|
||||
viewDistance.setTop(Util::roundUpToMultiple(viewDistance.top(), Metatile::pixelHeight()));
|
||||
viewDistance.setBottom(Util::roundUpToMultiple(viewDistance.bottom(), Metatile::pixelHeight()));
|
||||
viewDistance.setLeft(Util::roundUpToMultiple(viewDistance.left(), Metatile::pixelWidth()));
|
||||
viewDistance.setRight(Util::roundUpToMultiple(viewDistance.right(), Metatile::pixelWidth()));
|
||||
return viewDistance;
|
||||
}
|
||||
|
||||
// Get the distance in metatiles that the player is able to see in each direction in-game.
|
||||
// For the default view distance (i.e. assuming the player is centered in a 240x160 pixel GBA screen) this is 7x5 metatiles.
|
||||
QMargins Project::getMetatileViewDistance() {
|
||||
QMargins viewDistance = projectConfig.playerViewDistance;
|
||||
viewDistance.setTop(qCeil(viewDistance.top() / 16.0));
|
||||
viewDistance.setBottom(qCeil(viewDistance.bottom() / 16.0));
|
||||
viewDistance.setLeft(qCeil(viewDistance.left() / 16.0));
|
||||
viewDistance.setRight(qCeil(viewDistance.right() / 16.0));
|
||||
QMargins viewDistance = getPixelViewDistance();
|
||||
viewDistance.setTop(viewDistance.top() / Metatile::pixelHeight());
|
||||
viewDistance.setBottom(viewDistance.bottom() / Metatile::pixelHeight());
|
||||
viewDistance.setLeft(viewDistance.left() / Metatile::pixelWidth());
|
||||
viewDistance.setRight(viewDistance.right() / Metatile::pixelWidth());
|
||||
return viewDistance;
|
||||
}
|
||||
|
||||
|
|
@ -3417,15 +3506,14 @@ void Project::applyParsedLimits() {
|
|||
projectConfig.metatileEncounterTypeMask &= maxMask;
|
||||
projectConfig.metatileLayerTypeMask &= maxMask;
|
||||
|
||||
Block::setLayout();
|
||||
Metatile::setLayout(this);
|
||||
|
||||
Project::num_metatiles_primary = qMin(qMax(Project::num_metatiles_primary, 1), Block::getMaxMetatileId() + 1);
|
||||
Project::num_metatiles_primary = qBound(1, Project::num_metatiles_primary, Block::getMaxMetatileId() + 1);
|
||||
projectConfig.defaultMetatileId = qMin(projectConfig.defaultMetatileId, Block::getMaxMetatileId());
|
||||
projectConfig.defaultElevation = qMin(projectConfig.defaultElevation, Block::getMaxElevation());
|
||||
projectConfig.defaultCollision = qMin(projectConfig.defaultCollision, Block::getMaxCollision());
|
||||
projectConfig.collisionSheetSize.setHeight(qMin(qMax(projectConfig.collisionSheetSize.height(), 1), Block::getMaxElevation() + 1));
|
||||
projectConfig.collisionSheetSize.setWidth(qMin(qMax(projectConfig.collisionSheetSize.width(), 1), Block::getMaxCollision() + 1));
|
||||
projectConfig.collisionSheetSize.setHeight(qBound(1, projectConfig.collisionSheetSize.height(), Block::getMaxElevation() + 1));
|
||||
projectConfig.collisionSheetSize.setWidth(qBound(1, projectConfig.collisionSheetSize.width(), Block::getMaxCollision() + 1));
|
||||
}
|
||||
|
||||
bool Project::hasUnsavedChanges() {
|
||||
|
|
@ -3445,3 +3533,34 @@ bool Project::hasUnsavedChanges() {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Searches the project's map layouts to find the names of the tilesets that the provided tileset gets paired with.
|
||||
QSet<QString> Project::getPairedTilesetLabels(const Tileset *tileset) const {
|
||||
QSet<QString> pairedLabels;
|
||||
for (const auto &layout : this->mapLayouts) {
|
||||
if (tileset->is_secondary) {
|
||||
if (layout->tileset_secondary_label == tileset->name) {
|
||||
pairedLabels.insert(layout->tileset_primary_label);
|
||||
}
|
||||
} else if (layout->tileset_primary_label == tileset->name) {
|
||||
pairedLabels.insert(layout->tileset_secondary_label);
|
||||
}
|
||||
}
|
||||
return pairedLabels;
|
||||
}
|
||||
|
||||
// Returns the set of IDs for the layouts that use the specified tilesets.
|
||||
// nullptr for either tileset is treated as a wildcard (so 'getTilesetLayouts(nullptr, nullptr)' returns all layout IDs).
|
||||
QSet<QString> Project::getTilesetLayoutIds(const Tileset *primaryTileset, const Tileset *secondaryTileset) const {
|
||||
// Note: We're intentioanlly just returning the layout IDs, and not the pointer to the layout.
|
||||
// The layout may not be loaded yet (which isn't obvious), and we should leave it up to the caller to request that.
|
||||
QSet<QString> layoutIds;
|
||||
for (const auto &layout : this->mapLayouts) {
|
||||
if (primaryTileset && primaryTileset->name != layout->tileset_primary_label)
|
||||
continue;
|
||||
if (secondaryTileset && secondaryTileset->name != layout->tileset_secondary_label)
|
||||
continue;
|
||||
layoutIds.insert(layout->id);
|
||||
}
|
||||
return layoutIds;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
#ifdef QT_QML_LIB
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
#include "scripting.h"
|
||||
#include "editcommands.h"
|
||||
#include "config.h"
|
||||
#include "imageproviders.h"
|
||||
#include "scriptutility.h"
|
||||
|
||||
// TODO: "tilesetNeedsRedraw" is used when redrawing the map after
|
||||
// changing a metatile's tiles via script. It is unnecessarily
|
||||
|
|
@ -26,7 +28,7 @@ void MainWindow::tryRedrawMapArea(bool forceRedraw) {
|
|||
if (this->tilesetEditor)
|
||||
this->tilesetEditor->updateTilesets(this->editor->layout->tileset_primary_label, this->editor->layout->tileset_secondary_label);
|
||||
if (this->editor->metatile_selector_item)
|
||||
this->editor->metatile_selector_item->draw();
|
||||
this->editor->metatile_selector_item->refresh();
|
||||
if (this->editor->selected_border_metatiles_item)
|
||||
this->editor->selected_border_metatiles_item->draw();
|
||||
if (this->editor->current_metatile_selection_item)
|
||||
|
|
@ -40,6 +42,17 @@ void MainWindow::tryRedrawMapArea(bool forceRedraw) {
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::redrawResizedMapArea() {
|
||||
// We're calling this on a timer because we want to defer the redraw
|
||||
// until it's time to process events. This avoids some potential crashes,
|
||||
// as redrawMapScene will destroy a handful of objects capable of triggering
|
||||
// script API callbacks; we want to let them finish what they were doing
|
||||
// before we destroying them.
|
||||
// NOTE: This has the same problem as ScriptEditLayout, namely that it's
|
||||
// doing more work than necessary and can be prohibitively slow.
|
||||
QTimer::singleShot(0, this, &MainWindow::redrawMapScene);
|
||||
}
|
||||
|
||||
void MainWindow::tryCommitMapChanges(bool commitChanges) {
|
||||
if (commitChanges) {
|
||||
Layout *layout = this->editor->layout;
|
||||
|
|
@ -95,21 +108,15 @@ void MainWindow::setBlocksFromSelection(int x, int y, bool forceRedraw, bool com
|
|||
int MainWindow::getMetatileId(int x, int y) {
|
||||
if (!this->editor || !this->editor->layout)
|
||||
return 0;
|
||||
Block block;
|
||||
if (!this->editor->layout->getBlock(x, y, &block)) {
|
||||
return 0;
|
||||
}
|
||||
return block.metatileId();
|
||||
return this->editor->layout->getMetatileId(x, y);
|
||||
}
|
||||
|
||||
void MainWindow::setMetatileId(int x, int y, int metatileId, bool forceRedraw, bool commitChanges) {
|
||||
if (!this->editor || !this->editor->layout)
|
||||
return;
|
||||
Block block;
|
||||
if (!this->editor->layout->getBlock(x, y, &block)) {
|
||||
if (!this->editor->layout->setMetatileId(x, y, metatileId)) {
|
||||
return;
|
||||
}
|
||||
this->editor->layout->setBlock(x, y, Block(metatileId, block.collision(), block.elevation()));
|
||||
this->tryCommitMapChanges(commitChanges);
|
||||
this->tryRedrawMapArea(forceRedraw);
|
||||
}
|
||||
|
|
@ -231,7 +238,7 @@ void MainWindow::setDimensions(int width, int height) {
|
|||
return;
|
||||
this->editor->layout->setDimensions(width, height);
|
||||
this->tryCommitMapChanges(true);
|
||||
this->redrawMapScene();
|
||||
this->redrawResizedMapArea();
|
||||
}
|
||||
|
||||
void MainWindow::setWidth(int width) {
|
||||
|
|
@ -241,7 +248,7 @@ void MainWindow::setWidth(int width) {
|
|||
return;
|
||||
this->editor->layout->setDimensions(width, this->editor->layout->getHeight());
|
||||
this->tryCommitMapChanges(true);
|
||||
this->redrawMapScene();
|
||||
this->redrawResizedMapArea();
|
||||
}
|
||||
|
||||
void MainWindow::setHeight(int height) {
|
||||
|
|
@ -251,7 +258,7 @@ void MainWindow::setHeight(int height) {
|
|||
return;
|
||||
this->editor->layout->setDimensions(this->editor->layout->getWidth(), height);
|
||||
this->tryCommitMapChanges(true);
|
||||
this->redrawMapScene();
|
||||
this->redrawResizedMapArea();
|
||||
}
|
||||
|
||||
//=====================
|
||||
|
|
@ -301,7 +308,7 @@ void MainWindow::setBorderDimensions(int width, int height) {
|
|||
return;
|
||||
this->editor->layout->setBorderDimensions(width, height);
|
||||
this->tryCommitMapChanges(true);
|
||||
this->redrawMapScene();
|
||||
this->redrawResizedMapArea();
|
||||
}
|
||||
|
||||
void MainWindow::setBorderWidth(int width) {
|
||||
|
|
@ -311,7 +318,7 @@ void MainWindow::setBorderWidth(int width) {
|
|||
return;
|
||||
this->editor->layout->setBorderDimensions(width, this->editor->layout->getBorderHeight());
|
||||
this->tryCommitMapChanges(true);
|
||||
this->redrawMapScene();
|
||||
this->redrawResizedMapArea();
|
||||
}
|
||||
|
||||
void MainWindow::setBorderHeight(int height) {
|
||||
|
|
@ -321,7 +328,7 @@ void MainWindow::setBorderHeight(int height) {
|
|||
return;
|
||||
this->editor->layout->setBorderDimensions(this->editor->layout->getBorderWidth(), height);
|
||||
this->tryCommitMapChanges(true);
|
||||
this->redrawMapScene();
|
||||
this->redrawResizedMapArea();
|
||||
}
|
||||
|
||||
//======================
|
||||
|
|
@ -332,7 +339,7 @@ void MainWindow::refreshAfterPaletteChange(Tileset *tileset) {
|
|||
if (this->tilesetEditor) {
|
||||
this->tilesetEditor->updateTilesets(this->editor->layout->tileset_primary_label, this->editor->layout->tileset_secondary_label);
|
||||
}
|
||||
this->editor->metatile_selector_item->draw();
|
||||
this->editor->metatile_selector_item->refresh();
|
||||
this->editor->selected_border_metatiles_item->draw();
|
||||
this->editor->map_item->draw(true);
|
||||
this->editor->updateMapBorder();
|
||||
|
|
@ -345,10 +352,7 @@ void MainWindow::setTilesetPalette(Tileset *tileset, int paletteIndex, QList<QLi
|
|||
return;
|
||||
if (paletteIndex >= tileset->palettes.size())
|
||||
return;
|
||||
if (colors.size() != 16)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int i = 0; i < qMin(colors.length(), Tileset::numColorsPerPalette()); i++) {
|
||||
if (colors[i].size() != 3)
|
||||
continue;
|
||||
tileset->palettes[paletteIndex][i] = qRgb(colors[i][0], colors[i][1], colors[i][2]);
|
||||
|
|
@ -444,7 +448,7 @@ QJSValue MainWindow::getSecondaryTilesetPalettes() {
|
|||
}
|
||||
|
||||
void MainWindow::refreshAfterPalettePreviewChange() {
|
||||
this->editor->metatile_selector_item->draw();
|
||||
this->editor->metatile_selector_item->refresh();
|
||||
this->editor->selected_border_metatiles_item->draw();
|
||||
this->editor->map_item->draw(true);
|
||||
this->editor->updateMapBorder();
|
||||
|
|
@ -456,10 +460,7 @@ void MainWindow::setTilesetPalettePreview(Tileset *tileset, int paletteIndex, QL
|
|||
return;
|
||||
if (paletteIndex >= tileset->palettePreviews.size())
|
||||
return;
|
||||
if (colors.size() != 16)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int i = 0; i < qMin(colors.length(), Tileset::numColorsPerPalette()); i++) {
|
||||
if (colors[i].size() != 3)
|
||||
continue;
|
||||
tileset->palettePreviews[paletteIndex][i] = qRgb(colors[i][0], colors[i][1], colors[i][2]);
|
||||
|
|
@ -545,13 +546,13 @@ int MainWindow::getNumSecondaryTilesetMetatiles() {
|
|||
int MainWindow::getNumPrimaryTilesetTiles() {
|
||||
if (!this->editor || !this->editor->layout || !this->editor->layout->tileset_primary)
|
||||
return 0;
|
||||
return this->editor->layout->tileset_primary->tiles.length();
|
||||
return this->editor->layout->tileset_primary->numTiles();
|
||||
}
|
||||
|
||||
int MainWindow::getNumSecondaryTilesetTiles() {
|
||||
if (!this->editor || !this->editor->layout || !this->editor->layout->tileset_secondary)
|
||||
return 0;
|
||||
return this->editor->layout->tileset_secondary->tiles.length();
|
||||
return this->editor->layout->tileset_secondary->numTiles();
|
||||
}
|
||||
|
||||
QString MainWindow::getPrimaryTileset() {
|
||||
|
|
@ -566,14 +567,6 @@ QString MainWindow::getSecondaryTileset() {
|
|||
return this->editor->layout->tileset_secondary->name;
|
||||
}
|
||||
|
||||
void MainWindow::setPrimaryTileset(QString tileset) {
|
||||
this->on_comboBox_PrimaryTileset_currentTextChanged(tileset);
|
||||
}
|
||||
|
||||
void MainWindow::setSecondaryTileset(QString tileset) {
|
||||
this->on_comboBox_SecondaryTileset_currentTextChanged(tileset);
|
||||
}
|
||||
|
||||
void MainWindow::saveMetatilesByMetatileId(int metatileId) {
|
||||
Tileset * tileset = Tileset::getMetatileTileset(metatileId, this->editor->layout->tileset_primary, this->editor->layout->tileset_secondary);
|
||||
if (tileset)
|
||||
|
|
@ -796,17 +789,45 @@ void MainWindow::setMetatileTile(int metatileId, int tileIndex, QJSValue tileObj
|
|||
QJSValue MainWindow::getTilePixels(int tileId) {
|
||||
if (tileId < 0 || !this->editor || !this->editor->layout)
|
||||
return QJSValue();
|
||||
|
||||
QImage tileImage = getTileImage(tileId, this->editor->layout->tileset_primary, this->editor->layout->tileset_secondary);
|
||||
if (tileImage.isNull() || tileImage.sizeInBytes() < 64)
|
||||
if (tileImage.isNull() || tileImage.sizeInBytes() < Tile::numPixels())
|
||||
return QJSValue();
|
||||
|
||||
const uchar * pixels = tileImage.constBits();
|
||||
QJSValue pixelArray = Scripting::getEngine()->newArray(64);
|
||||
for (int i = 0; i < 64; i++) {
|
||||
QJSValue pixelArray = Scripting::getEngine()->newArray(Tile::numPixels());
|
||||
for (int i = 0; i < Tile::numPixels(); i++) {
|
||||
pixelArray.setProperty(i, pixels[i]);
|
||||
}
|
||||
return pixelArray;
|
||||
}
|
||||
|
||||
QList<int> MainWindow::getMetatileLayerOrder() const {
|
||||
if (!this->editor || !this->editor->layout)
|
||||
return QList<int>();
|
||||
return this->editor->layout->metatileLayerOrder();
|
||||
}
|
||||
|
||||
void MainWindow::setMetatileLayerOrder(const QList<int> &order) {
|
||||
if (!this->editor || !this->editor->layout || !ScriptUtility::validateMetatileLayerOrder(order))
|
||||
return;
|
||||
this->editor->layout->setMetatileLayerOrder(order);
|
||||
this->refreshAfterPalettePreviewChange();
|
||||
}
|
||||
|
||||
QList<float> MainWindow::getMetatileLayerOpacity() const {
|
||||
if (!this->editor || !this->editor->layout)
|
||||
return QList<float>();
|
||||
return this->editor->layout->metatileLayerOpacity();
|
||||
}
|
||||
|
||||
void MainWindow::setMetatileLayerOpacity(const QList<float> &opacities) {
|
||||
if (!this->editor || !this->editor->layout)
|
||||
return;
|
||||
this->editor->layout->setMetatileLayerOpacity(opacities);
|
||||
this->refreshAfterPalettePreviewChange();
|
||||
}
|
||||
|
||||
//=====================
|
||||
// Editing map header
|
||||
//=====================
|
||||
|
|
@ -943,3 +964,5 @@ void MainWindow::setFloorNumber(int floorNumber) {
|
|||
this->editor->map->header()->setFloorNumber(floorNumber);
|
||||
}
|
||||
|
||||
|
||||
#endif // QT_QML_LIB
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#ifdef QT_QML_LIB
|
||||
#include "mapview.h"
|
||||
#include "scripting.h"
|
||||
#include "imageproviders.h"
|
||||
#include "editor.h"
|
||||
|
||||
void MapView::updateScene() {
|
||||
if (this->scene()) {
|
||||
|
|
@ -294,13 +296,11 @@ void MapView::addTileImage(int x, int y, const Tile &tile, bool setTransparency,
|
|||
void MapView::addMetatileImage(int x, int y, int metatileId, bool setTransparency, int layer) {
|
||||
if (!this->editor || !this->editor->layout || !this->editor->layout->tileset_primary || !this->editor->layout->tileset_secondary)
|
||||
return;
|
||||
QImage image = getMetatileImage(static_cast<uint16_t>(metatileId),
|
||||
this->editor->layout->tileset_primary,
|
||||
this->editor->layout->tileset_secondary,
|
||||
this->editor->layout->metatileLayerOrder,
|
||||
this->editor->layout->metatileLayerOpacity);
|
||||
QImage image = getMetatileImage(static_cast<uint16_t>(metatileId), this->editor->layout);
|
||||
if (setTransparency)
|
||||
image.setColor(0, qRgba(0, 0, 0, 0));
|
||||
if (this->getOverlay(layer)->addImage(x, y, image))
|
||||
this->updateScene();
|
||||
}
|
||||
|
||||
#endif // QT_QML_LIB
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
#ifdef QT_QML_LIB
|
||||
#include "scriptutility.h"
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
#include "scripting.h"
|
||||
#include "config.h"
|
||||
|
||||
ScriptUtility::ScriptUtility(MainWindow *mainWindow) {
|
||||
this->window = mainWindow;
|
||||
}
|
||||
|
||||
ScriptUtility::~ScriptUtility() {
|
||||
if (window && window->ui && window->ui->menuTools) {
|
||||
for (auto action : this->registeredActions) {
|
||||
|
|
@ -201,46 +199,36 @@ QList<QString> ScriptUtility::getCustomScripts() {
|
|||
}
|
||||
|
||||
QList<int> ScriptUtility::getMetatileLayerOrder() {
|
||||
if (!window || !window->editor || !window->editor->layout)
|
||||
return QList<int>();
|
||||
return window->editor->layout->metatileLayerOrder;
|
||||
return Layout::globalMetatileLayerOrder();
|
||||
}
|
||||
|
||||
void ScriptUtility::setMetatileLayerOrder(QList<int> order) {
|
||||
if (!window || !window->editor || !window->editor->layout)
|
||||
return;
|
||||
|
||||
bool ScriptUtility::validateMetatileLayerOrder(const QList<int> &order) {
|
||||
const int numLayers = 3;
|
||||
int size = order.size();
|
||||
if (size < numLayers) {
|
||||
logError(QString("Metatile layer order has insufficient elements (%1), needs at least %2.").arg(size).arg(numLayers));
|
||||
return;
|
||||
}
|
||||
bool invalid = false;
|
||||
for (int i = 0; i < numLayers; i++) {
|
||||
bool valid = true;
|
||||
for (int i = 0; i < qMin(order.length(), numLayers); i++) {
|
||||
int layer = order.at(i);
|
||||
if (layer < 0 || layer >= numLayers) {
|
||||
logError(QString("'%1' is not a valid metatile layer order value, must be in range 0-%2.").arg(layer).arg(numLayers - 1));
|
||||
invalid = true;
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
if (invalid) return;
|
||||
return valid;
|
||||
}
|
||||
|
||||
window->editor->layout->metatileLayerOrder = order;
|
||||
window->refreshAfterPalettePreviewChange();
|
||||
void ScriptUtility::setMetatileLayerOrder(const QList<int> &order) {
|
||||
if (!validateMetatileLayerOrder(order))
|
||||
return;
|
||||
Layout::setGlobalMetatileLayerOrder(order);
|
||||
if (window) window->refreshAfterPalettePreviewChange();
|
||||
}
|
||||
|
||||
QList<float> ScriptUtility::getMetatileLayerOpacity() {
|
||||
if (!window || !window->editor || !window->editor->layout)
|
||||
return QList<float>();
|
||||
return window->editor->layout->metatileLayerOpacity;
|
||||
return Layout::globalMetatileLayerOpacity();
|
||||
}
|
||||
|
||||
void ScriptUtility::setMetatileLayerOpacity(QList<float> order) {
|
||||
if (!window || !window->editor || !window->editor->layout)
|
||||
return;
|
||||
window->editor->layout->metatileLayerOpacity = order;
|
||||
window->refreshAfterPalettePreviewChange();
|
||||
void ScriptUtility::setMetatileLayerOpacity(const QList<float> &opacities) {
|
||||
Layout::setGlobalMetatileLayerOpacity(opacities);
|
||||
if (window) window->refreshAfterPalettePreviewChange();
|
||||
}
|
||||
|
||||
QList<QString> ScriptUtility::getMapNames() {
|
||||
|
|
@ -328,3 +316,5 @@ bool ScriptUtility::isPrimaryTileset(QString tilesetName) {
|
|||
bool ScriptUtility::isSecondaryTileset(QString tilesetName) {
|
||||
return getSecondaryTilesetNames().contains(tilesetName);
|
||||
}
|
||||
|
||||
#endif // QT_QML_LIB
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
#if __has_include(<QQmlEngine>)
|
||||
#include <QQmlEngine>
|
||||
|
||||
#include "scripting.h"
|
||||
#include "log.h"
|
||||
#include "config.h"
|
||||
#include "mainwindow.h"
|
||||
|
||||
const QMap<CallbackType, QString> callbackFunctions = {
|
||||
{OnProjectOpened, "onProjectOpened"},
|
||||
|
|
@ -41,7 +43,7 @@ Scripting::Scripting(MainWindow *mainWindow) {
|
|||
const QStringList paths = userConfig.getCustomScriptPaths();
|
||||
const QList<bool> enabled = userConfig.getCustomScriptsEnabled();
|
||||
for (int i = 0; i < paths.length(); i++) {
|
||||
if (enabled.at(i))
|
||||
if (enabled.value(i, true))
|
||||
this->filepaths.append(paths.at(i));
|
||||
}
|
||||
this->loadModules(this->filepaths);
|
||||
|
|
@ -99,15 +101,12 @@ void Scripting::populateGlobalObject(MainWindow *mainWindow) {
|
|||
constants.setProperty("version", version);
|
||||
|
||||
// Get basic tileset information
|
||||
int numTilesPrimary = Project::getNumTilesPrimary();
|
||||
int numMetatilesPrimary = Project::getNumMetatilesPrimary();
|
||||
int numPalettesPrimary = Project::getNumPalettesPrimary();
|
||||
constants.setProperty("max_primary_tiles", numTilesPrimary);
|
||||
constants.setProperty("max_secondary_tiles", Project::getNumTilesTotal() - numTilesPrimary);
|
||||
constants.setProperty("max_primary_metatiles", numMetatilesPrimary);
|
||||
constants.setProperty("max_secondary_metatiles", Project::getNumMetatilesTotal() - numMetatilesPrimary);
|
||||
constants.setProperty("num_primary_palettes", numPalettesPrimary);
|
||||
constants.setProperty("num_secondary_palettes", Project::getNumPalettesTotal() - numPalettesPrimary);
|
||||
constants.setProperty("max_primary_tiles", Project::getNumTilesPrimary());
|
||||
constants.setProperty("max_secondary_tiles", Project::getNumTilesSecondary());
|
||||
constants.setProperty("max_primary_metatiles", Project::getNumMetatilesPrimary());
|
||||
constants.setProperty("max_secondary_metatiles", Project::getNumMetatilesSecondary());
|
||||
constants.setProperty("num_primary_palettes", Project::getNumPalettesPrimary());
|
||||
constants.setProperty("num_secondary_palettes", Project::getNumPalettesSecondary());
|
||||
constants.setProperty("layers_per_metatile", projectConfig.getNumLayersInMetatile());
|
||||
constants.setProperty("tiles_per_metatile", projectConfig.getNumTilesInMetatile());
|
||||
|
||||
|
|
@ -301,7 +300,7 @@ void Scripting::cb_MapShifted(int xDelta, int yDelta) {
|
|||
instance->invokeCallback(OnMapShifted, args);
|
||||
}
|
||||
|
||||
void Scripting::cb_TilesetUpdated(QString tilesetName) {
|
||||
void Scripting::cb_TilesetUpdated(const QString &tilesetName) {
|
||||
if (!instance) return;
|
||||
|
||||
QJSValueList args {
|
||||
|
|
@ -425,3 +424,6 @@ const QImage * Scripting::getImage(const QString &inputFilepath, bool useCache)
|
|||
instance->imageCache.insert(inputFilepath, image);
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
#endif // __has_include(<QQmlEngine>)
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ void BorderMetatilesPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
|||
|
||||
Blockdata oldBorder = layout->border;
|
||||
|
||||
for (int i = 0; i < selection.dimensions.x() && (i + pos.x()) < width; i++) {
|
||||
for (int j = 0; j < selection.dimensions.y() && (j + pos.y()) < height; j++) {
|
||||
MetatileSelectionItem item = selection.metatileItems.at(j * selection.dimensions.x() + i);
|
||||
for (int i = 0; i < selection.dimensions.width() && (i + pos.x()) < width; i++) {
|
||||
for (int j = 0; j < selection.dimensions.height() && (j + pos.y()) < height; j++) {
|
||||
MetatileSelectionItem item = selection.metatileItems.value(j * selection.dimensions.width() + i);
|
||||
layout->setBorderMetatileId(pos.x() + i, pos.y() + j, item.metatileId, true);
|
||||
}
|
||||
}
|
||||
|
|
@ -39,21 +39,15 @@ void BorderMetatilesPixmapItem::draw() {
|
|||
|
||||
int width = layout->getBorderWidth();
|
||||
int height = layout->getBorderHeight();
|
||||
QImage image(16 * width, 16 * height, QImage::Format_RGBA8888);
|
||||
QImage image(width * Metatile::pixelWidth(), height * Metatile::pixelHeight(), QImage::Format_RGBA8888);
|
||||
QPainter painter(&image);
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
for (int j = 0; j < height; j++) {
|
||||
int x = i * 16;
|
||||
int y = j * 16;
|
||||
QImage metatile_image = getMetatileImage(
|
||||
layout->getBorderMetatileId(i, j),
|
||||
layout->tileset_primary,
|
||||
layout->tileset_secondary,
|
||||
layout->metatileLayerOrder,
|
||||
layout->metatileLayerOpacity);
|
||||
QPoint metatile_origin = QPoint(x, y);
|
||||
painter.drawImage(metatile_origin, metatile_image);
|
||||
QImage metatile_image = getMetatileImage(layout->getBorderMetatileId(i, j), layout);
|
||||
int x = i * Metatile::pixelWidth();
|
||||
int y = j * Metatile::pixelHeight();
|
||||
painter.drawImage(x, y, metatile_image);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
32
src/ui/checkeredbgscene.cpp
Normal file
32
src/ui/checkeredbgscene.cpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#include "checkeredbgscene.h"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
void CheckeredBgScene::drawBackground(QPainter *painter, const QRectF &rect) {
|
||||
QRect r = rect.toRect();
|
||||
int w = this->gridSize.width();
|
||||
int h = this->gridSize.height();
|
||||
int xMin = r.left() - (r.left() % w) - w;
|
||||
int yMin = r.top() - (r.top() % h) - h;
|
||||
int xMax = r.right() - (r.right() % w) + w;
|
||||
int yMax = r.bottom() - (r.bottom() % h) + h;
|
||||
|
||||
// draw grid from top to bottom of scene
|
||||
QColor paintColor;
|
||||
for (int x = xMin; x <= xMax; x += w) {
|
||||
for (int y = yMin; y <= yMax; y += h) {
|
||||
if ((x/w + y/h) % 2) {
|
||||
if (this->validRect.contains(x, y))
|
||||
paintColor = QColor(132, 217, 165); // green light color
|
||||
else
|
||||
paintColor = 0xbcbcbc; // normal light color
|
||||
} else {
|
||||
if (this->validRect.contains(x, y))
|
||||
paintColor = QColor(76, 178, 121); // green dark color
|
||||
else
|
||||
paintColor = 0x969696; // normal dark color
|
||||
}
|
||||
painter->fillRect(QRect(x, y, w, h), paintColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,52 +2,6 @@
|
|||
#include "editcommands.h"
|
||||
#include "metatile.h"
|
||||
|
||||
void CollisionPixmapItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
|
||||
QPoint pos = Metatile::coordFromPixmapCoord(event->pos());
|
||||
if (pos != this->previousPos) {
|
||||
this->previousPos = pos;
|
||||
emit this->hoveredMapMovementPermissionChanged(pos.x(), pos.y());
|
||||
}
|
||||
if (this->settings->betterCursors && this->getEditsEnabled()) {
|
||||
setCursor(this->settings->mapCursor);
|
||||
}
|
||||
}
|
||||
|
||||
void CollisionPixmapItem::hoverEnterEvent(QGraphicsSceneHoverEvent * event) {
|
||||
this->has_mouse = true;
|
||||
QPoint pos = Metatile::coordFromPixmapCoord(event->pos());
|
||||
emit this->hoveredMapMovementPermissionChanged(pos.x(), pos.y());
|
||||
}
|
||||
|
||||
void CollisionPixmapItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *) {
|
||||
emit this->hoveredMapMovementPermissionCleared();
|
||||
if (this->settings->betterCursors && this->getEditsEnabled()){
|
||||
unsetCursor();
|
||||
}
|
||||
this->has_mouse = false;
|
||||
}
|
||||
|
||||
void CollisionPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
|
||||
QPoint pos = Metatile::coordFromPixmapCoord(event->pos());
|
||||
this->paint_tile_initial_x = this->straight_path_initial_x = pos.x();
|
||||
this->paint_tile_initial_y = this->straight_path_initial_y = pos.y();
|
||||
emit mouseEvent(event, this);
|
||||
}
|
||||
|
||||
void CollisionPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
|
||||
QPoint pos = Metatile::coordFromPixmapCoord(event->pos());
|
||||
if (pos != this->previousPos) {
|
||||
this->previousPos = pos;
|
||||
emit this->hoveredMapMovementPermissionChanged(pos.x(), pos.y());
|
||||
}
|
||||
emit mouseEvent(event, this);
|
||||
}
|
||||
|
||||
void CollisionPixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
|
||||
this->lockedAxis = CollisionPixmapItem::Axis::None;
|
||||
emit mouseEvent(event, this);
|
||||
}
|
||||
|
||||
void CollisionPixmapItem::draw(bool ignoreCache) {
|
||||
if (this->layout) {
|
||||
this->layout->setCollisionItem(this);
|
||||
|
|
|
|||
|
|
@ -100,9 +100,9 @@ void ConnectionPixmapItem::updatePos() {
|
|||
void ConnectionPixmapItem::updateOrigin() {
|
||||
if (this->connection->isVertical()) {
|
||||
this->originX = 0;
|
||||
this->originY = this->connection->relativePos(true).y() * this->mHeight;
|
||||
this->originY = this->connection->relativePixelPos(true).y();
|
||||
} else if (this->connection->isHorizontal()) {
|
||||
this->originX = this->connection->relativePos(true).x() * this->mWidth;
|
||||
this->originX = this->connection->relativePixelPos(true).x();
|
||||
this->originY = 0;
|
||||
}
|
||||
updatePos();
|
||||
|
|
@ -126,7 +126,11 @@ void ConnectionPixmapItem::setSelected(bool selected) {
|
|||
emit selectionChanged(selected);
|
||||
}
|
||||
|
||||
void ConnectionPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *) {
|
||||
void ConnectionPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
|
||||
if (!this->getEditable()) {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
this->setSelected(true);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,26 +3,21 @@
|
|||
#include <QPainter>
|
||||
|
||||
QPixmap drawMetatileSelection(MetatileSelection selection, Layout *layout) {
|
||||
int width = selection.dimensions.x() * 16;
|
||||
int height = selection.dimensions.y() * 16;
|
||||
int width = selection.dimensions.width() * Metatile::pixelWidth();
|
||||
int height = selection.dimensions.height() * Metatile::pixelHeight();
|
||||
QImage image(width, height, QImage::Format_RGBA8888);
|
||||
image.fill(QColor(0, 0, 0, 0));
|
||||
QPainter painter(&image);
|
||||
|
||||
for (int i = 0; i < selection.dimensions.x(); i++) {
|
||||
for (int j = 0; j < selection.dimensions.y(); j++) {
|
||||
int x = i * 16;
|
||||
int y = j * 16;
|
||||
for (int i = 0; i < selection.dimensions.width(); i++) {
|
||||
for (int j = 0; j < selection.dimensions.height(); j++) {
|
||||
int x = i * Metatile::pixelWidth();
|
||||
int y = j * Metatile::pixelHeight();
|
||||
QPoint metatile_origin = QPoint(x, y);
|
||||
int index = j * selection.dimensions.x() + i;
|
||||
MetatileSelectionItem item = selection.metatileItems.at(index);
|
||||
int index = j * selection.dimensions.width() + i;
|
||||
MetatileSelectionItem item = selection.metatileItems.value(index);
|
||||
if (item.enabled) {
|
||||
QImage metatile_image = getMetatileImage(
|
||||
item.metatileId,
|
||||
layout->tileset_primary,
|
||||
layout->tileset_secondary,
|
||||
layout->metatileLayerOrder,
|
||||
layout->metatileLayerOpacity);
|
||||
QImage metatile_image = getMetatileImage(item.metatileId, layout);
|
||||
painter.drawImage(metatile_origin, metatile_image);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,94 +1,71 @@
|
|||
#include "cursortilerect.h"
|
||||
#include "layoutpixmapitem.h"
|
||||
#include "log.h"
|
||||
|
||||
CursorTileRect::CursorTileRect(bool *enabled, QRgb color)
|
||||
{
|
||||
this->enabled = enabled;
|
||||
this->active = true;
|
||||
this->color = color;
|
||||
this->width = 16;
|
||||
this->height = 16;
|
||||
this->smartPathMode = false;
|
||||
this->straightPathMode = false;
|
||||
this->singleTileMode = false;
|
||||
this->anchored = false;
|
||||
this->rightClickSelectionAnchored = false;
|
||||
this->anchorCoordX = 0;
|
||||
this->anchorCoordY = 0;
|
||||
this->selectionWidth = 1;
|
||||
this->selectionHeight = 1;
|
||||
CursorTileRect::CursorTileRect(const QSize &tileSize, const QRgb &color, QGraphicsItem *parent)
|
||||
: QGraphicsItem(parent),
|
||||
m_tileSize(tileSize),
|
||||
m_selectionSize(QSize(1,1)),
|
||||
m_anchorCoord(QPoint(0,0)),
|
||||
m_color(color)
|
||||
{ }
|
||||
|
||||
// Size of the cursor may be explicitly enforced depending on settings.
|
||||
QSize CursorTileRect::size() const {
|
||||
if (m_singleTileMode)
|
||||
return m_tileSize;
|
||||
|
||||
if (smartPathInEffect())
|
||||
return m_tileSize * 2;
|
||||
|
||||
return QSize(m_tileSize.width() * m_selectionSize.width(),
|
||||
m_tileSize.height() * m_selectionSize.height());
|
||||
}
|
||||
|
||||
void CursorTileRect::setActive(bool active)
|
||||
{
|
||||
this->active = active;
|
||||
void CursorTileRect::initAnchor(int coordX, int coordY) {
|
||||
m_anchorCoord = QPoint(coordX, coordY);
|
||||
m_anchored = true;
|
||||
}
|
||||
|
||||
bool CursorTileRect::getActive()
|
||||
{
|
||||
return active;
|
||||
void CursorTileRect::stopAnchor() {
|
||||
m_anchored = false;
|
||||
}
|
||||
|
||||
void CursorTileRect::initAnchor(int coordX, int coordY)
|
||||
{
|
||||
this->anchorCoordX = coordX;
|
||||
this->anchorCoordY = coordY;
|
||||
this->anchored = true;
|
||||
void CursorTileRect::initRightClickSelectionAnchor(int coordX, int coordY) {
|
||||
m_anchorCoord = QPoint(coordX, coordY);
|
||||
m_rightClickSelectionAnchored = true;
|
||||
}
|
||||
|
||||
void CursorTileRect::stopAnchor()
|
||||
{
|
||||
this->anchored = false;
|
||||
void CursorTileRect::stopRightClickSelectionAnchor() {
|
||||
m_rightClickSelectionAnchored = false;
|
||||
}
|
||||
|
||||
void CursorTileRect::initRightClickSelectionAnchor(int coordX, int coordY)
|
||||
{
|
||||
this->anchorCoordX = coordX;
|
||||
this->anchorCoordY = coordY;
|
||||
this->rightClickSelectionAnchored = true;
|
||||
void CursorTileRect::updateSelectionSize(const QSize &size) {
|
||||
m_selectionSize = size.expandedTo(QSize(1,1)); // Enforce minimum of 1x1 cell
|
||||
prepareGeometryChange();
|
||||
update();
|
||||
}
|
||||
|
||||
void CursorTileRect::stopRightClickSelectionAnchor()
|
||||
{
|
||||
this->rightClickSelectionAnchored = false;
|
||||
bool CursorTileRect::smartPathInEffect() const {
|
||||
return !m_rightClickSelectionAnchored && m_smartPathMode && LayoutPixmapItem::isSmartPathSize(m_selectionSize);
|
||||
}
|
||||
|
||||
void CursorTileRect::updateSelectionSize(int width, int height)
|
||||
{
|
||||
this->selectionWidth = width;
|
||||
this->selectionHeight = height;
|
||||
this->width = width * 16;
|
||||
this->height = height * 16;
|
||||
this->prepareGeometryChange();
|
||||
this->update();
|
||||
}
|
||||
void CursorTileRect::updateLocation(int coordX, int coordY) {
|
||||
if (!m_singleTileMode) {
|
||||
if (m_rightClickSelectionAnchored) {
|
||||
coordX = qMin(coordX, m_anchorCoord.x());
|
||||
coordY = qMin(coordY, m_anchorCoord.y());
|
||||
} else if (m_anchored && !smartPathInEffect()) {
|
||||
int xDiff = coordX - m_anchorCoord.x();
|
||||
int yDiff = coordY - m_anchorCoord.y();
|
||||
if (xDiff < 0 && xDiff % m_selectionSize.width() != 0) xDiff -= m_selectionSize.width();
|
||||
if (yDiff < 0 && yDiff % m_selectionSize.height() != 0) yDiff -= m_selectionSize.height();
|
||||
|
||||
bool CursorTileRect::smartPathInEffect()
|
||||
{
|
||||
return !this->rightClickSelectionAnchored && this->smartPathMode && this->selectionHeight == 3 && this->selectionWidth == 3;
|
||||
}
|
||||
|
||||
void CursorTileRect::updateLocation(int coordX, int coordY)
|
||||
{
|
||||
if (!this->singleTileMode) {
|
||||
if (this->rightClickSelectionAnchored) {
|
||||
coordX = qMin(coordX, this->anchorCoordX);
|
||||
coordY = qMin(coordY, this->anchorCoordY);
|
||||
}
|
||||
else if (this->anchored && !this->smartPathInEffect()) {
|
||||
int xDiff = coordX - this->anchorCoordX;
|
||||
int yDiff = coordY - this->anchorCoordY;
|
||||
if (xDiff < 0 && xDiff % this->selectionWidth != 0) xDiff -= this->selectionWidth;
|
||||
if (yDiff < 0 && yDiff % this->selectionHeight != 0) yDiff -= this->selectionHeight;
|
||||
|
||||
coordX = this->anchorCoordX + (xDiff / this->selectionWidth) * this->selectionWidth;
|
||||
coordY = this->anchorCoordY + (yDiff / this->selectionHeight) * this->selectionHeight;
|
||||
coordX = m_anchorCoord.x() + (xDiff / m_selectionSize.width()) * m_selectionSize.width();
|
||||
coordY = m_anchorCoord.y() + (yDiff / m_selectionSize.height()) * m_selectionSize.height();
|
||||
}
|
||||
}
|
||||
|
||||
coordX = qMax(coordX, 0);
|
||||
coordY = qMax(coordY, 0);
|
||||
this->setX(coordX * 16);
|
||||
this->setY(coordY * 16);
|
||||
this->setVisible(*this->enabled && this->active);
|
||||
this->setX(coordX * m_tileSize.width());
|
||||
this->setY(coordY * m_tileSize.height());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ CustomScriptsEditor::CustomScriptsEditor(QWidget *parent) :
|
|||
const QStringList paths = userConfig.getCustomScriptPaths();
|
||||
const QList<bool> enabled = userConfig.getCustomScriptsEnabled();
|
||||
for (int i = 0; i < paths.length(); i++)
|
||||
this->displayScript(paths.at(i), enabled.at(i));
|
||||
this->displayScript(paths.at(i), enabled.value(i, true));
|
||||
|
||||
connect(ui->button_Help, &QAbstractButton::clicked, this, &CustomScriptsEditor::openManual);
|
||||
connect(ui->button_CreateNewScript, &QAbstractButton::clicked, this, &CustomScriptsEditor::createNewScript);
|
||||
|
|
|
|||
|
|
@ -201,8 +201,8 @@ void EventFrame::populateScriptDropdown(NoScrollComboBox * combo, Project * proj
|
|||
QStringList scripts = map->getScriptLabels(this->event->getEventGroup());
|
||||
populateDropdown(combo, scripts);
|
||||
|
||||
// Depending on the settings, the autocomplete may also contain all global scripts.
|
||||
if (project && porymapConfig.loadAllEventScripts) {
|
||||
// Depending on the settings, the autocomplete may also contain scripts from outside the map.
|
||||
if (project && porymapConfig.scriptAutocompleteMode != ScriptAutocompleteMode::MapOnly) {
|
||||
project->insertGlobalScriptLabels(scripts);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ void MapView::drawForeground(QPainter *painter, const QRectF&) {
|
|||
painter->save();
|
||||
if (editor->layout) {
|
||||
// We're clipping here to hide parts of the grid that are outside the map.
|
||||
const QRectF mapRect(-0.5, -0.5, editor->layout->getWidth() * 16 + 1.5, editor->layout->getHeight() * 16 + 1.5);
|
||||
const QRectF mapRect(-0.5, -0.5, editor->layout->pixelWidth() + 1.5, editor->layout->pixelHeight() + 1.5);
|
||||
painter->setClipping(true);
|
||||
painter->setClipRect(mapRect);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#include "config.h"
|
||||
#include "imageproviders.h"
|
||||
#include "log.h"
|
||||
#include "editor.h"
|
||||
#include <QPainter>
|
||||
|
||||
|
|
@ -9,39 +8,63 @@ QImage getCollisionMetatileImage(Block block) {
|
|||
}
|
||||
|
||||
QImage getCollisionMetatileImage(int collision, int elevation) {
|
||||
const QImage * image = Editor::collisionIcons.at(collision).at(elevation);
|
||||
const QImage * image = Editor::collisionIcons.value(collision).value(elevation);
|
||||
return image ? *image : QImage();
|
||||
}
|
||||
|
||||
QImage getMetatileImage(uint16_t metatileId, const Layout *layout, bool useTruePalettes) {
|
||||
Metatile* metatile = Tileset::getMetatile(metatileId,
|
||||
layout ? layout->tileset_primary : nullptr,
|
||||
layout ? layout->tileset_secondary : nullptr);
|
||||
return getMetatileImage(metatile, layout, useTruePalettes);
|
||||
}
|
||||
|
||||
QImage getMetatileImage(const Metatile *metatile, const Layout *layout, bool useTruePalettes) {
|
||||
if (!layout) {
|
||||
return getMetatileImage(metatile, nullptr, nullptr, {}, {}, useTruePalettes);
|
||||
}
|
||||
return getMetatileImage(metatile,
|
||||
layout->tileset_primary,
|
||||
layout->tileset_secondary,
|
||||
layout->metatileLayerOrder(),
|
||||
layout->metatileLayerOpacity(),
|
||||
useTruePalettes);
|
||||
}
|
||||
|
||||
QImage getMetatileImage(
|
||||
uint16_t metatileId,
|
||||
Tileset *primaryTileset,
|
||||
Tileset *secondaryTileset,
|
||||
const Tileset *primaryTileset,
|
||||
const Tileset *secondaryTileset,
|
||||
const QList<int> &layerOrder,
|
||||
const QList<float> &layerOpacity,
|
||||
bool useTruePalettes)
|
||||
{
|
||||
Metatile* metatile = Tileset::getMetatile(metatileId, primaryTileset, secondaryTileset);
|
||||
if (!metatile) {
|
||||
QImage metatile_image(16, 16, QImage::Format_RGBA8888);
|
||||
metatile_image.fill(Qt::magenta);
|
||||
return metatile_image;
|
||||
}
|
||||
return getMetatileImage(metatile, primaryTileset, secondaryTileset, layerOrder, layerOpacity, useTruePalettes);
|
||||
return getMetatileImage(Tileset::getMetatile(metatileId, primaryTileset, secondaryTileset),
|
||||
primaryTileset,
|
||||
secondaryTileset,
|
||||
layerOrder,
|
||||
layerOpacity,
|
||||
useTruePalettes);
|
||||
}
|
||||
|
||||
// The color to use when we want to show some portion of the image request was invalid.
|
||||
// Normally this is Qt::magenta, but we'll use Qt::transparent if we think the image allows it.
|
||||
QColor getInvalidImageColor() {
|
||||
return (projectConfig.transparencyColor == QColor(Qt::transparent)) ? QColor(Qt::transparent) : QColor(Qt::magenta);
|
||||
}
|
||||
|
||||
QImage getMetatileImage(
|
||||
Metatile *metatile,
|
||||
Tileset *primaryTileset,
|
||||
Tileset *secondaryTileset,
|
||||
const Metatile *metatile,
|
||||
const Tileset *primaryTileset,
|
||||
const Tileset *secondaryTileset,
|
||||
const QList<int> &layerOrder,
|
||||
const QList<float> &layerOpacity,
|
||||
bool useTruePalettes)
|
||||
{
|
||||
QImage metatile_image(16, 16, QImage::Format_RGBA8888);
|
||||
QImage metatileImage(Metatile::pixelSize(), QImage::Format_RGBA8888);
|
||||
if (!metatile) {
|
||||
metatile_image.fill(Qt::magenta);
|
||||
return metatile_image;
|
||||
metatileImage.fill(getInvalidImageColor());
|
||||
return metatileImage;
|
||||
}
|
||||
|
||||
QList<QList<QRgb>> palettes = Tileset::getBlockPalettes(primaryTileset, secondaryTileset, useTruePalettes);
|
||||
|
|
@ -50,22 +73,20 @@ QImage getMetatileImage(
|
|||
// tile pixels line up across layers we will still have something to render.
|
||||
// The GBA renders transparent pixels using palette 0 color 0. We have this color,
|
||||
// but all 3 games actually overwrite it with black when loading the tileset palettes,
|
||||
// so we have a setting to choose between these two behaviors.
|
||||
metatile_image.fill(projectConfig.setTransparentPixelsBlack ? QColor("black") : QColor(palettes.value(0).value(0)));
|
||||
// so we have a setting to specify an override transparency color.
|
||||
metatileImage.fill(projectConfig.transparencyColor.isValid() ? projectConfig.transparencyColor : QColor(palettes.value(0).value(0)));
|
||||
|
||||
QPainter painter(&metatileImage);
|
||||
|
||||
QPainter metatile_painter(&metatile_image);
|
||||
const int numLayers = 3; // When rendering, metatiles always have 3 layers
|
||||
uint32_t layerType = metatile->layerType();
|
||||
for (int layer = 0; layer < numLayers; layer++)
|
||||
for (int y = 0; y < 2; y++)
|
||||
for (int x = 0; x < 2; x++) {
|
||||
int l = layerOrder.size() >= numLayers ? layerOrder[layer] : layer;
|
||||
|
||||
for (const auto &layer : layerOrder)
|
||||
for (int y = 0; y < Metatile::tileHeight(); y++)
|
||||
for (int x = 0; x < Metatile::tileWidth(); x++) {
|
||||
// Get the tile to render next
|
||||
Tile tile;
|
||||
int tileOffset = (y * 2) + x;
|
||||
int tileOffset = (y * Metatile::tileWidth()) + x;
|
||||
if (projectConfig.tripleLayerMetatilesEnabled) {
|
||||
tile = metatile->tiles.value(tileOffset + (l * 4));
|
||||
tile = metatile->tiles.value(tileOffset + (layer * Metatile::tilesPerLayer()));
|
||||
} else {
|
||||
// "Vanilla" metatiles only have 8 tiles, but render 12.
|
||||
// The remaining 4 tiles are rendered using user-specified tiles depending on layer type.
|
||||
|
|
@ -73,97 +94,80 @@ QImage getMetatileImage(
|
|||
{
|
||||
default:
|
||||
case Metatile::LayerType::Normal:
|
||||
if (l == 0)
|
||||
if (layer == 0)
|
||||
tile = Tile(projectConfig.unusedTileNormal);
|
||||
else // Tiles are on layers 1 and 2
|
||||
tile = metatile->tiles.value(tileOffset + ((l - 1) * 4));
|
||||
tile = metatile->tiles.value(tileOffset + ((layer - 1) * Metatile::tilesPerLayer()));
|
||||
break;
|
||||
case Metatile::LayerType::Covered:
|
||||
if (l == 2)
|
||||
if (layer == 2)
|
||||
tile = Tile(projectConfig.unusedTileCovered);
|
||||
else // Tiles are on layers 0 and 1
|
||||
tile = metatile->tiles.value(tileOffset + (l * 4));
|
||||
tile = metatile->tiles.value(tileOffset + (layer * Metatile::tilesPerLayer()));
|
||||
break;
|
||||
case Metatile::LayerType::Split:
|
||||
if (l == 1)
|
||||
if (layer == 1)
|
||||
tile = Tile(projectConfig.unusedTileSplit);
|
||||
else // Tiles are on layers 0 and 2
|
||||
tile = metatile->tiles.value(tileOffset + ((l == 0 ? 0 : 1) * 4));
|
||||
tile = metatile->tiles.value(tileOffset + ((layer == 0 ? 0 : 1) * Metatile::tilesPerLayer()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QImage tile_image = getTileImage(tile.tileId, primaryTileset, secondaryTileset);
|
||||
if (tile_image.isNull()) {
|
||||
// Some metatiles specify tiles that are outside the valid range.
|
||||
// The way the GBA will render these depends on what's in memory (which Porymap can't know)
|
||||
// so we treat them as if they were transparent.
|
||||
continue;
|
||||
}
|
||||
QImage tileImage = getColoredTileImage(tile.tileId, primaryTileset, secondaryTileset, palettes.value(tile.palette));
|
||||
|
||||
// Colorize the metatile tiles with its palette.
|
||||
if (tile.palette < palettes.length()) {
|
||||
const QList<QRgb> palette = palettes.value(tile.palette);
|
||||
for (int j = 0; j < palette.length(); j++) {
|
||||
tile_image.setColor(j, palette.value(j));
|
||||
}
|
||||
} else {
|
||||
logWarn(QString("Tile '%1' is referring to invalid palette number: '%2'").arg(tile.tileId).arg(tile.palette));
|
||||
}
|
||||
|
||||
QPoint origin = QPoint(x*8, y*8);
|
||||
float opacity = layerOpacity.size() >= numLayers ? layerOpacity[l] : 1.0;
|
||||
float opacity = layerOpacity.value(layer, 1.0);
|
||||
if (opacity < 1.0) {
|
||||
int alpha = 255 * opacity;
|
||||
for (int c = 0; c < tile_image.colorCount(); c++) {
|
||||
QColor color(tile_image.color(c));
|
||||
for (int c = 0; c < tileImage.colorCount(); c++) {
|
||||
QColor color(tileImage.color(c));
|
||||
color.setAlpha(alpha);
|
||||
tile_image.setColor(c, color.rgba());
|
||||
tileImage.setColor(c, color.rgba());
|
||||
}
|
||||
}
|
||||
|
||||
// Color 0 is displayed as transparent.
|
||||
QColor color(tile_image.color(0));
|
||||
color.setAlpha(0);
|
||||
tile_image.setColor(0, color.rgba());
|
||||
tile.flip(&tile_image);
|
||||
metatile_painter.drawImage(origin, tile_image);
|
||||
}
|
||||
metatile_painter.end();
|
||||
if (tileImage.colorCount()) {
|
||||
QColor color(tileImage.color(0));
|
||||
color.setAlpha(0);
|
||||
tileImage.setColor(0, color.rgba());
|
||||
}
|
||||
|
||||
return metatile_image;
|
||||
tile.flip(&tileImage);
|
||||
painter.drawImage(x * Tile::pixelWidth(), y * Tile::pixelHeight(), tileImage);
|
||||
}
|
||||
painter.end();
|
||||
|
||||
return metatileImage;
|
||||
}
|
||||
|
||||
QImage getTileImage(uint16_t tileId, Tileset *primaryTileset, Tileset *secondaryTileset) {
|
||||
Tileset *tileset = Tileset::getTileTileset(tileId, primaryTileset, secondaryTileset);
|
||||
int index = Tile::getIndexInTileset(tileId);
|
||||
if (!tileset) {
|
||||
return QImage();
|
||||
}
|
||||
return tileset->tiles.value(index, QImage());
|
||||
QImage getTileImage(uint16_t tileId, const Tileset *primaryTileset, const Tileset *secondaryTileset) {
|
||||
const Tileset *tileset = Tileset::getTileTileset(tileId, primaryTileset, secondaryTileset);
|
||||
return tileset ? tileset->tileImage(tileId) : QImage();
|
||||
}
|
||||
|
||||
QImage getColoredTileImage(uint16_t tileId, Tileset *primaryTileset, Tileset *secondaryTileset, const QList<QRgb> &palette) {
|
||||
QImage getColoredTileImage(uint16_t tileId, const Tileset *primaryTileset, const Tileset *secondaryTileset, const QList<QRgb> &palette) {
|
||||
QImage tileImage = getTileImage(tileId, primaryTileset, secondaryTileset);
|
||||
if (tileImage.isNull()) {
|
||||
tileImage = QImage(8, 8, QImage::Format_RGBA8888);
|
||||
QPainter painter(&tileImage);
|
||||
painter.fillRect(0, 0, 8, 8, palette.at(0));
|
||||
// Some tiles specify tile IDs or palette IDs that are outside the valid range.
|
||||
// The way the GBA will render these depends on what's in memory (which Porymap can't know)
|
||||
// so we render them using the invalid color
|
||||
tileImage = QImage(Tile::pixelSize(), QImage::Format_RGBA8888);
|
||||
tileImage.fill(getInvalidImageColor());
|
||||
} else {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
tileImage.setColor(i, palette.at(i));
|
||||
for (int i = 0; i < Tileset::numColorsPerPalette(); i++) {
|
||||
tileImage.setColor(i, palette.value(i, getInvalidImageColor().rgb()));
|
||||
}
|
||||
}
|
||||
|
||||
return tileImage;
|
||||
}
|
||||
|
||||
QImage getPalettedTileImage(uint16_t tileId, Tileset *primaryTileset, Tileset *secondaryTileset, int paletteId, bool useTruePalettes) {
|
||||
QImage getPalettedTileImage(uint16_t tileId, const Tileset *primaryTileset, const Tileset *secondaryTileset, int paletteId, bool useTruePalettes) {
|
||||
QList<QRgb> palette = Tileset::getPalette(paletteId, primaryTileset, secondaryTileset, useTruePalettes);
|
||||
return getColoredTileImage(tileId, primaryTileset, secondaryTileset, palette);
|
||||
}
|
||||
|
||||
QImage getGreyscaleTileImage(uint16_t tileId, Tileset *primaryTileset, Tileset *secondaryTileset) {
|
||||
QImage getGreyscaleTileImage(uint16_t tileId, const Tileset *primaryTileset, const Tileset *secondaryTileset) {
|
||||
return getColoredTileImage(tileId, primaryTileset, secondaryTileset, greyscalePalette);
|
||||
}
|
||||
|
||||
|
|
@ -175,3 +179,94 @@ void flattenTo4bppImage(QImage * image) {
|
|||
for (int i = 0; i < image->sizeInBytes(); i++, pixel++)
|
||||
*pixel %= 16;
|
||||
}
|
||||
|
||||
// Constructs a grid image of the metatiles in the specified ID range.
|
||||
QImage getMetatileSheetImage(const Tileset *primaryTileset,
|
||||
const Tileset *secondaryTileset,
|
||||
uint16_t metatileIdStart,
|
||||
uint16_t metatileIdEnd,
|
||||
int numMetatilesWide,
|
||||
const QList<int> &layerOrder,
|
||||
const QList<float> &layerOpacity,
|
||||
const QSize &metatileSize,
|
||||
bool useTruePalettes)
|
||||
{
|
||||
if (metatileIdEnd < metatileIdStart || numMetatilesWide <= 0)
|
||||
return QImage();
|
||||
|
||||
int numMetatilesToDraw = metatileIdEnd - metatileIdStart + 1;
|
||||
|
||||
// Round up image height for incomplete last row.
|
||||
int numMetatilesTall = Util::roundUpToMultiple(numMetatilesToDraw, numMetatilesWide) / numMetatilesWide;
|
||||
|
||||
QImage image(numMetatilesWide * metatileSize.width(), numMetatilesTall * metatileSize.height(), QImage::Format_RGBA8888);
|
||||
image.fill(getInvalidImageColor());
|
||||
|
||||
QPainter painter(&image);
|
||||
for (int i = 0; i < numMetatilesToDraw; i++) {
|
||||
uint16_t metatileId = i + metatileIdStart;
|
||||
QImage metatileImage = getMetatileImage(metatileId, primaryTileset, secondaryTileset, layerOrder, layerOpacity, useTruePalettes)
|
||||
.scaled(metatileSize);
|
||||
|
||||
int x = (i % numMetatilesWide) * metatileSize.width();
|
||||
int y = (i / numMetatilesWide) * metatileSize.height();
|
||||
painter.drawImage(x, y, metatileImage);
|
||||
}
|
||||
painter.end();
|
||||
return image;
|
||||
}
|
||||
|
||||
// Constructs a grid image of the metatiles in the primary and secondary tileset,
|
||||
// rounding as necessary to keep the two tilesets on separate rows.
|
||||
// The unused metatiles (if any) between the primary and secondary tilesets are skipped.
|
||||
QImage getMetatileSheetImage(const Tileset *primaryTileset,
|
||||
const Tileset *secondaryTileset,
|
||||
int numMetatilesWide,
|
||||
const QList<int> &layerOrder,
|
||||
const QList<float> &layerOpacity,
|
||||
const QSize &metatileSize,
|
||||
bool useTruePalettes)
|
||||
{
|
||||
auto createSheetImage = [=](uint16_t start, const Tileset *tileset) {
|
||||
uint16_t end = start;
|
||||
if (tileset) {
|
||||
if (tileset->numMetatiles() == 0)
|
||||
return QImage();
|
||||
end += tileset->numMetatiles() - 1;
|
||||
}
|
||||
return getMetatileSheetImage(primaryTileset,
|
||||
secondaryTileset,
|
||||
start,
|
||||
end,
|
||||
numMetatilesWide,
|
||||
layerOrder,
|
||||
layerOpacity,
|
||||
metatileSize,
|
||||
useTruePalettes);
|
||||
};
|
||||
|
||||
QImage primaryImage = createSheetImage(0, primaryTileset);
|
||||
QImage secondaryImage = createSheetImage(Project::getNumMetatilesPrimary(), secondaryTileset);
|
||||
|
||||
QImage image(qMax(primaryImage.width(), secondaryImage.width()), primaryImage.height() + secondaryImage.height(), QImage::Format_RGBA8888);
|
||||
image.fill(getInvalidImageColor());
|
||||
|
||||
QPainter painter(&image);
|
||||
painter.drawImage(0, 0, primaryImage);
|
||||
painter.drawImage(0, primaryImage.height(), secondaryImage);
|
||||
painter.end();
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
QImage getMetatileSheetImage(const Layout *layout, int numMetatilesWide, bool useTruePalettes) {
|
||||
if (!layout)
|
||||
return QImage();
|
||||
return getMetatileSheetImage(layout->tileset_primary,
|
||||
layout->tileset_secondary,
|
||||
numMetatilesWide,
|
||||
layout->metatileLayerOrder(),
|
||||
layout->metatileLayerOpacity(),
|
||||
Metatile::pixelSize(),
|
||||
useTruePalettes);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,15 +25,15 @@ void LayoutPixmapItem::paint(QGraphicsSceneMouseEvent *event) {
|
|||
|
||||
// Paint onto the map.
|
||||
bool shiftPressed = event->modifiers() & Qt::ShiftModifier;
|
||||
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
|
||||
QSize selectionDimensions = this->metatileSelector->getSelectionDimensions();
|
||||
if (settings->smartPathsEnabled) {
|
||||
if (!shiftPressed && selectionDimensions.x() == 3 && selectionDimensions.y() == 3) {
|
||||
if (!shiftPressed && isSmartPathSize(selectionDimensions)) {
|
||||
paintSmartPath(pos.x(), pos.y());
|
||||
} else {
|
||||
paintNormal(pos.x(), pos.y());
|
||||
}
|
||||
} else {
|
||||
if (shiftPressed && selectionDimensions.x() == 3 && selectionDimensions.y() == 3) {
|
||||
if (shiftPressed && isSmartPathSize(selectionDimensions)) {
|
||||
paintSmartPath(pos.x(), pos.y());
|
||||
} else {
|
||||
paintNormal(pos.x(), pos.y());
|
||||
|
|
@ -91,7 +91,7 @@ void LayoutPixmapItem::shift(int xDelta, int yDelta, bool fromScriptCall) {
|
|||
destY %= this->layout->getHeight();
|
||||
|
||||
int blockIndex = j * this->layout->getWidth() + i;
|
||||
Block srcBlock = oldMetatiles.at(blockIndex);
|
||||
Block srcBlock = oldMetatiles.value(blockIndex);
|
||||
this->layout->setBlock(destX, destY, srcBlock);
|
||||
}
|
||||
|
||||
|
|
@ -110,28 +110,28 @@ void LayoutPixmapItem::paintNormal(int x, int y, bool fromScriptCall) {
|
|||
// This allows painting via dragging the mouse to tile the painted region.
|
||||
int xDiff = x - initialX;
|
||||
int yDiff = y - initialY;
|
||||
if (xDiff < 0 && xDiff % selection.dimensions.x() != 0) xDiff -= selection.dimensions.x();
|
||||
if (yDiff < 0 && yDiff % selection.dimensions.y() != 0) yDiff -= selection.dimensions.y();
|
||||
if (xDiff < 0 && xDiff % selection.dimensions.width() != 0) xDiff -= selection.dimensions.width();
|
||||
if (yDiff < 0 && yDiff % selection.dimensions.height() != 0) yDiff -= selection.dimensions.height();
|
||||
|
||||
x = initialX + (xDiff / selection.dimensions.x()) * selection.dimensions.x();
|
||||
y = initialY + (yDiff / selection.dimensions.y()) * selection.dimensions.y();
|
||||
x = initialX + (xDiff / selection.dimensions.width()) * selection.dimensions.width();
|
||||
y = initialY + (yDiff / selection.dimensions.height()) * selection.dimensions.height();
|
||||
|
||||
// for edit history
|
||||
Blockdata oldMetatiles = !fromScriptCall ? this->layout->blockdata : Blockdata();
|
||||
|
||||
for (int i = 0; i < selection.dimensions.x() && i + x < this->layout->getWidth(); i++)
|
||||
for (int j = 0; j < selection.dimensions.y() && j + y < this->layout->getHeight(); j++) {
|
||||
for (int i = 0; i < selection.dimensions.width() && i + x < this->layout->getWidth(); i++)
|
||||
for (int j = 0; j < selection.dimensions.height() && j + y < this->layout->getHeight(); j++) {
|
||||
int actualX = i + x;
|
||||
int actualY = j + y;
|
||||
Block block;
|
||||
if (this->layout->getBlock(actualX, actualY, &block)) {
|
||||
int index = j * selection.dimensions.x() + i;
|
||||
MetatileSelectionItem item = selection.metatileItems.at(index);
|
||||
int index = j * selection.dimensions.width() + i;
|
||||
MetatileSelectionItem item = selection.metatileItems.value(index);
|
||||
if (!item.enabled)
|
||||
continue;
|
||||
block.setMetatileId(item.metatileId);
|
||||
if (selection.hasCollision && selection.collisionItems.length() == selection.metatileItems.length()) {
|
||||
CollisionSelectionItem collisionItem = selection.collisionItems.at(index);
|
||||
CollisionSelectionItem collisionItem = selection.collisionItems.value(index);
|
||||
block.setCollision(collisionItem.collision);
|
||||
block.setElevation(collisionItem.elevation);
|
||||
}
|
||||
|
|
@ -177,8 +177,11 @@ bool isSmartPathTile(QList<MetatileSelectionItem> metatileItems, uint16_t metati
|
|||
return false;
|
||||
}
|
||||
|
||||
bool isValidSmartPathSelection(MetatileSelection selection) {
|
||||
if (selection.dimensions.x() != 3 || selection.dimensions.y() != 3)
|
||||
bool LayoutPixmapItem::isValidSmartPathSelection(MetatileSelection selection) {
|
||||
if (!isSmartPathSize(selection.dimensions))
|
||||
return false;
|
||||
|
||||
if (selection.metatileItems.length() != (LayoutPixmapItem::smartPathWidth * LayoutPixmapItem::smartPathHeight))
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < selection.metatileItems.length(); i++) {
|
||||
|
|
@ -195,13 +198,13 @@ void LayoutPixmapItem::paintSmartPath(int x, int y, bool fromScriptCall) {
|
|||
return;
|
||||
|
||||
// Shift to the middle tile of the smart path selection.
|
||||
uint16_t openMetatileId = selection.metatileItems.at(4).metatileId;
|
||||
uint16_t openMetatileId = selection.metatileItems.at(smartPathMiddleIndex).metatileId;
|
||||
uint16_t openCollision = 0;
|
||||
uint16_t openElevation = 0;
|
||||
bool setCollisions = false;
|
||||
if (selection.hasCollision && selection.collisionItems.length() == selection.metatileItems.length()) {
|
||||
openCollision = selection.collisionItems.at(4).collision;
|
||||
openElevation = selection.collisionItems.at(4).elevation;
|
||||
openCollision = selection.collisionItems.at(smartPathMiddleIndex).collision;
|
||||
openElevation = selection.collisionItems.at(smartPathMiddleIndex).elevation;
|
||||
setCollisions = true;
|
||||
}
|
||||
|
||||
|
|
@ -356,7 +359,7 @@ void LayoutPixmapItem::updateMetatileSelection(QGraphicsSceneMouseEvent *event)
|
|||
metatiles.append(block.metatileId());
|
||||
}
|
||||
int blockIndex = y * this->layout->getWidth() + x;
|
||||
block = this->layout->blockdata.at(blockIndex);
|
||||
block = this->layout->blockdata.value(blockIndex);
|
||||
auto collision = block.collision();
|
||||
auto elevation = block.elevation();
|
||||
collisions.append(QPair<uint16_t, uint16_t>(collision, elevation));
|
||||
|
|
@ -377,7 +380,7 @@ void LayoutPixmapItem::floodFill(QGraphicsSceneMouseEvent *event) {
|
|||
int metatileId = selection.metatileItems.first().metatileId;
|
||||
if (selection.metatileItems.count() > 1 || (this->layout->getBlock(pos.x(), pos.y(), &block) && block.metatileId() != metatileId)) {
|
||||
bool smartPathsEnabled = event->modifiers() & Qt::ShiftModifier;
|
||||
if ((this->settings->smartPathsEnabled || smartPathsEnabled) && selection.dimensions.x() == 3 && selection.dimensions.y() == 3)
|
||||
if ((this->settings->smartPathsEnabled || smartPathsEnabled) && isSmartPathSize(selection.dimensions))
|
||||
this->floodFillSmartPath(pos.x(), pos.y());
|
||||
else
|
||||
this->floodFill(pos.x(), pos.y());
|
||||
|
|
@ -398,7 +401,7 @@ void LayoutPixmapItem::magicFill(QGraphicsSceneMouseEvent *event) {
|
|||
}
|
||||
|
||||
void LayoutPixmapItem::magicFill(int x, int y, uint16_t metatileId, bool fromScriptCall) {
|
||||
QPoint selectionDimensions(1, 1);
|
||||
QSize selectionDimensions(1, 1);
|
||||
QList<MetatileSelectionItem> selectedMetatiles = QList<MetatileSelectionItem>({MetatileSelectionItem{ true, metatileId }});
|
||||
this->magicFill(x, y, selectionDimensions, selectedMetatiles, QList<CollisionSelectionItem>(), fromScriptCall);
|
||||
}
|
||||
|
|
@ -411,9 +414,9 @@ void LayoutPixmapItem::magicFill(int x, int y, bool fromScriptCall) {
|
|||
void LayoutPixmapItem::magicFill(
|
||||
int initialX,
|
||||
int initialY,
|
||||
QPoint selectionDimensions,
|
||||
QList<MetatileSelectionItem> selectedMetatiles,
|
||||
QList<CollisionSelectionItem> selectedCollisions,
|
||||
const QSize &selectionDimensions,
|
||||
const QList<MetatileSelectionItem> &selectedMetatiles,
|
||||
const QList<CollisionSelectionItem> &selectedCollisions,
|
||||
bool fromScriptCall) {
|
||||
Block block;
|
||||
if (this->layout->getBlock(initialX, initialY, &block)) {
|
||||
|
|
@ -430,12 +433,12 @@ void LayoutPixmapItem::magicFill(
|
|||
if (this->layout->getBlock(x, y, &block) && block.metatileId() == metatileId) {
|
||||
int xDiff = x - initialX;
|
||||
int yDiff = y - initialY;
|
||||
int i = xDiff % selectionDimensions.x();
|
||||
int j = yDiff % selectionDimensions.y();
|
||||
if (i < 0) i = selectionDimensions.x() + i;
|
||||
if (j < 0) j = selectionDimensions.y() + j;
|
||||
int index = j * selectionDimensions.x() + i;
|
||||
if (selectedMetatiles.at(index).enabled) {
|
||||
int i = xDiff % selectionDimensions.width();
|
||||
int j = yDiff % selectionDimensions.height();
|
||||
if (i < 0) i = selectionDimensions.width() + i;
|
||||
if (j < 0) j = selectionDimensions.height() + j;
|
||||
int index = j * selectionDimensions.width() + i;
|
||||
if (index < selectedMetatiles.length() && selectedMetatiles.at(index).enabled) {
|
||||
block.setMetatileId(selectedMetatiles.at(index).metatileId);
|
||||
if (setCollisions) {
|
||||
CollisionSelectionItem item = selectedCollisions.at(index);
|
||||
|
|
@ -460,7 +463,7 @@ void LayoutPixmapItem::floodFill(int initialX, int initialY, bool fromScriptCall
|
|||
}
|
||||
|
||||
void LayoutPixmapItem::floodFill(int initialX, int initialY, uint16_t metatileId, bool fromScriptCall) {
|
||||
QPoint selectionDimensions(1, 1);
|
||||
QSize selectionDimensions(1, 1);
|
||||
QList<MetatileSelectionItem> selectedMetatiles = QList<MetatileSelectionItem>({MetatileSelectionItem{true, metatileId}});
|
||||
this->floodFill(initialX, initialY, selectionDimensions, selectedMetatiles, QList<CollisionSelectionItem>(), fromScriptCall);
|
||||
}
|
||||
|
|
@ -468,9 +471,9 @@ void LayoutPixmapItem::floodFill(int initialX, int initialY, uint16_t metatileId
|
|||
void LayoutPixmapItem::floodFill(
|
||||
int initialX,
|
||||
int initialY,
|
||||
QPoint selectionDimensions,
|
||||
QList<MetatileSelectionItem> selectedMetatiles,
|
||||
QList<CollisionSelectionItem> selectedCollisions,
|
||||
const QSize &selectionDimensions,
|
||||
const QList<MetatileSelectionItem> &selectedMetatiles,
|
||||
const QList<CollisionSelectionItem> &selectedCollisions,
|
||||
bool fromScriptCall) {
|
||||
bool setCollisions = selectedCollisions.length() == selectedMetatiles.length();
|
||||
Blockdata oldMetatiles = !fromScriptCall ? this->layout->blockdata : Blockdata();
|
||||
|
|
@ -490,17 +493,17 @@ void LayoutPixmapItem::floodFill(
|
|||
visited.insert(x + y * this->layout->getWidth());
|
||||
int xDiff = x - initialX;
|
||||
int yDiff = y - initialY;
|
||||
int i = xDiff % selectionDimensions.x();
|
||||
int j = yDiff % selectionDimensions.y();
|
||||
if (i < 0) i = selectionDimensions.x() + i;
|
||||
if (j < 0) j = selectionDimensions.y() + j;
|
||||
int index = j * selectionDimensions.x() + i;
|
||||
uint16_t metatileId = selectedMetatiles.at(index).metatileId;
|
||||
int i = xDiff % selectionDimensions.width();
|
||||
int j = yDiff % selectionDimensions.height();
|
||||
if (i < 0) i = selectionDimensions.width() + i;
|
||||
if (j < 0) j = selectionDimensions.height() + j;
|
||||
int index = j * selectionDimensions.width() + i;
|
||||
uint16_t metatileId = selectedMetatiles.value(index).metatileId;
|
||||
uint16_t old_metatileId = block.metatileId();
|
||||
if (selectedMetatiles.at(index).enabled && (selectedMetatiles.count() != 1 || old_metatileId != metatileId)) {
|
||||
if (selectedMetatiles.value(index).enabled && (selectedMetatiles.count() != 1 || old_metatileId != metatileId)) {
|
||||
block.setMetatileId(metatileId);
|
||||
if (setCollisions) {
|
||||
CollisionSelectionItem item = selectedCollisions.at(index);
|
||||
CollisionSelectionItem item = selectedCollisions.value(index);
|
||||
block.setCollision(item.collision);
|
||||
block.setElevation(item.elevation);
|
||||
}
|
||||
|
|
@ -535,12 +538,12 @@ void LayoutPixmapItem::floodFillSmartPath(int initialX, int initialY, bool fromS
|
|||
return;
|
||||
|
||||
// Shift to the middle tile of the smart path selection.
|
||||
uint16_t openMetatileId = selection.metatileItems.at(4).metatileId;
|
||||
uint16_t openMetatileId = selection.metatileItems.at(smartPathMiddleIndex).metatileId;
|
||||
uint16_t openCollision = 0;
|
||||
uint16_t openElevation = 0;
|
||||
bool setCollisions = false;
|
||||
if (selection.hasCollision && selection.collisionItems.length() == selection.metatileItems.length()) {
|
||||
CollisionSelectionItem item = selection.collisionItems.at(4);
|
||||
CollisionSelectionItem item = selection.collisionItems.at(smartPathMiddleIndex);
|
||||
openCollision = item.collision;
|
||||
openElevation = item.elevation;
|
||||
setCollisions = true;
|
||||
|
|
@ -695,25 +698,19 @@ void LayoutPixmapItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
|
|||
QPoint pos = Metatile::coordFromPixmapCoord(event->pos());
|
||||
if (pos != this->metatilePos) {
|
||||
this->metatilePos = pos;
|
||||
emit this->hoveredMapMetatileChanged(pos);
|
||||
}
|
||||
if (this->settings->betterCursors && this->editsEnabled) {
|
||||
setCursor(this->settings->mapCursor);
|
||||
emit this->hoverChanged(pos);
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutPixmapItem::hoverEnterEvent(QGraphicsSceneHoverEvent * event) {
|
||||
void LayoutPixmapItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event) {
|
||||
this->has_mouse = true;
|
||||
QPoint pos = Metatile::coordFromPixmapCoord(event->pos());
|
||||
emit this->hoveredMapMetatileChanged(pos);
|
||||
this->metatilePos = Metatile::coordFromPixmapCoord(event->pos());
|
||||
emit this->hoverEntered(this->metatilePos);
|
||||
}
|
||||
|
||||
void LayoutPixmapItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *) {
|
||||
emit this->hoveredMapMetatileCleared();
|
||||
if (this->settings->betterCursors && this->editsEnabled) {
|
||||
unsetCursor();
|
||||
}
|
||||
this->has_mouse = false;
|
||||
emit this->hoverCleared();
|
||||
}
|
||||
|
||||
void LayoutPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
|
||||
|
|
@ -730,7 +727,7 @@ void LayoutPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
|
|||
return;
|
||||
|
||||
this->metatilePos = pos;
|
||||
emit hoveredMapMetatileChanged(pos);
|
||||
emit hoverChanged(pos);
|
||||
emit mouseEvent(event, this);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ MapImageExporter::MapImageExporter(QWidget *parent, Project *project, Map *map,
|
|||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
ui->setupUi(this);
|
||||
|
||||
m_scene = new QGraphicsScene(this);
|
||||
m_scene = new CheckeredBgScene(QSize(8,8), this);
|
||||
m_preview = m_scene->addPixmap(QPixmap());
|
||||
ui->graphicsView_Preview->setScene(m_scene);
|
||||
|
||||
|
|
@ -333,8 +333,8 @@ QGifImage* MapImageExporter::createTimelapseGifImage(QProgressDialog *progress)
|
|||
if (currentHistoryAppliesToFrame(step.historyStack) || step.historyStack->index() == step.initialStackIndex) {
|
||||
// Either this is relevant edit history, or it's the final frame (which is always rendered). Record the size of the map at this point.
|
||||
QMargins margins = getMargins(m_map);
|
||||
canvasSize = canvasSize.expandedTo(QSize(m_layout->getWidth() * 16 + margins.left() + margins.right(),
|
||||
m_layout->getHeight() * 16 + margins.top() + margins.bottom()));
|
||||
canvasSize = canvasSize.expandedTo(QSize(m_layout->pixelWidth() + margins.left() + margins.right(),
|
||||
m_layout->pixelHeight() + margins.top() + margins.bottom()));
|
||||
}
|
||||
if (step.historyStack->canUndo()){
|
||||
step.historyStack->undo();
|
||||
|
|
@ -434,8 +434,8 @@ QPixmap MapImageExporter::getStitchedImage(QProgressDialog *progress) {
|
|||
if (!connection->isCardinal()) continue;
|
||||
Map *connectedMap = connection->targetMap();
|
||||
if (!connectedMap) continue;
|
||||
QPoint pos = connection->relativePos();
|
||||
unvisited.append(StitchedMap{cur.x + (pos.x() * 16), cur.y + (pos.y() * 16), connectedMap});
|
||||
QPoint pos = connection->relativePixelPos();
|
||||
unvisited.append(StitchedMap{cur.x + pos.x(), cur.y + pos.y(), connectedMap});
|
||||
}
|
||||
}
|
||||
if (stitchedMaps.isEmpty())
|
||||
|
|
@ -447,7 +447,7 @@ QPixmap MapImageExporter::getStitchedImage(QProgressDialog *progress) {
|
|||
// Determine the overall dimensions of the stitched maps.
|
||||
QRect dimensions = QRect(0, 0, m_map->getWidth(), m_map->getHeight()) + getMargins(m_map);
|
||||
for (const StitchedMap &map : stitchedMaps) {
|
||||
dimensions |= (QRect(map.x, map.y, map.map->getWidth() * 16, map.map->getHeight() * 16) + getMargins(map.map));
|
||||
dimensions |= (QRect(map.x, map.y, map.map->pixelWidth(), map.map->pixelHeight()) + getMargins(map.map));
|
||||
}
|
||||
|
||||
QPixmap stitchedPixmap(dimensions.width(), dimensions.height());
|
||||
|
|
@ -602,7 +602,7 @@ QPixmap MapImageExporter::getFormattedMapPixmap() {
|
|||
QMargins MapImageExporter::getMargins(const Map *map) {
|
||||
QMargins margins;
|
||||
if (m_settings.showBorder) {
|
||||
margins = m_project->getMetatileViewDistance() * 16;
|
||||
margins = m_project->getPixelViewDistance();
|
||||
} else if (map && connectionsEnabled()) {
|
||||
for (const auto &connection : map->getConnections()) {
|
||||
const QString dir = connection->direction();
|
||||
|
|
@ -612,10 +612,10 @@ QMargins MapImageExporter::getMargins(const Map *map) {
|
|||
if (!targetMap) continue;
|
||||
|
||||
QRect rect = targetMap->getConnectionRect(dir);
|
||||
if (dir == "up") margins.setTop(rect.height() * 16);
|
||||
else if (dir == "down") margins.setBottom(rect.height() * 16);
|
||||
else if (dir == "left") margins.setLeft(rect.width() * 16);
|
||||
else if (dir == "right") margins.setRight(rect.width() * 16);
|
||||
if (dir == "up") margins.setTop(rect.height());
|
||||
else if (dir == "down") margins.setBottom(rect.height());
|
||||
else if (dir == "left") margins.setLeft(rect.width());
|
||||
else if (dir == "right") margins.setRight(rect.width());
|
||||
}
|
||||
}
|
||||
if (m_settings.showGrid) {
|
||||
|
|
@ -652,7 +652,7 @@ void MapImageExporter::paintBorder(QPainter *painter, Layout *layout) {
|
|||
// Skip border painting if it would be fully covered by the rest of the map
|
||||
if (layout->isWithinBounds(QRect(x, y, layout->getBorderWidth(), layout->getBorderHeight())))
|
||||
continue;
|
||||
painter->drawPixmap(x * 16, y * 16, layout->border_pixmap);
|
||||
painter->drawPixmap(x * Metatile::pixelWidth(), y * Metatile::pixelHeight(), layout->border_pixmap);
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
|
|
@ -665,7 +665,7 @@ void MapImageExporter::paintConnections(QPainter *painter, const Map *map) {
|
|||
for (const auto &connection : map->getConnections()) {
|
||||
if (!m_settings.showConnections.contains(connection->direction()))
|
||||
continue;
|
||||
painter->drawImage(connection->relativePos(true) * 16, connection->render().toImage());
|
||||
painter->drawImage(connection->relativePixelPos(true), connection->render().toImage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -693,12 +693,12 @@ void MapImageExporter::paintGrid(QPainter *painter, const Layout *layout) {
|
|||
if (!m_settings.showGrid)
|
||||
return;
|
||||
|
||||
int w = layout->getWidth() * 16;
|
||||
int h = layout->getHeight() * 16;
|
||||
for (int x = 0; x <= w; x += 16) {
|
||||
int w = layout->pixelWidth();
|
||||
int h = layout->pixelHeight();
|
||||
for (int x = 0; x <= w; x += Metatile::pixelWidth()) {
|
||||
painter->drawLine(x, 0, x, h);
|
||||
}
|
||||
for (int y = 0; y <= h; y += 16) {
|
||||
for (int y = 0; y <= h; y += Metatile::pixelHeight()) {
|
||||
painter->drawLine(0, y, w, y);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,9 +37,11 @@ QPainterPath MapRuler::shape() const {
|
|||
ruler.addRect(xRuler);
|
||||
ruler.addRect(yRuler);
|
||||
ruler = ruler.simplified();
|
||||
for (int x = 16; x < pixWidth(); x += 16)
|
||||
int w = Metatile::pixelWidth();
|
||||
int h = Metatile::pixelHeight();
|
||||
for (int x = w; x < pixWidth(); x += w)
|
||||
ruler.addRect(x, xRuler.y(), 0, thickness);
|
||||
for (int y = 16; y < pixHeight(); y += 16)
|
||||
for (int y = h; y < pixHeight(); y += h)
|
||||
ruler.addRect(yRuler.x(), y, thickness, 0);
|
||||
if (deltaX() && deltaY())
|
||||
ruler.addPolygon(QVector<QPointF>({ cornerTick.p1(), cornerTick.p2() }));
|
||||
|
|
@ -131,7 +133,9 @@ QPoint MapRuler::snapToWithinBounds(QPoint pos) const {
|
|||
|
||||
void MapRuler::updateGeometry() {
|
||||
prepareGeometryChange();
|
||||
setPos(QPoint(left() * 16 + 8, top() * 16 + 8));
|
||||
int w = Metatile::pixelWidth();
|
||||
int h = Metatile::pixelHeight();
|
||||
setPos(QPoint(left() * w + w/2, top() * h + h/2));
|
||||
/* Determine what quadrant the end point is in relative to the anchor point. The anchor
|
||||
* point is the top-left corner of the metatile the ruler starts in, so a zero-length
|
||||
* ruler is considered to be in the bottom-right quadrant from the anchor point. */
|
||||
|
|
|
|||
376
src/ui/metatileimageexporter.cpp
Normal file
376
src/ui/metatileimageexporter.cpp
Normal file
|
|
@ -0,0 +1,376 @@
|
|||
#include "metatileimageexporter.h"
|
||||
#include "ui_metatileimageexporter.h"
|
||||
#include "filedialog.h"
|
||||
#include "imageproviders.h"
|
||||
#include "utility.h"
|
||||
#include "project.h"
|
||||
#include "metatile.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
MetatileImageExporter::MetatileImageExporter(QWidget *parent, Tileset *primaryTileset, Tileset *secondaryTileset, Settings *savedSettings) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::MetatileImageExporter),
|
||||
m_primaryTileset(primaryTileset),
|
||||
m_secondaryTileset(secondaryTileset),
|
||||
m_savedSettings(savedSettings)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
m_transparencyButtons = {
|
||||
ui->radioButton_TransparencyNormal,
|
||||
ui->radioButton_TransparencyBlack,
|
||||
ui->radioButton_TransparencyFirst,
|
||||
};
|
||||
|
||||
m_scene = new CheckeredBgScene(QSize(8,8), this);
|
||||
m_preview = m_scene->addPixmap(QPixmap());
|
||||
ui->graphicsView_Preview->setScene(m_scene);
|
||||
|
||||
if (projectConfig.tripleLayerMetatilesEnabled) {
|
||||
// When triple-layer metatiles are enabled there is no unused layer,
|
||||
// so this setting becomes pointless. Disable it.
|
||||
ui->checkBox_Placeholders->setVisible(false);
|
||||
}
|
||||
|
||||
uint16_t maxMetatileId = Block::getMaxMetatileId();
|
||||
ui->spinBox_MetatileStart->setMaximum(maxMetatileId);
|
||||
ui->spinBox_MetatileEnd->setMaximum(maxMetatileId);
|
||||
ui->spinBox_WidthMetatiles->setRange(1, maxMetatileId);
|
||||
ui->spinBox_WidthPixels->setRange(1 * Metatile::pixelWidth(), maxMetatileId * Metatile::pixelWidth());
|
||||
|
||||
if (m_primaryTileset) {
|
||||
ui->comboBox_PrimaryTileset->setTextItem(m_primaryTileset->name);
|
||||
}
|
||||
if (m_secondaryTileset) {
|
||||
ui->comboBox_SecondaryTileset->setTextItem(m_secondaryTileset->name);
|
||||
}
|
||||
|
||||
if (m_savedSettings) {
|
||||
populate(*m_savedSettings);
|
||||
} else {
|
||||
populate({});
|
||||
}
|
||||
|
||||
connect(ui->listWidget_Layers, &ReorderableListWidget::itemChanged, this, &MetatileImageExporter::updatePreview);
|
||||
connect(ui->listWidget_Layers, &ReorderableListWidget::reordered, this, &MetatileImageExporter::updatePreview);
|
||||
|
||||
connect(ui->pushButton_Save, &QPushButton::pressed, [this] { if (saveImage()) close(); });
|
||||
connect(ui->pushButton_Close, &QPushButton::pressed, this, &MetatileImageExporter::close);
|
||||
connect(ui->pushButton_Reset, &QPushButton::pressed, this, &MetatileImageExporter::reset);
|
||||
|
||||
connect(ui->spinBox_WidthMetatiles, &UIntSpinBox::valueChanged, this, &MetatileImageExporter::syncPixelWidth);
|
||||
connect(ui->spinBox_WidthMetatiles, &UIntSpinBox::valueChanged, this, &MetatileImageExporter::queuePreviewUpdate);
|
||||
connect(ui->spinBox_WidthMetatiles, &UIntSpinBox::editingFinished, this, &MetatileImageExporter::tryUpdatePreview);
|
||||
|
||||
connect(ui->spinBox_WidthPixels, &UIntSpinBox::valueChanged, this, &MetatileImageExporter::syncMetatileWidth);
|
||||
connect(ui->spinBox_WidthPixels, &UIntSpinBox::valueChanged, this, &MetatileImageExporter::queuePreviewUpdate);
|
||||
connect(ui->spinBox_WidthPixels, &UIntSpinBox::editingFinished, this, &MetatileImageExporter::syncPixelWidth); // Round pixel width to multiple of 16
|
||||
connect(ui->spinBox_WidthPixels, &UIntSpinBox::editingFinished, this, &MetatileImageExporter::tryUpdatePreview);
|
||||
|
||||
connect(ui->spinBox_MetatileStart, &UIntHexSpinBox::valueChanged, this, &MetatileImageExporter::validateMetatileEnd);
|
||||
connect(ui->spinBox_MetatileStart, &UIntHexSpinBox::valueChanged, this, &MetatileImageExporter::queuePreviewUpdate);
|
||||
connect(ui->spinBox_MetatileStart, &UIntHexSpinBox::editingFinished, this, &MetatileImageExporter::tryUpdatePreview);
|
||||
|
||||
connect(ui->spinBox_MetatileEnd, &UIntHexSpinBox::valueChanged, this, &MetatileImageExporter::validateMetatileStart);
|
||||
connect(ui->spinBox_MetatileEnd, &UIntHexSpinBox::valueChanged, this, &MetatileImageExporter::queuePreviewUpdate);
|
||||
connect(ui->spinBox_MetatileEnd, &UIntHexSpinBox::editingFinished, this, &MetatileImageExporter::tryUpdatePreview);
|
||||
|
||||
// If we used toggled instead of clicked we'd get two preview updates instead of one when the setting changes.
|
||||
connect(ui->radioButton_TransparencyNormal, &QRadioButton::clicked, this, &MetatileImageExporter::updatePreview);
|
||||
connect(ui->radioButton_TransparencyBlack, &QRadioButton::clicked, this, &MetatileImageExporter::updatePreview);
|
||||
connect(ui->radioButton_TransparencyFirst, &QRadioButton::clicked, this, &MetatileImageExporter::updatePreview);
|
||||
|
||||
connect(ui->checkBox_Placeholders, &QCheckBox::toggled, this, &MetatileImageExporter::updatePreview);
|
||||
connect(ui->checkBox_PrimaryTileset, &QCheckBox::toggled, this, &MetatileImageExporter::tryEnforceMetatileRange);
|
||||
connect(ui->checkBox_PrimaryTileset, &QCheckBox::toggled, this, &MetatileImageExporter::updatePreview);
|
||||
connect(ui->checkBox_SecondaryTileset, &QCheckBox::toggled, this, &MetatileImageExporter::tryEnforceMetatileRange);
|
||||
connect(ui->checkBox_SecondaryTileset, &QCheckBox::toggled, this, &MetatileImageExporter::updatePreview);
|
||||
|
||||
ui->graphicsView_Preview->setFocus();
|
||||
}
|
||||
|
||||
MetatileImageExporter::~MetatileImageExporter() {
|
||||
delete ui;
|
||||
}
|
||||
|
||||
// Allow the window to open before displaying the preview.
|
||||
// Metatile sheet image creation is generally quick, so this only
|
||||
// really matters so that the graphics view can adjust the scale properly.
|
||||
void MetatileImageExporter::showEvent(QShowEvent *event) {
|
||||
QDialog::showEvent(event);
|
||||
if (!event->spontaneous()) {
|
||||
QTimer::singleShot(0, this, &MetatileImageExporter::updatePreview);
|
||||
}
|
||||
}
|
||||
|
||||
void MetatileImageExporter::closeEvent(QCloseEvent *event) {
|
||||
if (m_savedSettings) {
|
||||
m_savedSettings->metatileStart = ui->spinBox_MetatileStart->value();
|
||||
m_savedSettings->metatileEnd = ui->spinBox_MetatileEnd->value();
|
||||
m_savedSettings->numMetatilesWide = ui->spinBox_WidthMetatiles->value();
|
||||
m_savedSettings->usePrimaryTileset = ui->checkBox_PrimaryTileset->isChecked();
|
||||
m_savedSettings->useSecondaryTileset = ui->checkBox_SecondaryTileset->isChecked();
|
||||
m_savedSettings->renderPlaceholders = ui->checkBox_Placeholders->isChecked();
|
||||
for (int i = 0; i < m_transparencyButtons.length(); i++) {
|
||||
if (m_transparencyButtons.at(i)->isChecked()) {
|
||||
m_savedSettings->transparencyMode = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_savedSettings->layerOrder.clear();
|
||||
for (int i = 0; i < ui->listWidget_Layers->count(); i++) {
|
||||
auto item = ui->listWidget_Layers->item(i);
|
||||
int layerNum = item->data(Qt::UserRole).toInt();
|
||||
m_savedSettings->layerOrder[layerNum] = (item->checkState() == Qt::Checked);
|
||||
}
|
||||
}
|
||||
QDialog::closeEvent(event);
|
||||
}
|
||||
|
||||
void MetatileImageExporter::populate(const Settings &settings) {
|
||||
const QSignalBlocker b_MetatileStart(ui->spinBox_MetatileStart);
|
||||
ui->spinBox_MetatileStart->setValue(settings.metatileStart);
|
||||
|
||||
const QSignalBlocker b_MetatileEnd(ui->spinBox_MetatileStart);
|
||||
ui->spinBox_MetatileEnd->setValue(settings.metatileEnd);
|
||||
|
||||
const QSignalBlocker b_WidthMetatiles(ui->spinBox_MetatileStart);
|
||||
ui->spinBox_WidthMetatiles->setValue(settings.numMetatilesWide);
|
||||
|
||||
const QSignalBlocker b_WidthPixels(ui->spinBox_MetatileStart);
|
||||
ui->spinBox_WidthPixels->setValue(settings.numMetatilesWide * Metatile::pixelWidth());
|
||||
|
||||
const QSignalBlocker b_PrimaryTileset(ui->spinBox_MetatileStart);
|
||||
ui->checkBox_PrimaryTileset->setChecked(settings.usePrimaryTileset);
|
||||
|
||||
const QSignalBlocker b_SecondaryTileset(ui->spinBox_MetatileStart);
|
||||
ui->checkBox_SecondaryTileset->setChecked(settings.useSecondaryTileset);
|
||||
|
||||
const QSignalBlocker b_Placeholders(ui->spinBox_MetatileStart);
|
||||
ui->checkBox_Placeholders->setChecked(settings.renderPlaceholders);
|
||||
|
||||
if (m_transparencyButtons.value(settings.transparencyMode)) {
|
||||
auto button = m_transparencyButtons[settings.transparencyMode];
|
||||
const QSignalBlocker b_Transparency(button);
|
||||
button->setChecked(true);
|
||||
}
|
||||
|
||||
// Build layer list from settings
|
||||
const QSignalBlocker b_Layers(ui->listWidget_Layers);
|
||||
ui->listWidget_Layers->clear();
|
||||
for (auto it = settings.layerOrder.cbegin(); it != settings.layerOrder.cend(); it++) {
|
||||
int layerNum = it.key();
|
||||
bool enabled = it.value();
|
||||
|
||||
auto item = new QListWidgetItem(Metatile::getLayerName(layerNum));
|
||||
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsUserCheckable | Qt::ItemNeverHasChildren);
|
||||
item->setCheckState(enabled ? Qt::Checked : Qt::Unchecked);
|
||||
item->setData(Qt::UserRole, layerNum); // Save the original index to identify the layer
|
||||
ui->listWidget_Layers->addItem(item);
|
||||
}
|
||||
// Don't give extra unnecessary space to the list
|
||||
ui->listWidget_Layers->setFixedHeight(ui->listWidget_Layers->sizeHintForRow(0) * ui->listWidget_Layers->count() + 4);
|
||||
|
||||
tryEnforceMetatileRange();
|
||||
}
|
||||
|
||||
void MetatileImageExporter::applySettings(const Settings &settings) {
|
||||
populate(settings);
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
void MetatileImageExporter::reset() {
|
||||
applySettings({});
|
||||
}
|
||||
|
||||
QImage MetatileImageExporter::getImage() {
|
||||
tryUpdatePreview();
|
||||
return m_preview->pixmap().toImage();
|
||||
}
|
||||
|
||||
bool MetatileImageExporter::saveImage(QString filepath) {
|
||||
tryUpdatePreview();
|
||||
if (filepath.isEmpty()) {
|
||||
QString defaultFilepath = QString("%1/%2").arg(FileDialog::getDirectory()).arg(getDefaultFileName());
|
||||
filepath = FileDialog::getSaveFileName(this, windowTitle(), defaultFilepath, QStringLiteral("Image Files (*.png *.jpg *.bmp)"));
|
||||
if (filepath.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return m_preview->pixmap().save(filepath);
|
||||
}
|
||||
|
||||
QString MetatileImageExporter::getDefaultFileName() const {
|
||||
if (m_layerOrder.length() == 1) {
|
||||
// Exporting a metatile layer image is an expected use case for Porytiles, which expects certain file names.
|
||||
// We can make the process a little easier by setting the default file name to those expected file names.
|
||||
static const QStringList layerFilenames = { "bottom", "middle", "top" };
|
||||
return layerFilenames.at(m_layerOrder.constFirst()) + ".png";
|
||||
}
|
||||
|
||||
QString defaultFilename;
|
||||
if (ui->checkBox_PrimaryTileset->isChecked() && m_primaryTileset) {
|
||||
defaultFilename.append(QString("%1_").arg(Tileset::stripPrefix(m_primaryTileset->name)));
|
||||
}
|
||||
if (ui->checkBox_SecondaryTileset->isChecked() && m_secondaryTileset) {
|
||||
defaultFilename.append(QString("%1_").arg(Tileset::stripPrefix(m_secondaryTileset->name)));
|
||||
}
|
||||
if (!m_layerOrder.isEmpty() && m_layerOrder != QList<int>({0,1,2})) {
|
||||
for (int i = m_layerOrder.length() - 1; i >= 0; i--) {
|
||||
defaultFilename.append(Metatile::getLayerName(m_layerOrder.at(i)));
|
||||
}
|
||||
defaultFilename.append("_");
|
||||
}
|
||||
defaultFilename.append("Metatile");
|
||||
|
||||
uint16_t start = ui->spinBox_MetatileStart->value();
|
||||
uint16_t end = ui->spinBox_MetatileEnd->value();
|
||||
if (start != end) {
|
||||
defaultFilename.append("s");
|
||||
}
|
||||
if (!ui->checkBox_PrimaryTileset->isChecked() && !ui->checkBox_SecondaryTileset->isChecked()) {
|
||||
defaultFilename.append(QString("_%1").arg(Metatile::getMetatileIdString(start)));
|
||||
if (start != end) {
|
||||
defaultFilename.append(QString("-%1").arg(Metatile::getMetatileIdString(end)));
|
||||
}
|
||||
}
|
||||
return QString("%1.png").arg(defaultFilename);
|
||||
}
|
||||
|
||||
void MetatileImageExporter::queuePreviewUpdate() {
|
||||
m_previewUpdateQueued = true;
|
||||
}
|
||||
|
||||
// For updating only when a change has been recorded.
|
||||
// Useful for something that might happen often, like an input widget losing focus.
|
||||
void MetatileImageExporter::tryUpdatePreview() {
|
||||
if (m_preview->pixmap().isNull() || m_previewUpdateQueued) {
|
||||
updatePreview();
|
||||
}
|
||||
}
|
||||
|
||||
void MetatileImageExporter::updatePreview() {
|
||||
copyRenderSettings();
|
||||
|
||||
m_layerOrder.clear();
|
||||
for (int i = 0; i < ui->listWidget_Layers->count(); i++) {
|
||||
auto item = ui->listWidget_Layers->item(i);
|
||||
if (item->checkState() == Qt::Checked) {
|
||||
int layerNum = item->data(Qt::UserRole).toInt();
|
||||
m_layerOrder.prepend(qBound(0, layerNum, 2));
|
||||
}
|
||||
}
|
||||
|
||||
QImage previewImage;
|
||||
if (ui->checkBox_PrimaryTileset->isChecked() && ui->checkBox_SecondaryTileset->isChecked()) {
|
||||
// Special behavior to combine the two tilesets while skipping the unused region between tilesets.
|
||||
previewImage = getMetatileSheetImage(m_primaryTileset,
|
||||
m_secondaryTileset,
|
||||
ui->spinBox_WidthMetatiles->value(),
|
||||
m_layerOrder);
|
||||
} else {
|
||||
previewImage = getMetatileSheetImage(m_primaryTileset,
|
||||
m_secondaryTileset,
|
||||
ui->spinBox_MetatileStart->value(),
|
||||
ui->spinBox_MetatileEnd->value(),
|
||||
ui->spinBox_WidthMetatiles->value(),
|
||||
m_layerOrder);
|
||||
}
|
||||
|
||||
m_preview->setPixmap(QPixmap::fromImage(previewImage));
|
||||
m_scene->setSceneRect(m_scene->itemsBoundingRect());
|
||||
m_previewUpdateQueued = false;
|
||||
|
||||
restoreRenderSettings();
|
||||
}
|
||||
|
||||
void MetatileImageExporter::validateMetatileStart() {
|
||||
const QSignalBlocker b(ui->spinBox_MetatileStart);
|
||||
ui->spinBox_MetatileStart->setValue(qMin(ui->spinBox_MetatileStart->value(),
|
||||
ui->spinBox_MetatileEnd->value()));
|
||||
}
|
||||
|
||||
void MetatileImageExporter::validateMetatileEnd() {
|
||||
const QSignalBlocker b(ui->spinBox_MetatileEnd);
|
||||
ui->spinBox_MetatileEnd->setValue(qMax(ui->spinBox_MetatileStart->value(),
|
||||
ui->spinBox_MetatileEnd->value()));
|
||||
}
|
||||
|
||||
void MetatileImageExporter::updateMetatileRange() {
|
||||
uint16_t min;
|
||||
uint16_t max;
|
||||
if (ui->checkBox_PrimaryTileset->isChecked() && m_primaryTileset) {
|
||||
if (ui->checkBox_SecondaryTileset->isChecked() && m_secondaryTileset) {
|
||||
// Both tilesets enforced
|
||||
min = qMin(m_primaryTileset->firstMetatileId(), m_secondaryTileset->firstMetatileId());
|
||||
max = qMax(m_primaryTileset->lastMetatileId(), m_secondaryTileset->lastMetatileId());
|
||||
} else {
|
||||
// Primary enforced
|
||||
min = m_primaryTileset->firstMetatileId();
|
||||
max = m_primaryTileset->lastMetatileId();
|
||||
}
|
||||
} else if (ui->checkBox_SecondaryTileset->isChecked() && m_secondaryTileset) {
|
||||
// Secondary enforced
|
||||
min = m_secondaryTileset->firstMetatileId();
|
||||
max = m_secondaryTileset->lastMetatileId();
|
||||
} else {
|
||||
// No tilesets enforced
|
||||
return;
|
||||
}
|
||||
|
||||
const QSignalBlocker b_MetatileStart(ui->spinBox_MetatileStart);
|
||||
const QSignalBlocker b_MetatileEnd(ui->spinBox_MetatileEnd);
|
||||
ui->spinBox_MetatileStart->setValue(min);
|
||||
ui->spinBox_MetatileEnd->setValue(max);
|
||||
}
|
||||
|
||||
void MetatileImageExporter::tryEnforceMetatileRange() {
|
||||
// Users can either specify which tileset(s) to render, or specify a range of metatiles, but not both.
|
||||
if (ui->checkBox_PrimaryTileset->isChecked() || ui->checkBox_SecondaryTileset->isChecked()) {
|
||||
updateMetatileRange();
|
||||
ui->groupBox_MetatileRange->setDisabled(true);
|
||||
} else {
|
||||
ui->groupBox_MetatileRange->setDisabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void MetatileImageExporter::syncPixelWidth() {
|
||||
const QSignalBlocker b(ui->spinBox_WidthPixels);
|
||||
ui->spinBox_WidthPixels->setValue(ui->spinBox_WidthMetatiles->value() * Metatile::pixelWidth());
|
||||
}
|
||||
|
||||
void MetatileImageExporter::syncMetatileWidth() {
|
||||
const QSignalBlocker b(ui->spinBox_WidthMetatiles);
|
||||
ui->spinBox_WidthMetatiles->setValue(Util::roundUpToMultiple(ui->spinBox_WidthPixels->value(), Metatile::pixelWidth()) / Metatile::pixelWidth());
|
||||
}
|
||||
|
||||
// These settings control some rendering behavior that make metatiles render accurately to their in-game appearance,
|
||||
// which may be undesirable when exporting metatile images for editing.
|
||||
// The settings are buried in getMetatileImage at the moment, to change them we'll temporarily overwrite them.
|
||||
void MetatileImageExporter::copyRenderSettings() {
|
||||
m_savedConfig.transparencyColor = projectConfig.transparencyColor;
|
||||
m_savedConfig.unusedTileNormal = projectConfig.unusedTileNormal;
|
||||
m_savedConfig.unusedTileCovered = projectConfig.unusedTileCovered;
|
||||
m_savedConfig.unusedTileSplit = projectConfig.unusedTileSplit;
|
||||
|
||||
if (ui->radioButton_TransparencyNormal->isChecked()) {
|
||||
projectConfig.transparencyColor = QColor(Qt::transparent);
|
||||
} else if (ui->radioButton_TransparencyBlack->isChecked()) {
|
||||
projectConfig.transparencyColor = QColor(Qt::black);
|
||||
} else {
|
||||
projectConfig.transparencyColor = QColor();
|
||||
}
|
||||
|
||||
if (!ui->checkBox_Placeholders->isChecked()) {
|
||||
projectConfig.unusedTileNormal = 0;
|
||||
projectConfig.unusedTileCovered = 0;
|
||||
projectConfig.unusedTileSplit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void MetatileImageExporter::restoreRenderSettings() {
|
||||
projectConfig.transparencyColor = m_savedConfig.transparencyColor;
|
||||
projectConfig.unusedTileNormal = m_savedConfig.unusedTileNormal;
|
||||
projectConfig.unusedTileCovered = m_savedConfig.unusedTileCovered;
|
||||
projectConfig.unusedTileSplit = m_savedConfig.unusedTileSplit;
|
||||
}
|
||||
|
|
@ -3,40 +3,89 @@
|
|||
#include "imageproviders.h"
|
||||
#include <QPainter>
|
||||
|
||||
static const QList<QPoint> tilePositions = {
|
||||
QPoint(0, 0),
|
||||
QPoint(1, 0),
|
||||
QPoint(0, 1),
|
||||
QPoint(1, 1),
|
||||
QPoint(2, 0),
|
||||
QPoint(3, 0),
|
||||
QPoint(2, 1),
|
||||
QPoint(3, 1),
|
||||
QPoint(4, 0),
|
||||
QPoint(5, 0),
|
||||
QPoint(4, 1),
|
||||
QPoint(5, 1),
|
||||
};
|
||||
MetatileLayersItem::MetatileLayersItem(Metatile *metatile, Tileset *primaryTileset, Tileset *secondaryTileset, Qt::Orientation orientation)
|
||||
: SelectablePixmapItem(16, 16, Metatile::tileWidth(), Metatile::tileHeight()),
|
||||
metatile(metatile),
|
||||
primaryTileset(primaryTileset),
|
||||
secondaryTileset(secondaryTileset)
|
||||
{
|
||||
setAcceptHoverEvents(true);
|
||||
setOrientation(orientation);
|
||||
}
|
||||
|
||||
void MetatileLayersItem::setOrientation(Qt::Orientation orientation) {
|
||||
if (this->orientation == orientation)
|
||||
return;
|
||||
this->orientation = orientation;
|
||||
int maxWidth = Metatile::tileWidth();
|
||||
int maxHeight = Metatile::tileHeight();
|
||||
|
||||
// Generate a table of tile positions that allows us to map between
|
||||
// the index of a tile in the metatile and its position in this layer view.
|
||||
this->tilePositions.clear();
|
||||
if (this->orientation == Qt::Horizontal) {
|
||||
// Tiles are laid out horizontally, with the bottom layer on the left:
|
||||
// 0 1 4 5 8 9
|
||||
// 2 3 6 7 10 11
|
||||
for (int layer = 0; layer < projectConfig.getNumLayersInMetatile(); layer++)
|
||||
for (int y = 0; y < Metatile::tileHeight(); y++)
|
||||
for (int x = 0; x < Metatile::tileWidth(); x++) {
|
||||
this->tilePositions.append(QPoint(x + layer * Metatile::tileWidth(), y));
|
||||
}
|
||||
maxWidth *= projectConfig.getNumLayersInMetatile();
|
||||
} else if (this->orientation == Qt::Vertical) {
|
||||
// Tiles are laid out vertically, with the bottom layer on the bottom:
|
||||
// 8 9
|
||||
// 10 11
|
||||
// 4 5
|
||||
// 6 7
|
||||
// 0 1
|
||||
// 2 3
|
||||
for (int layer = projectConfig.getNumLayersInMetatile() - 1; layer >= 0; layer--)
|
||||
for (int y = 0; y < Metatile::tileHeight(); y++)
|
||||
for (int x = 0; x < Metatile::tileWidth(); x++) {
|
||||
this->tilePositions.append(QPoint(x, y + layer * Metatile::tileHeight()));
|
||||
}
|
||||
maxHeight *= projectConfig.getNumLayersInMetatile();
|
||||
}
|
||||
setMaxSelectionSize(maxWidth, maxHeight);
|
||||
update();
|
||||
if (!this->pixmap().isNull()) {
|
||||
draw();
|
||||
}
|
||||
}
|
||||
|
||||
void MetatileLayersItem::draw() {
|
||||
const int numLayers = projectConfig.getNumLayersInMetatile();
|
||||
QPixmap pixmap(numLayers * 32, 32);
|
||||
QPixmap pixmap(this->cellWidth * this->maxSelectionWidth, this->cellHeight * this->maxSelectionHeight);
|
||||
QPainter painter(&pixmap);
|
||||
|
||||
// Draw tile images
|
||||
int numTiles = qMin(projectConfig.getNumTilesInMetatile(), this->metatile ? this->metatile->tiles.length() : 0);
|
||||
for (int i = 0; i < numTiles; i++) {
|
||||
Tile tile = this->metatile->tiles.at(i);
|
||||
QImage tileImage = getPalettedTileImage(tile.tileId, this->primaryTileset, this->secondaryTileset, tile.palette, true).scaled(16, 16);
|
||||
QImage tileImage = getPalettedTileImage(tile.tileId,
|
||||
this->primaryTileset,
|
||||
this->secondaryTileset,
|
||||
tile.palette,
|
||||
true
|
||||
).scaled(this->cellWidth, this->cellHeight);
|
||||
tile.flip(&tileImage);
|
||||
painter.drawImage(tilePositions.at(i) * 16, tileImage);
|
||||
QPoint pos = tileIndexToPos(i);
|
||||
painter.drawImage(pos.x() * this->cellWidth, pos.y() * this->cellHeight, tileImage);
|
||||
}
|
||||
if (this->showGrid) {
|
||||
// Draw grid
|
||||
painter.setPen(Qt::white);
|
||||
for (int i = 1; i < numLayers; i++) {
|
||||
int x = i * 32;
|
||||
painter.drawLine(x, 0, x, 32);
|
||||
const int layerWidth = this->cellWidth * Metatile::tileWidth();
|
||||
const int layerHeight = this->cellHeight * Metatile::tileHeight();
|
||||
for (int i = 1; i < projectConfig.getNumLayersInMetatile(); i++) {
|
||||
if (this->orientation == Qt::Vertical) {
|
||||
int y = i * layerHeight;
|
||||
painter.drawLine(0, y, layerWidth, y);
|
||||
} else if (this->orientation == Qt::Horizontal) {
|
||||
int x = i * layerWidth;
|
||||
painter.drawLine(x, 0, x, layerHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -45,95 +94,88 @@ void MetatileLayersItem::draw() {
|
|||
|
||||
void MetatileLayersItem::setMetatile(Metatile *metatile) {
|
||||
this->metatile = metatile;
|
||||
this->clearLastModifiedCoords();
|
||||
this->clearLastHoveredCoords();
|
||||
draw();
|
||||
}
|
||||
|
||||
void MetatileLayersItem::setTilesets(Tileset *primaryTileset, Tileset *secondaryTileset) {
|
||||
this->primaryTileset = primaryTileset;
|
||||
this->secondaryTileset = secondaryTileset;
|
||||
this->draw();
|
||||
this->clearLastModifiedCoords();
|
||||
this->clearLastHoveredCoords();
|
||||
}
|
||||
|
||||
void MetatileLayersItem::updateSelection() {
|
||||
drawSelection();
|
||||
emit selectedTilesChanged(getSelectionStart(), getSelectionDimensions());
|
||||
}
|
||||
|
||||
void MetatileLayersItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
|
||||
const QPoint pos = getBoundedPos(event->pos());
|
||||
setCursorCellPos(pos);
|
||||
|
||||
if (event->buttons() & Qt::RightButton) {
|
||||
SelectablePixmapItem::mousePressEvent(event);
|
||||
QPoint selectionOrigin = this->getSelectionStart();
|
||||
QPoint dimensions = this->getSelectionDimensions();
|
||||
emit this->selectedTilesChanged(selectionOrigin, dimensions.x(), dimensions.y());
|
||||
this->drawSelection();
|
||||
updateSelection();
|
||||
} else if (event->modifiers() & Qt::ControlModifier) {
|
||||
emit paletteChanged(pos);
|
||||
} else {
|
||||
const QPoint pos = this->getBoundedPos(event->pos());
|
||||
this->prevChangedPos = pos;
|
||||
this->clearLastHoveredCoords();
|
||||
emit this->tileChanged(pos.x(), pos.y());
|
||||
emit tileChanged(pos);
|
||||
}
|
||||
}
|
||||
|
||||
void MetatileLayersItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
|
||||
const QPoint pos = getBoundedPos(event->pos());
|
||||
if (!setCursorCellPos(pos))
|
||||
return;
|
||||
|
||||
if (event->buttons() & Qt::RightButton) {
|
||||
SelectablePixmapItem::mouseMoveEvent(event);
|
||||
QPoint selectionOrigin = this->getSelectionStart();
|
||||
QPoint dimensions = this->getSelectionDimensions();
|
||||
emit this->selectedTilesChanged(selectionOrigin, dimensions.x(), dimensions.y());
|
||||
this->drawSelection();
|
||||
updateSelection();
|
||||
} else if (event->modifiers() & Qt::ControlModifier) {
|
||||
emit paletteChanged(pos);
|
||||
} else {
|
||||
const QPoint pos = this->getBoundedPos(event->pos());
|
||||
if (prevChangedPos != pos) {
|
||||
this->prevChangedPos = pos;
|
||||
this->clearLastHoveredCoords();
|
||||
emit this->tileChanged(pos.x(), pos.y());
|
||||
}
|
||||
emit tileChanged(pos);
|
||||
}
|
||||
}
|
||||
|
||||
void MetatileLayersItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
|
||||
if (event->buttons() & Qt::RightButton) {
|
||||
SelectablePixmapItem::mouseReleaseEvent(event);
|
||||
QPoint selectionOrigin = this->getSelectionStart();
|
||||
QPoint dimensions = this->getSelectionDimensions();
|
||||
emit this->selectedTilesChanged(selectionOrigin, dimensions.x(), dimensions.y());
|
||||
updateSelection();
|
||||
}
|
||||
|
||||
this->draw();
|
||||
// Clear selection rectangle
|
||||
draw();
|
||||
}
|
||||
|
||||
void MetatileLayersItem::hoverMoveEvent(QGraphicsSceneHoverEvent * event) {
|
||||
const QPoint pos = this->getBoundedPos(event->pos());
|
||||
if (pos == this->prevHoveredPos)
|
||||
return;
|
||||
this->prevHoveredPos = pos;
|
||||
setCursorCellPos(getBoundedPos(event->pos()));
|
||||
}
|
||||
|
||||
int tileIndex = tilePositions.indexOf(pos);
|
||||
if (tileIndex < 0 || tileIndex >= this->metatile->tiles.length())
|
||||
return;
|
||||
bool MetatileLayersItem::setCursorCellPos(const QPoint &pos) {
|
||||
if (this->cursorCellPos == pos)
|
||||
return false;
|
||||
this->cursorCellPos = pos;
|
||||
|
||||
emit this->hoveredTileChanged(this->metatile->tiles.at(tileIndex).tileId);
|
||||
emit this->hoveredTileChanged(tileUnderCursor());
|
||||
return true;
|
||||
}
|
||||
|
||||
void MetatileLayersItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *) {
|
||||
this->clearLastHoveredCoords();
|
||||
this->cursorCellPos = QPoint(-1,-1);
|
||||
emit this->hoveredTileCleared();
|
||||
}
|
||||
|
||||
void MetatileLayersItem::clearLastModifiedCoords() {
|
||||
this->prevChangedPos = QPoint(-1, -1);
|
||||
}
|
||||
|
||||
void MetatileLayersItem::clearLastHoveredCoords() {
|
||||
this->prevHoveredPos = QPoint(-1, -1);
|
||||
Tile MetatileLayersItem::tileUnderCursor() const {
|
||||
int tileIndex = posToTileIndex(this->cursorCellPos);
|
||||
if (tileIndex < 0 || !this->metatile || tileIndex >= this->metatile->tiles.length()) {
|
||||
return Tile();
|
||||
}
|
||||
return this->metatile->tiles.at(tileIndex);
|
||||
}
|
||||
|
||||
QPoint MetatileLayersItem::getBoundedPos(const QPointF &pos) {
|
||||
int x, y;
|
||||
int maxX = (projectConfig.getNumLayersInMetatile() * 2) - 1;
|
||||
x = static_cast<int>(pos.x()) / 16;
|
||||
y = static_cast<int>(pos.y()) / 16;
|
||||
if (x < 0) x = 0;
|
||||
if (y < 0) y = 0;
|
||||
if (x > maxX) x = maxX;
|
||||
if (y > 1) y = 1;
|
||||
return QPoint(x, y);
|
||||
int x = static_cast<int>(pos.x()) / this->cellWidth;
|
||||
int y = static_cast<int>(pos.y()) / this->cellHeight;
|
||||
return QPoint(qBound(0, x, this->maxSelectionWidth - 1),
|
||||
qBound(0, y, this->maxSelectionHeight - 1));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,40 +3,20 @@
|
|||
#include "project.h"
|
||||
#include <QPainter>
|
||||
|
||||
QPoint MetatileSelector::getSelectionDimensions() {
|
||||
QSize MetatileSelector::getSelectionDimensions() const {
|
||||
if (this->prefabSelection || this->externalSelection)
|
||||
return selection.dimensions;
|
||||
return SelectablePixmapItem::getSelectionDimensions();
|
||||
}
|
||||
|
||||
int MetatileSelector::numPrimaryMetatilesRounded() const {
|
||||
// We round up the number of primary metatiles to keep the tilesets on separate rows.
|
||||
return ceil((double)this->primaryTileset->numMetatiles() / this->numMetatilesWide) * this->numMetatilesWide;
|
||||
if (!primaryTileset())
|
||||
return 0;
|
||||
return Util::roundUpToMultiple(primaryTileset()->numMetatiles(), this->numMetatilesWide);
|
||||
}
|
||||
|
||||
void MetatileSelector::updateBasePixmap() {
|
||||
int primaryLength = this->numPrimaryMetatilesRounded();
|
||||
int length_ = primaryLength + this->secondaryTileset->numMetatiles();
|
||||
int height_ = length_ / this->numMetatilesWide;
|
||||
if (length_ % this->numMetatilesWide != 0) {
|
||||
height_++;
|
||||
}
|
||||
QImage image(this->numMetatilesWide * 16, height_ * 16, QImage::Format_RGBA8888);
|
||||
image.fill(Qt::magenta);
|
||||
QPainter painter(&image);
|
||||
for (int i = 0; i < length_; i++) {
|
||||
int tile = i;
|
||||
if (i >= primaryLength) {
|
||||
tile += Project::getNumMetatilesPrimary() - primaryLength;
|
||||
}
|
||||
QImage metatile_image = getMetatileImage(tile, this->primaryTileset, this->secondaryTileset, layout->metatileLayerOrder, layout->metatileLayerOpacity);
|
||||
int map_y = i / this->numMetatilesWide;
|
||||
int map_x = i % this->numMetatilesWide;
|
||||
QPoint metatile_origin = QPoint(map_x * 16, map_y * 16);
|
||||
painter.drawImage(metatile_origin, metatile_image);
|
||||
}
|
||||
painter.end();
|
||||
this->basePixmap = QPixmap::fromImage(image);
|
||||
this->basePixmap = QPixmap::fromImage(getMetatileSheetImage(this->layout, this->numMetatilesWide));
|
||||
}
|
||||
|
||||
void MetatileSelector::draw() {
|
||||
|
|
@ -53,17 +33,20 @@ void MetatileSelector::drawSelection() {
|
|||
}
|
||||
|
||||
bool MetatileSelector::select(uint16_t metatileId) {
|
||||
if (!Tileset::metatileIsValid(metatileId, this->primaryTileset, this->secondaryTileset)) return false;
|
||||
bool ok;
|
||||
QPoint pos = metatileIdToPos(metatileId, &ok);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
this->externalSelection = false;
|
||||
this->prefabSelection = false;
|
||||
this->selection = MetatileSelection{
|
||||
QPoint(1, 1),
|
||||
QSize(1, 1),
|
||||
false,
|
||||
QList<MetatileSelectionItem>({MetatileSelectionItem{true, metatileId}}),
|
||||
QList<CollisionSelectionItem>(),
|
||||
};
|
||||
QPoint coords = this->getMetatileIdCoords(metatileId);
|
||||
SelectablePixmapItem::select(coords.x(), coords.y(), 0, 0);
|
||||
SelectablePixmapItem::select(pos);
|
||||
this->updateSelectedMetatiles();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -73,9 +56,8 @@ void MetatileSelector::selectFromMap(uint16_t metatileId, uint16_t collision, ui
|
|||
this->setExternalSelection(1, 1, {metatileId}, {movePermissions});
|
||||
}
|
||||
|
||||
void MetatileSelector::setTilesets(Tileset *primaryTileset, Tileset *secondaryTileset) {
|
||||
this->primaryTileset = primaryTileset;
|
||||
this->secondaryTileset = secondaryTileset;
|
||||
void MetatileSelector::setLayout(Layout *layout) {
|
||||
this->layout = layout;
|
||||
if (this->externalSelection)
|
||||
this->updateExternalSelectedMetatiles();
|
||||
else
|
||||
|
|
@ -85,11 +67,11 @@ void MetatileSelector::setTilesets(Tileset *primaryTileset, Tileset *secondaryTi
|
|||
draw();
|
||||
}
|
||||
|
||||
MetatileSelection MetatileSelector::getMetatileSelection() {
|
||||
return selection;
|
||||
void MetatileSelector::refresh() {
|
||||
setLayout(this->layout);
|
||||
}
|
||||
|
||||
void MetatileSelector::setExternalSelection(int width, int height, QList<uint16_t> metatiles, QList<QPair<uint16_t, uint16_t>> collisions) {
|
||||
void MetatileSelector::setExternalSelection(int width, int height, const QList<uint16_t> &metatiles, const QList<QPair<uint16_t, uint16_t>> &collisions) {
|
||||
this->prefabSelection = false;
|
||||
this->externalSelection = true;
|
||||
this->externalSelectionWidth = width;
|
||||
|
|
@ -98,19 +80,19 @@ void MetatileSelector::setExternalSelection(int width, int height, QList<uint16_
|
|||
this->selection.metatileItems.clear();
|
||||
this->selection.collisionItems.clear();
|
||||
this->selection.hasCollision = true;
|
||||
this->selection.dimensions = QPoint(width, height);
|
||||
for (int i = 0; i < metatiles.length(); i++) {
|
||||
auto collision = collisions.at(i);
|
||||
this->selection.collisionItems.append(CollisionSelectionItem{true, collision.first, collision.second});
|
||||
this->selection.dimensions = QSize(width, height);
|
||||
for (int i = 0; i < qMin(metatiles.length(), collisions.length()); i++) {
|
||||
uint16_t metatileId = metatiles.at(i);
|
||||
uint16_t collision = collisions.at(i).first;
|
||||
uint16_t elevation = collisions.at(i).second;
|
||||
this->selection.collisionItems.append(CollisionSelectionItem{true, collision, elevation});
|
||||
this->externalSelectedMetatiles.append(metatileId);
|
||||
if (!Tileset::metatileIsValid(metatileId, this->primaryTileset, this->secondaryTileset))
|
||||
if (!this->layout->metatileIsValid(metatileId))
|
||||
metatileId = 0;
|
||||
this->selection.metatileItems.append(MetatileSelectionItem{true, metatileId});
|
||||
}
|
||||
if (this->selection.metatileItems.length() == 1) {
|
||||
QPoint coords = this->getMetatileIdCoords(this->selection.metatileItems.first().metatileId);
|
||||
SelectablePixmapItem::select(coords.x(), coords.y(), 0, 0);
|
||||
SelectablePixmapItem::select(metatileIdToPos(this->selection.metatileItems.first().metatileId));
|
||||
}
|
||||
|
||||
this->draw();
|
||||
|
|
@ -127,7 +109,9 @@ void MetatileSelector::setPrefabSelection(MetatileSelection selection) {
|
|||
}
|
||||
|
||||
bool MetatileSelector::positionIsValid(const QPoint &pos) const {
|
||||
return Tileset::metatileIsValid(getMetatileId(pos.x(), pos.y()), this->primaryTileset, this->secondaryTileset);
|
||||
bool ok;
|
||||
posToMetatileId(pos, &ok);
|
||||
return ok;
|
||||
}
|
||||
|
||||
void MetatileSelector::mousePressEvent(QGraphicsSceneMouseEvent *event) {
|
||||
|
|
@ -168,8 +152,14 @@ void MetatileSelector::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
|
|||
}
|
||||
|
||||
void MetatileSelector::hoverChanged() {
|
||||
uint16_t metatileId = this->getMetatileId(this->cellPos.x(), this->cellPos.y());
|
||||
emit this->hoveredMetatileSelectionChanged(metatileId);
|
||||
bool ok;
|
||||
uint16_t metatileId = posToMetatileId(this->cellPos, &ok);
|
||||
if (ok) {
|
||||
emit this->hoveredMetatileSelectionChanged(metatileId);
|
||||
} else {
|
||||
emit this->hoveredMetatileSelectionCleared();
|
||||
this->cellPos = QPoint(-1, -1);
|
||||
}
|
||||
}
|
||||
|
||||
void MetatileSelector::hoverLeaveEvent(QGraphicsSceneHoverEvent*) {
|
||||
|
|
@ -185,11 +175,9 @@ void MetatileSelector::updateSelectedMetatiles() {
|
|||
this->selection.hasCollision = false;
|
||||
this->selection.dimensions = this->getSelectionDimensions();
|
||||
QPoint origin = this->getSelectionStart();
|
||||
for (int j = 0; j < this->selection.dimensions.y(); j++) {
|
||||
for (int i = 0; i < this->selection.dimensions.x(); i++) {
|
||||
uint16_t metatileId = this->getMetatileId(origin.x() + i, origin.y() + j);
|
||||
if (!Tileset::metatileIsValid(metatileId, this->primaryTileset, this->secondaryTileset))
|
||||
metatileId = 0;
|
||||
for (int j = 0; j < this->selection.dimensions.height(); j++) {
|
||||
for (int i = 0; i < this->selection.dimensions.width(); i++) {
|
||||
uint16_t metatileId = posToMetatileId(origin.x() + i, origin.y() + j);
|
||||
this->selection.metatileItems.append(MetatileSelectionItem{true, metatileId});
|
||||
}
|
||||
}
|
||||
|
|
@ -198,46 +186,62 @@ void MetatileSelector::updateSelectedMetatiles() {
|
|||
|
||||
void MetatileSelector::updateExternalSelectedMetatiles() {
|
||||
this->selection.metatileItems.clear();
|
||||
this->selection.dimensions = QPoint(this->externalSelectionWidth, this->externalSelectionHeight);
|
||||
this->selection.dimensions = QSize(this->externalSelectionWidth, this->externalSelectionHeight);
|
||||
for (int i = 0; i < this->externalSelectedMetatiles.count(); ++i) {
|
||||
uint16_t metatileId = this->externalSelectedMetatiles.at(i);
|
||||
if (!Tileset::metatileIsValid(metatileId, this->primaryTileset, this->secondaryTileset))
|
||||
if (!this->layout->metatileIsValid(metatileId))
|
||||
metatileId = 0;
|
||||
this->selection.metatileItems.append(MetatileSelectionItem{true, metatileId});
|
||||
}
|
||||
emit selectedMetatilesChanged();
|
||||
}
|
||||
|
||||
uint16_t MetatileSelector::getMetatileId(int x, int y) const {
|
||||
uint16_t MetatileSelector::posToMetatileId(const QPoint &pos, bool *ok) const {
|
||||
return posToMetatileId(pos.x(), pos.y(), ok);
|
||||
}
|
||||
|
||||
uint16_t MetatileSelector::posToMetatileId(int x, int y, bool *ok) const {
|
||||
if (ok) *ok = true;
|
||||
int index = y * this->numMetatilesWide + x;
|
||||
int numPrimary = this->numPrimaryMetatilesRounded();
|
||||
if (index < numPrimary) {
|
||||
return static_cast<uint16_t>(index);
|
||||
} else {
|
||||
return static_cast<uint16_t>(Project::getNumMetatilesPrimary() + index - numPrimary);
|
||||
}
|
||||
}
|
||||
|
||||
QPoint MetatileSelector::getMetatileIdCoords(uint16_t metatileId) {
|
||||
if (!Tileset::metatileIsValid(metatileId, this->primaryTileset, this->secondaryTileset))
|
||||
{
|
||||
// Invalid metatile id.
|
||||
return QPoint(0, 0);
|
||||
uint16_t metatileId = static_cast<uint16_t>(index);
|
||||
if (primaryTileset() && primaryTileset()->containsMetatileId(metatileId)) {
|
||||
return metatileId;
|
||||
}
|
||||
|
||||
int index = metatileId < Project::getNumMetatilesPrimary()
|
||||
? metatileId
|
||||
: metatileId - Project::getNumMetatilesPrimary() + this->numPrimaryMetatilesRounded();
|
||||
return QPoint(index % this->numMetatilesWide, index / this->numMetatilesWide);
|
||||
// There's some extra handling here because we round the tilesets to keep them on separate rows.
|
||||
// This means if the maximum number of primary metatiles is not divisible by the metatile width
|
||||
// then the metatiles we used to round the primary tileset would have the index of valid secondary metatiles.
|
||||
// These need to be ignored, or they'll appear to be duplicates of the subseqeunt secondary metatiles.
|
||||
int numPrimaryRounded = numPrimaryMetatilesRounded();
|
||||
int firstSecondaryRow = numPrimaryRounded / this->numMetatilesWide;
|
||||
metatileId = static_cast<uint16_t>(Project::getNumMetatilesPrimary() + index - numPrimaryRounded);
|
||||
if (secondaryTileset() && secondaryTileset()->containsMetatileId(metatileId) && y >= firstSecondaryRow) {
|
||||
return metatileId;
|
||||
}
|
||||
|
||||
if (ok) *ok = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
QPoint MetatileSelector::getMetatileIdCoordsOnWidget(uint16_t metatileId) {
|
||||
QPoint pos = getMetatileIdCoords(metatileId);
|
||||
QPoint MetatileSelector::metatileIdToPos(uint16_t metatileId, bool *ok) const {
|
||||
if (primaryTileset() && primaryTileset()->containsMetatileId(metatileId)) {
|
||||
if (ok) *ok = true;
|
||||
int index = metatileId;
|
||||
return QPoint(index % this->numMetatilesWide, index / this->numMetatilesWide);
|
||||
}
|
||||
if (secondaryTileset() && secondaryTileset()->containsMetatileId(metatileId)) {
|
||||
if (ok) *ok = true;
|
||||
int index = metatileId - Project::getNumMetatilesPrimary() + numPrimaryMetatilesRounded();
|
||||
return QPoint(index % this->numMetatilesWide, index / this->numMetatilesWide);
|
||||
}
|
||||
|
||||
if (ok) *ok = false;
|
||||
return QPoint(0,0);
|
||||
}
|
||||
|
||||
QPoint MetatileSelector::getMetatileIdCoordsOnWidget(uint16_t metatileId) const {
|
||||
QPoint pos = metatileIdToPos(metatileId);
|
||||
pos.rx() = (pos.x() * this->cellWidth) + (this->cellWidth / 2);
|
||||
pos.ry() = (pos.y() * this->cellHeight) + (this->cellHeight / 2);
|
||||
return pos;
|
||||
}
|
||||
|
||||
void MetatileSelector::setLayout(Layout *layout) {
|
||||
this->layout = layout;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ static WildMonInfo encounterClipboard;
|
|||
|
||||
MonTabWidget::MonTabWidget(Editor *editor, QWidget *parent) : QTabWidget(parent) {
|
||||
this->editor = editor;
|
||||
connect(this, &MonTabWidget::edited, this->editor, &Editor::saveEncounterTabData);
|
||||
connect(this, &MonTabWidget::edited, this->editor, &Editor::wildMonTableEdited);
|
||||
|
||||
populate();
|
||||
this->tabBar()->installEventFilter(new WheelFilter(this));
|
||||
}
|
||||
|
|
@ -64,7 +67,7 @@ void MonTabWidget::paste(int index) {
|
|||
WildMonInfo newInfo = getDefaultMonInfo(this->editor->project->wildMonFields.at(index));
|
||||
combineEncounters(newInfo, encounterClipboard);
|
||||
populateTab(index, newInfo);
|
||||
emit editor->wildMonTableEdited();
|
||||
emit edited();
|
||||
}
|
||||
|
||||
void MonTabWidget::actionCopyTab(int index) {
|
||||
|
|
@ -88,15 +91,12 @@ void MonTabWidget::actionAddDeleteTab(int index) {
|
|||
if (activeTabs[index]) {
|
||||
// delete tab
|
||||
deactivateTab(index);
|
||||
editor->saveEncounterTabData();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// add tab
|
||||
populateTab(index, getDefaultMonInfo(editor->project->wildMonFields.at(index)));
|
||||
editor->saveEncounterTabData();
|
||||
setCurrentIndex(index);
|
||||
}
|
||||
emit editor->wildMonTableEdited();
|
||||
emit edited();
|
||||
}
|
||||
|
||||
void MonTabWidget::clearTableAt(int tabIndex) {
|
||||
|
|
@ -123,8 +123,7 @@ void MonTabWidget::populateTab(int tabIndex, WildMonInfo monInfo) {
|
|||
QTableView *speciesTable = tableAt(tabIndex);
|
||||
|
||||
EncounterTableModel *model = new EncounterTableModel(monInfo, editor->project->wildMonFields[tabIndex], this);
|
||||
connect(model, &EncounterTableModel::edited, editor, &Editor::saveEncounterTabData);
|
||||
connect(model, &EncounterTableModel::edited, editor, &Editor::wildMonTableEdited);
|
||||
connect(model, &EncounterTableModel::edited, this, &MonTabWidget::edited);
|
||||
speciesTable->setModel(model);
|
||||
|
||||
speciesTable->setItemDelegateForColumn(EncounterTableModel::ColumnType::Species, new SpeciesComboDelegate(editor->project, this));
|
||||
|
|
|
|||
|
|
@ -5,43 +5,32 @@
|
|||
#include "movablerect.h"
|
||||
#include "utility.h"
|
||||
|
||||
MovableRect::MovableRect(bool *enabled, const QRectF &rect, const QRgb &color)
|
||||
MovableRect::MovableRect(const QRectF &rect, const QSize &cellSize, const QRgb &color)
|
||||
: QGraphicsRectItem(rect),
|
||||
enabled(enabled),
|
||||
baseRect(rect),
|
||||
cellSize(cellSize),
|
||||
color(color)
|
||||
{
|
||||
updateVisibility();
|
||||
}
|
||||
{ }
|
||||
|
||||
/// Center rect on grid position (x, y)
|
||||
void MovableRect::updateLocation(int x, int y) {
|
||||
setRect(this->baseRect.x() + (x * 16),
|
||||
this->baseRect.y() + (y * 16),
|
||||
setRect(this->baseRect.x() + (x * this->cellSize.width()),
|
||||
this->baseRect.y() + (y * this->cellSize.height()),
|
||||
this->baseRect.width(),
|
||||
this->baseRect.height());
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
void MovableRect::setActive(bool active) {
|
||||
this->active = active;
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
void MovableRect::updateVisibility() {
|
||||
setVisible(*this->enabled && this->active);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
ResizableRect::ResizableRect(QObject *parent, bool *enabled, int width, int height, QRgb color)
|
||||
ResizableRect::ResizableRect(QObject *parent, const QSize &cellSize, const QSize &size, const QRgb &color)
|
||||
: QObject(parent),
|
||||
MovableRect(enabled, QRect(0, 0, width * 16, height * 16), color)
|
||||
MovableRect(QRect(0, 0, size.width(), size.height()), cellSize, color)
|
||||
{
|
||||
setAcceptHoverEvents(true);
|
||||
setFlags(this->flags() | QGraphicsItem::ItemIsMovable);
|
||||
setAcceptHoverEvents(true);
|
||||
setFlags(this->flags() | QGraphicsItem::ItemIsMovable);
|
||||
}
|
||||
|
||||
ResizableRect::Edge ResizableRect::detectEdge(int x, int y) {
|
||||
|
|
@ -126,8 +115,8 @@ void ResizableRect::mousePressEvent(QGraphicsSceneMouseEvent *event) {
|
|||
}
|
||||
|
||||
void ResizableRect::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
|
||||
int dx = Util::roundUp(event->scenePos().x() - this->clickedPos.x(), 16);
|
||||
int dy = Util::roundUp(event->scenePos().y() - this->clickedPos.y(), 16);
|
||||
int dx = Util::roundUpToMultiple(event->scenePos().x() - this->clickedPos.x(), this->cellSize.width());
|
||||
int dy = Util::roundUpToMultiple(event->scenePos().y() - this->clickedPos.y(), this->cellSize.height());
|
||||
|
||||
QRect resizedRect = this->clickedRect;
|
||||
|
||||
|
|
@ -161,20 +150,20 @@ void ResizableRect::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
|
|||
break;
|
||||
}
|
||||
|
||||
// Lower limits: smallest possible size is 16x16 square
|
||||
if (resizedRect.width() < 16) {
|
||||
// Lower limits: smallest possible size is 1 cell
|
||||
if (resizedRect.width() < this->cellSize.width()) {
|
||||
if (dx < 0) { // right sided adjustment made
|
||||
resizedRect.setWidth(16);
|
||||
resizedRect.setWidth(this->cellSize.width());
|
||||
} else { // left sided adjustment slightly more complicated
|
||||
int dxMax = this->clickedRect.right() - this->clickedRect.left() - 16;
|
||||
int dxMax = this->clickedRect.right() - this->clickedRect.left() - this->cellSize.width();
|
||||
resizedRect.adjust(dxMax - dx, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
if (resizedRect.height() < 16) {
|
||||
if (resizedRect.height() < this->cellSize.height()) {
|
||||
if (dy < 0) { // bottom
|
||||
resizedRect.setHeight(16);
|
||||
resizedRect.setHeight(this->cellSize.height());
|
||||
} else { // top
|
||||
int dyMax = this->clickedRect.bottom() - this->clickedRect.top() - 16;
|
||||
int dyMax = this->clickedRect.bottom() - this->clickedRect.top() - this->cellSize.height();
|
||||
resizedRect.adjust(0, dyMax - dy, 0, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,14 +137,6 @@ void MultiKeyEdit::addNewKeySequenceEdit() {
|
|||
connect(lineEdit, &QLineEdit::customContextMenuRequested,
|
||||
this, &MultiKeyEdit::customContextMenuRequested);
|
||||
|
||||
// Gross way to connect the line edit's clear button.
|
||||
auto actions = lineEdit->findChildren<QAction*>();
|
||||
if (!actions.isEmpty()) {
|
||||
connect(actions.first(), &QAction::triggered, this, [this, keySequenceEdit]() {
|
||||
removeOne(keySequenceEdit->keySequence());
|
||||
});
|
||||
}
|
||||
|
||||
layout()->addWidget(keySequenceEdit);
|
||||
this->keySequenceEdits.append(keySequenceEdit);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,10 +62,10 @@ void NewLayoutDialog::refresh() {
|
|||
if (this->layoutToCopy) {
|
||||
// If we're importing a layout then some settings will be enforced.
|
||||
ui->newLayoutForm->setSettings(this->layoutToCopy->settings());
|
||||
ui->newLayoutForm->setDisabled(true);
|
||||
ui->newLayoutForm->setDimensionsDisabled(true);
|
||||
} else {
|
||||
ui->newLayoutForm->setSettings(*settings);
|
||||
ui->newLayoutForm->setDisabled(false);
|
||||
ui->newLayoutForm->setDimensionsDisabled(false);
|
||||
}
|
||||
|
||||
ui->lineEdit_Name->setText(settings->name);
|
||||
|
|
|
|||
|
|
@ -40,10 +40,9 @@ void NewLayoutForm::initUi(Project *project) {
|
|||
}
|
||||
}
|
||||
|
||||
void NewLayoutForm::setDisabled(bool disabled) {
|
||||
void NewLayoutForm::setDimensionsDisabled(bool disabled) {
|
||||
ui->groupBox_MapDimensions->setDisabled(disabled);
|
||||
ui->groupBox_BorderDimensions->setDisabled(disabled);
|
||||
ui->groupBox_Tilesets->setDisabled(disabled);
|
||||
}
|
||||
|
||||
void NewLayoutForm::setSettings(const Layout::Settings &settings) {
|
||||
|
|
@ -111,7 +110,7 @@ bool NewLayoutForm::validatePrimaryTileset(bool allowEmpty) {
|
|||
if (name.isEmpty()) {
|
||||
if (!allowEmpty) errorText = QString("The Primary Tileset cannot be empty.");
|
||||
} else if (ui->comboBox_PrimaryTileset->findText(name) < 0) {
|
||||
errorText = QString("The Primary Tileset '%1' does not exist.").arg(ui->label_PrimaryTileset->text()).arg(name);
|
||||
errorText = QString("The Primary Tileset '%1' does not exist.").arg(name);
|
||||
}
|
||||
|
||||
bool isValid = errorText.isEmpty();
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user