mirror of
https://github.com/huderlem/porymap.git
synced 2026-09-07 08:25:20 -05:00
Merge pull request #761 from GriffinRichards/tileset-editor
Add some Tileset Editor requests
This commit is contained in:
@@ -173,6 +173,9 @@
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<action name="actionUndo">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Undo</string>
|
||||
</property>
|
||||
@@ -187,6 +190,9 @@
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRedo">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Redo</string>
|
||||
</property>
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>253</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,171 +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="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>
|
||||
<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>
|
||||
@@ -371,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>
|
||||
@@ -451,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>
|
||||
@@ -497,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">
|
||||
@@ -520,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>
|
||||
@@ -555,8 +786,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>446</width>
|
||||
<height>241</height>
|
||||
<width>458</width>
|
||||
<height>203</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
@@ -681,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"/>
|
||||
@@ -744,6 +984,9 @@
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionUndo">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Undo</string>
|
||||
</property>
|
||||
@@ -752,6 +995,9 @@
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRedo">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Redo</string>
|
||||
</property>
|
||||
@@ -776,6 +1022,9 @@
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionPaste">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Paste</string>
|
||||
</property>
|
||||
@@ -863,6 +1112,33 @@
|
||||
<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>
|
||||
|
||||
@@ -108,6 +108,7 @@ public:
|
||||
int metatilesZoom;
|
||||
int tilesetEditorMetatilesZoom;
|
||||
int tilesetEditorTilesZoom;
|
||||
Qt::Orientation tilesetEditorLayerOrientation;
|
||||
bool showPlayerView;
|
||||
bool showCursorTile;
|
||||
bool showBorder;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -124,10 +124,13 @@ public:
|
||||
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);
|
||||
|
||||
@@ -90,7 +90,11 @@ public:
|
||||
|
||||
uint16_t firstMetatileId() const;
|
||||
uint16_t lastMetatileId() const;
|
||||
bool contains(uint16_t metatileId) const { return metatileId >= firstMetatileId() && metatileId <= lastMetatileId(); }
|
||||
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;
|
||||
|
||||
@@ -109,6 +109,7 @@ public:
|
||||
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);
|
||||
|
||||
@@ -43,7 +43,8 @@ public:
|
||||
bool getSingleTileMode() const { return m_singleTileMode; }
|
||||
|
||||
void updateLocation(int x, int y);
|
||||
void updateSelectionSize(int width, int height);
|
||||
void updateSelectionSize(const QSize &size);
|
||||
void updateSelectionSize(int width, int height) { updateSelectionSize(QSize(width, height)); }
|
||||
|
||||
private:
|
||||
const QSize m_tileSize;
|
||||
|
||||
@@ -61,17 +61,17 @@ 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);
|
||||
|
||||
|
||||
@@ -9,23 +9,40 @@
|
||||
class MetatileLayersItem: public SelectablePixmapItem {
|
||||
Q_OBJECT
|
||||
public:
|
||||
MetatileLayersItem(Metatile *metatile, Tileset *primaryTileset, Tileset *secondaryTileset);
|
||||
MetatileLayersItem(Metatile *metatile,
|
||||
Tileset *primaryTileset,
|
||||
Tileset *secondaryTileset,
|
||||
Qt::Orientation orientation = Qt::Horizontal);
|
||||
void draw();
|
||||
void setTilesets(Tileset*, Tileset*);
|
||||
void setMetatile(Metatile*);
|
||||
void clearLastModifiedCoords();
|
||||
void clearLastHoveredCoords();
|
||||
|
||||
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;
|
||||
Qt::Orientation orientation;
|
||||
QPoint prevChangedPos;
|
||||
QPoint prevHoveredPos;
|
||||
|
||||
QList<QPoint> tilePositions;
|
||||
|
||||
QPoint getBoundedPos(const QPointF &);
|
||||
void updateSelection();
|
||||
void hover(const QPoint &pos);
|
||||
signals:
|
||||
void tileChanged(int, int);
|
||||
void selectedTilesChanged(QPoint, int, int);
|
||||
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:
|
||||
|
||||
@@ -22,7 +22,7 @@ struct CollisionSelectionItem
|
||||
|
||||
struct MetatileSelection
|
||||
{
|
||||
QPoint dimensions;
|
||||
QSize dimensions;
|
||||
bool hasCollision;
|
||||
QList<MetatileSelectionItem> metatileItems;
|
||||
QList<CollisionSelectionItem> collisionItems;
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
setAcceptHoverEvents(true);
|
||||
}
|
||||
|
||||
QPoint getSelectionDimensions() const override;
|
||||
QSize getSelectionDimensions() const override;
|
||||
void draw() override;
|
||||
void refresh();
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ private:
|
||||
Tileset *secondaryTileset;
|
||||
|
||||
QList<ColorInputWidget*> colorInputs;
|
||||
QList<History<PaletteHistoryItem*>> palettesHistory;
|
||||
QMap<int, History<PaletteHistoryItem*>> palettesHistory;
|
||||
QMap<int,QSet<int>> unusedColorCache;
|
||||
QPointer<PaletteColorSearch> colorSearchWindow;
|
||||
|
||||
@@ -53,6 +53,7 @@ private:
|
||||
void refreshPaletteId();
|
||||
void commitEditHistory();
|
||||
void commitEditHistory(int paletteId);
|
||||
void updateEditHistoryActions();
|
||||
void restoreWindowState();
|
||||
void invalidateCache();
|
||||
void closeEvent(QCloseEvent*);
|
||||
|
||||
@@ -19,9 +19,15 @@ public:
|
||||
selectionOffsetX(0),
|
||||
selectionOffsetY(0)
|
||||
{}
|
||||
virtual QPoint getSelectionDimensions() const;
|
||||
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;
|
||||
@@ -33,17 +39,28 @@ protected:
|
||||
int selectionOffsetY;
|
||||
|
||||
QPoint getSelectionStart();
|
||||
void select(int x, int y, int width = 0, int height = 0);
|
||||
void select(const QPoint &pos, const QSize &size = QSize(0,0)) { select(pos.x(), pos.y(), size.width(), size.height()); }
|
||||
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
|
||||
|
||||
@@ -20,6 +20,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;
|
||||
@@ -27,15 +28,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
|
||||
@@ -69,8 +79,7 @@ private slots:
|
||||
void onHoveredTileChanged(const Tile&);
|
||||
void onHoveredTileChanged(uint16_t);
|
||||
void onHoveredTileCleared();
|
||||
void onMetatileLayerTileChanged(int, int);
|
||||
void onMetatileLayerSelectionChanged(QPoint, int, int);
|
||||
void onMetatileLayerSelectionChanged(const QPoint&, const QSize&);
|
||||
void onPaletteEditorChangedPaletteColor();
|
||||
|
||||
void on_actionChange_Metatiles_Count_triggered();
|
||||
@@ -87,9 +96,7 @@ private slots:
|
||||
void on_actionUndo_triggered();
|
||||
void on_actionRedo_triggered();
|
||||
|
||||
void on_lineEdit_metatileLabel_editingFinished();
|
||||
|
||||
void on_copyButton_metatileLabel_clicked();
|
||||
void on_copyButton_MetatileLabel_clicked();
|
||||
|
||||
void on_actionCut_triggered();
|
||||
void on_actionCopy_triggered();
|
||||
@@ -123,8 +130,8 @@ private:
|
||||
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);
|
||||
@@ -135,9 +142,19 @@ private:
|
||||
void commitEncounterType();
|
||||
void commitTerrainType();
|
||||
void commitLayerType();
|
||||
void commit(MetatileHistoryItem *item);
|
||||
void updateEditHistoryActions();
|
||||
void setRawAttributesVisible(bool visible);
|
||||
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);
|
||||
|
||||
Ui::TilesetEditor *ui;
|
||||
History<MetatileHistoryItem*> metatileHistory;
|
||||
@@ -161,6 +178,8 @@ private:
|
||||
bool lockSelection = false;
|
||||
QSet<uint16_t> metatileReloadQueue;
|
||||
MetatileImageExporter::Settings *metatileImageExportSettings = nullptr;
|
||||
QList<QPair<uint16_t,uint16_t>> metatileIdSwaps;
|
||||
int numLayerViewRows;
|
||||
|
||||
bool save();
|
||||
|
||||
|
||||
@@ -19,9 +19,13 @@ public:
|
||||
bool select(uint16_t metatileId);
|
||||
void setTilesets(Tileset*, Tileset*);
|
||||
uint16_t getSelectedMetatileId() const { return this->selectedMetatileId; }
|
||||
void updateSelectedMetatile();
|
||||
QPoint getMetatileIdCoordsOnWidget(uint16_t metatileId) const;
|
||||
|
||||
void setSwapMode(bool enabeled);
|
||||
void addToSwapSelection(uint16_t metatileId);
|
||||
void removeFromSwapSelection(uint16_t metatileId);
|
||||
void clearSwapSelection();
|
||||
|
||||
QVector<uint16_t> usedMetatiles;
|
||||
bool selectorShowUnused = false;
|
||||
bool selectorShowCounts = false;
|
||||
@@ -41,12 +45,18 @@ private:
|
||||
QPixmap basePixmap;
|
||||
Tileset *primaryTileset = nullptr;
|
||||
Tileset *secondaryTileset = nullptr;
|
||||
uint16_t selectedMetatileId;
|
||||
uint16_t selectedMetatileId = 0;
|
||||
QPoint prevCellPos = QPoint(-1,-1);
|
||||
|
||||
QList<uint16_t> swapMetatileIds;
|
||||
uint16_t lastHoveredMetatileId = 0;
|
||||
bool inSwapMode = false;
|
||||
|
||||
void updateBasePixmap();
|
||||
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 shouldAcceptEvent(QGraphicsSceneMouseEvent*);
|
||||
bool isValidMetatileId(uint16_t metatileId) const;
|
||||
int numRows(int numMetatiles) const;
|
||||
int numRows() const;
|
||||
void drawGrid();
|
||||
@@ -60,6 +70,7 @@ 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 * Metatile::tileWidth(), Metatile::tileHeight()) {
|
||||
TilesetEditorTileSelector(Tileset *primaryTileset, Tileset *secondaryTileset)
|
||||
: SelectablePixmapItem(16, 16, Metatile::tileWidth(), Metatile::tileWidth()) {
|
||||
this->primaryTileset = primaryTileset;
|
||||
this->secondaryTileset = secondaryTileset;
|
||||
this->numTilesWide = 16;
|
||||
@@ -18,7 +18,8 @@ public:
|
||||
this->paletteChanged = false;
|
||||
setAcceptHoverEvents(true);
|
||||
}
|
||||
QPoint getSelectionDimensions() const override;
|
||||
QSize getSelectionDimensions() const override;
|
||||
void setMaxSelectionSize(int width, int height) override;
|
||||
void draw() override;
|
||||
void select(uint16_t metatileId);
|
||||
void highlight(uint16_t metatileId);
|
||||
@@ -26,7 +27,7 @@ public:
|
||||
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();
|
||||
@@ -48,7 +49,7 @@ private:
|
||||
int externalSelectionWidth;
|
||||
int externalSelectionHeight;
|
||||
QList<Tile> externalSelectedTiles;
|
||||
QList<int> externalSelectedPos;
|
||||
QPoint prevCellPos = QPoint(-1,-1);
|
||||
|
||||
Tileset *primaryTileset;
|
||||
Tileset *secondaryTileset;
|
||||
@@ -62,7 +63,7 @@ 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();
|
||||
|
||||
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>
|
||||
|
||||
@@ -338,6 +338,7 @@ void PorymapConfig::reset() {
|
||||
this->metatilesZoom = 30;
|
||||
this->tilesetEditorMetatilesZoom = 30;
|
||||
this->tilesetEditorTilesZoom = 30;
|
||||
this->tilesetEditorLayerOrientation = Qt::Vertical;
|
||||
this->showPlayerView = false;
|
||||
this->showCursorTile = true;
|
||||
this->showBorder = true;
|
||||
@@ -454,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") {
|
||||
@@ -604,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");
|
||||
|
||||
@@ -99,7 +99,7 @@ QRect Layout::getVisibleRect() const {
|
||||
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);
|
||||
@@ -134,6 +134,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();
|
||||
}
|
||||
|
||||
@@ -107,6 +107,14 @@ 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();
|
||||
}
|
||||
@@ -250,8 +258,8 @@ QString Tileset::getMetatileLabelPrefix(const QString &name)
|
||||
}
|
||||
|
||||
bool Tileset::metatileIsValid(uint16_t metatileId, const Tileset *primaryTileset, const Tileset *secondaryTileset) {
|
||||
return (primaryTileset && primaryTileset->contains(metatileId))
|
||||
|| (secondaryTileset && secondaryTileset->contains(metatileId));
|
||||
return (primaryTileset && primaryTileset->containsMetatileId(metatileId))
|
||||
|| (secondaryTileset && secondaryTileset->containsMetatileId(metatileId));
|
||||
}
|
||||
|
||||
QList<QList<QRgb>> Tileset::getBlockPalettes(const Tileset *primaryTileset, const Tileset *secondaryTileset, bool useTruePalettes) {
|
||||
|
||||
@@ -1120,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();
|
||||
}
|
||||
|
||||
@@ -1774,8 +1773,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);
|
||||
}
|
||||
|
||||
@@ -1787,7 +1787,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();
|
||||
@@ -1795,8 +1795,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) * Metatile::pixelWidth(), (size.y() - 1) * Metatile::pixelHeight()) / 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();
|
||||
@@ -1970,8 +1970,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");
|
||||
}
|
||||
|
||||
@@ -1187,6 +1187,18 @@ 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);
|
||||
@@ -1194,6 +1206,11 @@ bool Project::loadLayoutTilesets(Layout *layout) {
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -3546,3 +3563,19 @@ QSet<QString> Project::getPairedTilesetLabels(const Tileset *tileset) const {
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -96,21 +96,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);
|
||||
}
|
||||
|
||||
@@ -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.at(j * selection.dimensions.width() + i);
|
||||
layout->setBorderMetatileId(pos.x() + i, pos.y() + j, item.metatileId, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,18 +3,18 @@
|
||||
#include <QPainter>
|
||||
|
||||
QPixmap drawMetatileSelection(MetatileSelection selection, Layout *layout) {
|
||||
int width = selection.dimensions.x() * Metatile::pixelWidth();
|
||||
int height = selection.dimensions.y() * Metatile::pixelHeight();
|
||||
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++) {
|
||||
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;
|
||||
int index = j * selection.dimensions.width() + i;
|
||||
MetatileSelectionItem item = selection.metatileItems.at(index);
|
||||
if (item.enabled) {
|
||||
QImage metatile_image = getMetatileImage(item.metatileId, layout);
|
||||
|
||||
@@ -39,8 +39,8 @@ void CursorTileRect::stopRightClickSelectionAnchor() {
|
||||
m_rightClickSelectionAnchored = false;
|
||||
}
|
||||
|
||||
void CursorTileRect::updateSelectionSize(int width, int height) {
|
||||
m_selectionSize = QSize(width, height).expandedTo(QSize(1,1));
|
||||
void CursorTileRect::updateSelectionSize(const QSize &size) {
|
||||
m_selectionSize = size.expandedTo(QSize(1,1)); // Enforce minimum of 1x1 cell
|
||||
prepareGeometryChange();
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -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 && selectionDimensions == QSize(3,3)) {
|
||||
paintSmartPath(pos.x(), pos.y());
|
||||
} else {
|
||||
paintNormal(pos.x(), pos.y());
|
||||
}
|
||||
} else {
|
||||
if (shiftPressed && selectionDimensions.x() == 3 && selectionDimensions.y() == 3) {
|
||||
if (shiftPressed && selectionDimensions == QSize(3,3)) {
|
||||
paintSmartPath(pos.x(), pos.y());
|
||||
} else {
|
||||
paintNormal(pos.x(), pos.y());
|
||||
@@ -110,22 +110,22 @@ 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;
|
||||
int index = j * selection.dimensions.width() + i;
|
||||
MetatileSelectionItem item = selection.metatileItems.at(index);
|
||||
if (!item.enabled)
|
||||
continue;
|
||||
@@ -178,7 +178,7 @@ bool isSmartPathTile(QList<MetatileSelectionItem> metatileItems, uint16_t metati
|
||||
}
|
||||
|
||||
bool isValidSmartPathSelection(MetatileSelection selection) {
|
||||
if (selection.dimensions.x() != 3 || selection.dimensions.y() != 3)
|
||||
if (selection.dimensions != QSize(3,3))
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < selection.metatileItems.length(); i++) {
|
||||
@@ -377,7 +377,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) && selection.dimensions == QSize(3,3))
|
||||
this->floodFillSmartPath(pos.x(), pos.y());
|
||||
else
|
||||
this->floodFill(pos.x(), pos.y());
|
||||
@@ -398,7 +398,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 +411,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,11 +430,11 @@ 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;
|
||||
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 (selectedMetatiles.at(index).enabled) {
|
||||
block.setMetatileId(selectedMetatiles.at(index).metatileId);
|
||||
if (setCollisions) {
|
||||
@@ -460,7 +460,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 +468,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,11 +490,11 @@ 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;
|
||||
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.at(index).metatileId;
|
||||
uint16_t old_metatileId = block.metatileId();
|
||||
if (selectedMetatiles.at(index).enabled && (selectedMetatiles.count() != 1 || old_metatileId != metatileId)) {
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#include "imageproviders.h"
|
||||
#include <QPainter>
|
||||
|
||||
MetatileLayersItem::MetatileLayersItem(Metatile *metatile, Tileset *primaryTileset, Tileset *secondaryTileset)
|
||||
: SelectablePixmapItem(16, 16, Metatile::tileWidth() * projectConfig.getNumLayersInMetatile(), Metatile::tileHeight()),
|
||||
MetatileLayersItem::MetatileLayersItem(Metatile *metatile, Tileset *primaryTileset, Tileset *secondaryTileset, Qt::Orientation orientation)
|
||||
: SelectablePixmapItem(16, 16, Metatile::tileWidth(), Metatile::tileHeight()),
|
||||
metatile(metatile),
|
||||
primaryTileset(primaryTileset),
|
||||
secondaryTileset(secondaryTileset)
|
||||
@@ -12,28 +12,51 @@ MetatileLayersItem::MetatileLayersItem(Metatile *metatile, Tileset *primaryTiles
|
||||
clearLastModifiedCoords();
|
||||
clearLastHoveredCoords();
|
||||
setAcceptHoverEvents(true);
|
||||
setOrientation(orientation);
|
||||
}
|
||||
|
||||
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),
|
||||
};
|
||||
void MetatileLayersItem::setOrientation(Qt::Orientation orientation) {
|
||||
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();
|
||||
const int layerWidth = this->cellWidth * Metatile::tileWidth();
|
||||
const int layerHeight = this->cellHeight * Metatile::tileHeight();
|
||||
QPixmap pixmap(numLayers * layerWidth, layerHeight);
|
||||
QPixmap pixmap(this->cellWidth * this->maxSelectionWidth, this->cellHeight * this->maxSelectionHeight);
|
||||
QPainter painter(&pixmap);
|
||||
|
||||
// Draw tile images
|
||||
@@ -47,15 +70,22 @@ void MetatileLayersItem::draw() {
|
||||
true
|
||||
).scaled(this->cellWidth, this->cellHeight);
|
||||
tile.flip(&tileImage);
|
||||
QPoint pos = tilePositions.at(i);
|
||||
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 * layerWidth;
|
||||
painter.drawLine(x, 0, x, layerHeight);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,57 +106,64 @@ void MetatileLayersItem::setTilesets(Tileset *primaryTileset, Tileset *secondary
|
||||
this->clearLastHoveredCoords();
|
||||
}
|
||||
|
||||
void MetatileLayersItem::updateSelection() {
|
||||
drawSelection();
|
||||
emit selectedTilesChanged(getSelectionStart(), getSelectionDimensions());
|
||||
}
|
||||
|
||||
void MetatileLayersItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
|
||||
const QPoint pos = this->getBoundedPos(event->pos());
|
||||
hover(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);
|
||||
}
|
||||
this->prevChangedPos = pos;
|
||||
}
|
||||
|
||||
void MetatileLayersItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
|
||||
const QPoint pos = this->getBoundedPos(event->pos());
|
||||
if (this->prevChangedPos == pos)
|
||||
return;
|
||||
hover(pos);
|
||||
|
||||
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);
|
||||
}
|
||||
this->prevChangedPos = 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());
|
||||
hover(getBoundedPos(event->pos()));
|
||||
}
|
||||
|
||||
void MetatileLayersItem::hover(const QPoint &pos) {
|
||||
if (pos == this->prevHoveredPos)
|
||||
return;
|
||||
this->prevHoveredPos = pos;
|
||||
|
||||
int tileIndex = tilePositions.indexOf(pos);
|
||||
if (tileIndex < 0 || tileIndex >= this->metatile->tiles.length())
|
||||
int tileIndex = posToTileIndex(pos);
|
||||
if (tileIndex < 0 || !this->metatile || tileIndex >= this->metatile->tiles.length())
|
||||
return;
|
||||
|
||||
emit this->hoveredTileChanged(this->metatile->tiles.at(tileIndex));
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "project.h"
|
||||
#include <QPainter>
|
||||
|
||||
QPoint MetatileSelector::getSelectionDimensions() const {
|
||||
QSize MetatileSelector::getSelectionDimensions() const {
|
||||
if (this->prefabSelection || this->externalSelection)
|
||||
return selection.dimensions;
|
||||
return SelectablePixmapItem::getSelectionDimensions();
|
||||
@@ -41,7 +41,7 @@ bool MetatileSelector::select(uint16_t metatileId) {
|
||||
this->externalSelection = false;
|
||||
this->prefabSelection = false;
|
||||
this->selection = MetatileSelection{
|
||||
QPoint(1, 1),
|
||||
QSize(1, 1),
|
||||
false,
|
||||
QList<MetatileSelectionItem>({MetatileSelectionItem{true, metatileId}}),
|
||||
QList<CollisionSelectionItem>(),
|
||||
@@ -80,7 +80,7 @@ void MetatileSelector::setExternalSelection(int width, int height, const QList<u
|
||||
this->selection.metatileItems.clear();
|
||||
this->selection.collisionItems.clear();
|
||||
this->selection.hasCollision = true;
|
||||
this->selection.dimensions = QPoint(width, height);
|
||||
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;
|
||||
@@ -175,8 +175,8 @@ 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++) {
|
||||
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});
|
||||
}
|
||||
@@ -186,7 +186,7 @@ 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 (!this->layout->metatileIsValid(metatileId))
|
||||
@@ -204,7 +204,7 @@ uint16_t MetatileSelector::posToMetatileId(int x, int y, bool *ok) const {
|
||||
if (ok) *ok = true;
|
||||
int index = y * this->numMetatilesWide + x;
|
||||
uint16_t metatileId = static_cast<uint16_t>(index);
|
||||
if (primaryTileset() && primaryTileset()->contains(metatileId)) {
|
||||
if (primaryTileset() && primaryTileset()->containsMetatileId(metatileId)) {
|
||||
return metatileId;
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ uint16_t MetatileSelector::posToMetatileId(int x, int y, bool *ok) const {
|
||||
int numPrimaryRounded = numPrimaryMetatilesRounded();
|
||||
int firstSecondaryRow = numPrimaryRounded / this->numMetatilesWide;
|
||||
metatileId = static_cast<uint16_t>(Project::getNumMetatilesPrimary() + index - numPrimaryRounded);
|
||||
if (secondaryTileset() && secondaryTileset()->contains(metatileId) && y >= firstSecondaryRow) {
|
||||
if (secondaryTileset() && secondaryTileset()->containsMetatileId(metatileId) && y >= firstSecondaryRow) {
|
||||
return metatileId;
|
||||
}
|
||||
|
||||
@@ -224,12 +224,12 @@ uint16_t MetatileSelector::posToMetatileId(int x, int y, bool *ok) const {
|
||||
}
|
||||
|
||||
QPoint MetatileSelector::metatileIdToPos(uint16_t metatileId, bool *ok) const {
|
||||
if (primaryTileset() && primaryTileset()->contains(metatileId)) {
|
||||
if (primaryTileset() && primaryTileset()->containsMetatileId(metatileId)) {
|
||||
if (ok) *ok = true;
|
||||
int index = metatileId;
|
||||
return QPoint(index % this->numMetatilesWide, index / this->numMetatilesWide);
|
||||
}
|
||||
if (secondaryTileset() && secondaryTileset()->contains(metatileId)) {
|
||||
if (secondaryTileset() && secondaryTileset()->containsMetatileId(metatileId)) {
|
||||
if (ok) *ok = true;
|
||||
int index = metatileId - Project::getNumMetatilesPrimary() + numPrimaryMetatilesRounded();
|
||||
return QPoint(index % this->numMetatilesWide, index / this->numMetatilesWide);
|
||||
|
||||
@@ -28,11 +28,6 @@ PaletteEditor::PaletteEditor(Project *project, Tileset *primaryTileset, Tileset
|
||||
ui->layout_Colors->addWidget(colorInput, i / numColorsPerRow, i % numColorsPerRow);
|
||||
}
|
||||
|
||||
// Setup edit-undo history for each of the palettes.
|
||||
for (int i = 0; i < Project::getNumPalettesTotal(); i++) {
|
||||
this->palettesHistory.append(History<PaletteHistoryItem*>());
|
||||
}
|
||||
|
||||
int bitDepth = porymapConfig.paletteEditorBitDepth;
|
||||
if (bitDepth == 15) {
|
||||
this->ui->bit_depth_15->setChecked(true);
|
||||
@@ -62,6 +57,8 @@ PaletteEditor::PaletteEditor(Project *project, Tileset *primaryTileset, Tileset
|
||||
connect(this->ui->spinBox_PaletteId, QOverload<int>::of(&QSpinBox::valueChanged), this, &PaletteEditor::refreshPaletteId);
|
||||
connect(this->ui->spinBox_PaletteId, QOverload<int>::of(&QSpinBox::valueChanged), this, &PaletteEditor::changedPalette);
|
||||
|
||||
ui->actionRedo->setShortcuts({ui->actionRedo->shortcut(), QKeySequence("Ctrl+Shift+Z")});
|
||||
|
||||
refreshPaletteId();
|
||||
restoreWindowState();
|
||||
}
|
||||
@@ -127,8 +124,12 @@ void PaletteEditor::refreshPaletteId() {
|
||||
refreshColorInputs();
|
||||
|
||||
int paletteId = currentPaletteId();
|
||||
|
||||
if (!this->palettesHistory[paletteId].current()) {
|
||||
// The original colors are saved as an initial commit.
|
||||
commitEditHistory(paletteId);
|
||||
} else {
|
||||
updateEditHistoryActions();
|
||||
}
|
||||
if (this->colorSearchWindow) {
|
||||
this->colorSearchWindow->setPaletteId(paletteId);
|
||||
@@ -154,8 +155,8 @@ void PaletteEditor::commitEditHistory(int paletteId) {
|
||||
for (int i = 0; i < this->colorInputs.length(); i++) {
|
||||
colors.append(this->colorInputs.at(i)->color());
|
||||
}
|
||||
PaletteHistoryItem *commit = new PaletteHistoryItem(colors);
|
||||
this->palettesHistory[paletteId].push(commit);
|
||||
this->palettesHistory[paletteId].push(new PaletteHistoryItem(colors));
|
||||
updateEditHistoryActions();
|
||||
}
|
||||
|
||||
void PaletteEditor::restoreWindowState() {
|
||||
@@ -165,18 +166,27 @@ void PaletteEditor::restoreWindowState() {
|
||||
restoreState(geometry.value("palette_editor_state"));
|
||||
}
|
||||
|
||||
void PaletteEditor::updateEditHistoryActions() {
|
||||
int paletteId = currentPaletteId();
|
||||
// We have an initial commit that shouldn't be available to Undo, so we ignore that.
|
||||
ui->actionUndo->setEnabled(this->palettesHistory[paletteId].index() > 0);
|
||||
ui->actionRedo->setEnabled(this->palettesHistory[paletteId].canRedo());
|
||||
}
|
||||
|
||||
void PaletteEditor::on_actionUndo_triggered() {
|
||||
int paletteId = currentPaletteId();
|
||||
PaletteHistoryItem *prev = this->palettesHistory[paletteId].back();
|
||||
if (prev)
|
||||
setPalette(paletteId, prev->colors);
|
||||
PaletteHistoryItem *commit = this->palettesHistory[paletteId].back();
|
||||
if (!commit) return;
|
||||
setPalette(paletteId, commit->colors);
|
||||
updateEditHistoryActions();
|
||||
}
|
||||
|
||||
void PaletteEditor::on_actionRedo_triggered() {
|
||||
int paletteId = currentPaletteId();
|
||||
PaletteHistoryItem *next = this->palettesHistory[paletteId].next();
|
||||
if (next)
|
||||
setPalette(paletteId, next->colors);
|
||||
PaletteHistoryItem *commit = this->palettesHistory[paletteId].next();
|
||||
if (!commit) return;
|
||||
setPalette(paletteId, commit->colors);
|
||||
updateEditHistoryActions();
|
||||
}
|
||||
|
||||
void PaletteEditor::on_actionImport_Palette_triggered() {
|
||||
|
||||
@@ -58,7 +58,7 @@ void Prefab::loadPrefabs() {
|
||||
QString secondaryTileset = ParseUtil::jsonToQString(prefabObj["secondary_tileset"]);
|
||||
|
||||
MetatileSelection selection;
|
||||
selection.dimensions = QPoint(width, height);
|
||||
selection.dimensions = QSize(width, height);
|
||||
selection.hasCollision = true;
|
||||
for (int j = 0; j < width * height; j++) {
|
||||
selection.metatileItems.append(MetatileSelectionItem{false, 0});
|
||||
@@ -112,14 +112,14 @@ void Prefab::savePrefabs() {
|
||||
for (auto item : this->items) {
|
||||
OrderedJson::object prefabObj;
|
||||
prefabObj["name"] = item.name;
|
||||
prefabObj["width"] = item.selection.dimensions.x();
|
||||
prefabObj["height"] = item.selection.dimensions.y();
|
||||
prefabObj["width"] = item.selection.dimensions.width();
|
||||
prefabObj["height"] = item.selection.dimensions.height();
|
||||
prefabObj["primary_tileset"] = item.primaryTileset;
|
||||
prefabObj["secondary_tileset"] = item.secondaryTileset;
|
||||
OrderedJson::array metatiles;
|
||||
for (int y = 0; y < item.selection.dimensions.y(); y++) {
|
||||
for (int x = 0; x < item.selection.dimensions.x(); x++) {
|
||||
int index = y * item.selection.dimensions.x() + x;
|
||||
for (int y = 0; y < item.selection.dimensions.height(); y++) {
|
||||
for (int x = 0; x < item.selection.dimensions.width(); x++) {
|
||||
int index = y * item.selection.dimensions.width() + x;
|
||||
auto metatileItem = item.selection.metatileItems.at(index);
|
||||
if (metatileItem.enabled) {
|
||||
OrderedJson::object metatileObj;
|
||||
|
||||
@@ -23,13 +23,13 @@ PrefabCreationDialog::PrefabCreationDialog(QWidget *parent, MetatileSelector *me
|
||||
|
||||
QObject::connect(this->ui->graphicsView_Prefab, &ClickableGraphicsView::clicked, [=](QMouseEvent *event){
|
||||
auto pos = event->pos();
|
||||
int selectionWidth = this->selection.dimensions.x() * Metatile::pixelWidth();
|
||||
int selectionHeight = this->selection.dimensions.y() * Metatile::pixelHeight();
|
||||
int selectionWidth = this->selection.dimensions.width() * Metatile::pixelWidth();
|
||||
int selectionHeight = this->selection.dimensions.height() * Metatile::pixelHeight();
|
||||
if (pos.x() < 0 || pos.x() >= selectionWidth || pos.y() < 0 || pos.y() >= selectionHeight)
|
||||
return;
|
||||
int metatileX = pos.x() / Metatile::pixelWidth();
|
||||
int metatileY = pos.y() / Metatile::pixelHeight();
|
||||
int index = metatileY * this->selection.dimensions.x() + metatileX;
|
||||
int index = metatileY * this->selection.dimensions.width() + metatileX;
|
||||
bool toggledState = !this->selection.metatileItems[index].enabled;
|
||||
this->selection.metatileItems[index].enabled = toggledState;
|
||||
if (this->selection.hasCollision) {
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
#include "selectablepixmapitem.h"
|
||||
#include <QPainter>
|
||||
|
||||
QPoint SelectablePixmapItem::getSelectionDimensions() const
|
||||
{
|
||||
return QPoint(abs(this->selectionOffsetX) + 1, abs(this->selectionOffsetY) + 1);
|
||||
}
|
||||
|
||||
QPoint SelectablePixmapItem::getSelectionStart()
|
||||
{
|
||||
int x = this->selectionInitialX;
|
||||
@@ -15,47 +10,60 @@ QPoint SelectablePixmapItem::getSelectionStart()
|
||||
return QPoint(x, y);
|
||||
}
|
||||
|
||||
void SelectablePixmapItem::select(int x, int y, int width, int height)
|
||||
{
|
||||
this->selectionInitialX = x;
|
||||
this->selectionInitialY = y;
|
||||
this->selectionOffsetX = qBound(0, width, this->maxSelectionWidth);
|
||||
this->selectionOffsetY = qBound(0, height, this->maxSelectionHeight);
|
||||
this->draw();
|
||||
emit this->selectionChanged(x, y, width, height);
|
||||
void SelectablePixmapItem::setSelection(const QPoint &pos, const QSize &size) {
|
||||
this->selectionInitialX = pos.x();
|
||||
this->selectionInitialY = pos.y();
|
||||
this->selectionOffsetX = getBoundedWidth(size.width()) - 1;
|
||||
this->selectionOffsetY = getBoundedHeight(size.height()) - 1;
|
||||
}
|
||||
|
||||
void SelectablePixmapItem::select(const QPoint &pos, const QSize &size) {
|
||||
setSelection(pos, size);
|
||||
draw();
|
||||
emit selectionChanged(pos, getSelectionDimensions());
|
||||
}
|
||||
|
||||
void SelectablePixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
QPoint pos = this->getCellPos(event->pos());
|
||||
this->selectionInitialX = pos.x();
|
||||
this->selectionInitialY = pos.y();
|
||||
this->selectionOffsetX = 0;
|
||||
this->selectionOffsetY = 0;
|
||||
this->updateSelection(pos.x(), pos.y());
|
||||
QPoint pos = getCellPos(event->pos());
|
||||
setSelection(pos, QSize(1,1));
|
||||
this->prevCellPos = pos;
|
||||
updateSelection(pos);
|
||||
}
|
||||
|
||||
void SelectablePixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
QPoint pos = this->getCellPos(event->pos());
|
||||
this->updateSelection(pos.x(), pos.y());
|
||||
QPoint pos = getCellPos(event->pos());
|
||||
if (pos == this->prevCellPos)
|
||||
return;
|
||||
this->prevCellPos = pos;
|
||||
updateSelection(pos);
|
||||
}
|
||||
|
||||
void SelectablePixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
QPoint pos = this->getCellPos(event->pos());
|
||||
this->updateSelection(pos.x(), pos.y());
|
||||
updateSelection(getCellPos(event->pos()));
|
||||
}
|
||||
|
||||
void SelectablePixmapItem::updateSelection(int x, int y)
|
||||
{
|
||||
void SelectablePixmapItem::setMaxSelectionSize(int width, int height) {
|
||||
this->maxSelectionWidth = qMax(width, 1);
|
||||
this->maxSelectionHeight = qMax(height, 1);
|
||||
|
||||
// Update the selection if we shrank below the current selection size.
|
||||
QSize size = getSelectionDimensions();
|
||||
if (size.width() > this->maxSelectionWidth || size.height() > this->maxSelectionHeight) {
|
||||
setSelection(getSelectionStart(), size);
|
||||
draw();
|
||||
// 'draw' is allowed to change the selection position/size,
|
||||
// so call these again rather than keep values from above.
|
||||
emit selectionChanged(getSelectionStart(), getSelectionDimensions());
|
||||
}
|
||||
}
|
||||
|
||||
void SelectablePixmapItem::updateSelection(const QPoint &pos) {
|
||||
// Snap to a valid position inside the selection area.
|
||||
int width = pixmap().width() / this->cellWidth;
|
||||
int height = pixmap().height() / this->cellHeight;
|
||||
if (x < 0) x = 0;
|
||||
if (x >= width) x = width - 1;
|
||||
if (y < 0) y = 0;
|
||||
if (y >= height) y = height - 1;
|
||||
int x = qBound(0, pos.x(), cellsWide() - 1);
|
||||
int y = qBound(0, pos.y(), cellsTall() - 1);
|
||||
|
||||
this->selectionOffsetX = x - this->selectionInitialX;
|
||||
this->selectionOffsetY = y - this->selectionInitialY;
|
||||
@@ -76,25 +84,30 @@ void SelectablePixmapItem::updateSelection(int x, int y)
|
||||
this->selectionOffsetY = -this->maxSelectionHeight + 1;
|
||||
}
|
||||
|
||||
this->draw();
|
||||
emit this->selectionChanged(x, y, width, height);
|
||||
draw();
|
||||
emit selectionChanged(QPoint(x, y), getSelectionDimensions());
|
||||
}
|
||||
|
||||
QPoint SelectablePixmapItem::getCellPos(QPointF pos)
|
||||
{
|
||||
if (pos.x() < 0) pos.setX(0);
|
||||
if (pos.y() < 0) pos.setY(0);
|
||||
if (pos.x() >= this->pixmap().width()) pos.setX(this->pixmap().width() - 1);
|
||||
if (pos.y() >= this->pixmap().height()) pos.setY(this->pixmap().height() - 1);
|
||||
return QPoint(static_cast<int>(pos.x()) / this->cellWidth,
|
||||
static_cast<int>(pos.y()) / this->cellHeight);
|
||||
void SelectablePixmapItem::setSelectionStyle(Qt::PenStyle style) {
|
||||
this->selectionStyle = style;
|
||||
draw();
|
||||
}
|
||||
|
||||
void SelectablePixmapItem::drawSelection()
|
||||
{
|
||||
QPoint origin = this->getSelectionStart();
|
||||
QPoint dimensions = this->getSelectionDimensions();
|
||||
QRect selectionRect(origin.x() * this->cellWidth, origin.y() * this->cellHeight, dimensions.x() * this->cellWidth, dimensions.y() * this->cellHeight);
|
||||
QPoint SelectablePixmapItem::getCellPos(const QPointF &itemPos) {
|
||||
if (this->cellWidth == 0 || this->cellHeight == 0 || pixmap().isNull())
|
||||
return QPoint(0,0);
|
||||
|
||||
int x = qBound(0, static_cast<int>(itemPos.x()), pixmap().width() - 1);
|
||||
int y = qBound(0, static_cast<int>(itemPos.y()), pixmap().height() - 1);
|
||||
return QPoint(x / this->cellWidth, y / this->cellHeight);
|
||||
}
|
||||
|
||||
void SelectablePixmapItem::drawSelection() {
|
||||
drawSelectionRect(getSelectionStart(), getSelectionDimensions(), this->selectionStyle);
|
||||
}
|
||||
|
||||
void SelectablePixmapItem::drawSelectionRect(const QPoint &origin, const QSize &dimensions, Qt::PenStyle style) {
|
||||
QRect selectionRect(origin.x() * this->cellWidth, origin.y() * this->cellHeight, dimensions.width() * this->cellWidth, dimensions.height() * this->cellHeight);
|
||||
|
||||
// If a selection is fully outside the bounds of the selectable area, don't draw anything.
|
||||
// This prevents the border of the selection rectangle potentially being visible on an otherwise invisible selection.
|
||||
@@ -102,12 +115,27 @@ void SelectablePixmapItem::drawSelection()
|
||||
if (!selectionRect.intersects(pixmap.rect()))
|
||||
return;
|
||||
|
||||
auto fillPen = QPen(QColor(Qt::white));
|
||||
auto borderPen = QPen(QColor(Qt::black));
|
||||
borderPen.setStyle(style);
|
||||
|
||||
QPainter painter(&pixmap);
|
||||
painter.setPen(QColor(0xff, 0xff, 0xff));
|
||||
painter.drawRect(selectionRect.x(), selectionRect.y(), selectionRect.width() - 1, selectionRect.height() - 1);
|
||||
painter.setPen(QColor(0, 0, 0));
|
||||
painter.drawRect(selectionRect.x() - 1, selectionRect.y() - 1, selectionRect.width() + 1, selectionRect.height() + 1);
|
||||
painter.drawRect(selectionRect.x() + 1, selectionRect.y() + 1, selectionRect.width() - 3, selectionRect.height() - 3);
|
||||
if (style == Qt::SolidLine) {
|
||||
painter.setPen(fillPen);
|
||||
painter.drawRect(selectionRect - QMargins(1,1,1,1));
|
||||
painter.setPen(borderPen);
|
||||
painter.drawRect(selectionRect);
|
||||
painter.drawRect(selectionRect - QMargins(2,2,2,2));
|
||||
} else {
|
||||
// Having separately sized rectangles with anything but a
|
||||
// solid line looks a little wonky because the dashes wont align.
|
||||
// For non-solid styles we'll draw a base white rectangle, then draw
|
||||
// a styled black rectangle on top
|
||||
painter.setPen(fillPen);
|
||||
painter.drawRect(selectionRect);
|
||||
painter.setPen(borderPen);
|
||||
painter.drawRect(selectionRect);
|
||||
}
|
||||
|
||||
this->setPixmap(pixmap);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ TilesetEditor::TilesetEditor(Project *project, Layout *layout, QWidget *parent)
|
||||
|
||||
auto validator = new IdentifierValidator(this);
|
||||
validator->setAllowEmpty(true);
|
||||
ui->lineEdit_metatileLabel->setValidator(validator);
|
||||
ui->lineEdit_MetatileLabel->setValidator(validator);
|
||||
|
||||
ui->actionShow_Tileset_Divider->setChecked(porymapConfig.showTilesetEditorDivider);
|
||||
ui->actionShow_Raw_Metatile_Attributes->setChecked(porymapConfig.showTilesetEditorRawAttributes);
|
||||
@@ -62,12 +62,18 @@ TilesetEditor::TilesetEditor(Project *project, Layout *layout, QWidget *parent)
|
||||
|
||||
connect(ui->spinBox_paletteSelector, QOverload<int>::of(&QSpinBox::valueChanged), this, &TilesetEditor::refreshPaletteId);
|
||||
|
||||
connect(ui->actionLayer_Arrangement_Horizontal, &QAction::triggered, [this] { setMetatileLayerOrientation(Qt::Horizontal); });
|
||||
connect(ui->actionLayer_Arrangement_Vertical, &QAction::triggered, [this] { setMetatileLayerOrientation(Qt::Vertical); });
|
||||
|
||||
connect(ui->lineEdit_MetatileLabel, &QLineEdit::editingFinished, this, &TilesetEditor::commitMetatileLabel);
|
||||
|
||||
initAttributesUi();
|
||||
initMetatileSelector();
|
||||
initMetatileLayersItem();
|
||||
initTileSelector();
|
||||
initSelectedTileItem();
|
||||
initShortcuts();
|
||||
setMetatileLayerOrientation(porymapConfig.tilesetEditorLayerOrientation);
|
||||
this->metatileSelector->select(0);
|
||||
restoreWindowState();
|
||||
}
|
||||
@@ -133,92 +139,85 @@ void TilesetEditor::setTilesets(QString primaryTilesetLabel, QString secondaryTi
|
||||
this->primaryTileset = new Tileset(*primaryTileset);
|
||||
this->secondaryTileset = new Tileset(*secondaryTileset);
|
||||
if (this->paletteEditor) this->paletteEditor->setTilesets(this->primaryTileset, this->secondaryTileset);
|
||||
this->initMetatileHistory();
|
||||
initMetatileHistory();
|
||||
}
|
||||
|
||||
void TilesetEditor::initAttributesUi() {
|
||||
connect(ui->comboBox_metatileBehaviors, &NoScrollComboBox::editingFinished, this, &TilesetEditor::commitMetatileBehavior);
|
||||
connect(ui->comboBox_encounterType, &NoScrollComboBox::editingFinished, this, &TilesetEditor::commitEncounterType);
|
||||
connect(ui->comboBox_terrainType, &NoScrollComboBox::editingFinished, this, &TilesetEditor::commitTerrainType);
|
||||
connect(ui->comboBox_layerType, &NoScrollComboBox::editingFinished, this, &TilesetEditor::commitLayerType);
|
||||
connect(ui->comboBox_MetatileBehaviors, &NoScrollComboBox::editingFinished, this, &TilesetEditor::commitMetatileBehavior);
|
||||
connect(ui->comboBox_EncounterType, &NoScrollComboBox::editingFinished, this, &TilesetEditor::commitEncounterType);
|
||||
connect(ui->comboBox_TerrainType, &NoScrollComboBox::editingFinished, this, &TilesetEditor::commitTerrainType);
|
||||
connect(ui->comboBox_LayerType, &NoScrollComboBox::editingFinished, this, &TilesetEditor::commitLayerType);
|
||||
|
||||
// Behavior
|
||||
if (projectConfig.metatileBehaviorMask) {
|
||||
for (auto i = project->metatileBehaviorMapInverse.constBegin(); i != project->metatileBehaviorMapInverse.constEnd(); i++) {
|
||||
this->ui->comboBox_metatileBehaviors->addItem(i.value(), i.key());
|
||||
this->ui->comboBox_MetatileBehaviors->addItem(i.value(), i.key());
|
||||
}
|
||||
this->ui->comboBox_metatileBehaviors->setMinimumContentsLength(0);
|
||||
this->ui->comboBox_MetatileBehaviors->setMinimumContentsLength(0);
|
||||
} else {
|
||||
this->ui->comboBox_metatileBehaviors->setVisible(false);
|
||||
this->ui->label_metatileBehavior->setVisible(false);
|
||||
this->ui->frame_MetatileBehavior->setVisible(false);
|
||||
}
|
||||
|
||||
// Terrain Type
|
||||
if (projectConfig.metatileTerrainTypeMask) {
|
||||
for (auto i = project->terrainTypeToName.constBegin(); i != project->terrainTypeToName.constEnd(); i++) {
|
||||
this->ui->comboBox_terrainType->addItem(i.value(), i.key());
|
||||
this->ui->comboBox_TerrainType->addItem(i.value(), i.key());
|
||||
}
|
||||
this->ui->comboBox_terrainType->setMinimumContentsLength(0);
|
||||
this->ui->comboBox_TerrainType->setMinimumContentsLength(0);
|
||||
} else {
|
||||
this->ui->comboBox_terrainType->setVisible(false);
|
||||
this->ui->label_terrainType->setVisible(false);
|
||||
this->ui->frame_TerrainType->setVisible(false);
|
||||
}
|
||||
|
||||
// Encounter Type
|
||||
if (projectConfig.metatileEncounterTypeMask) {
|
||||
for (auto i = project->encounterTypeToName.constBegin(); i != project->encounterTypeToName.constEnd(); i++) {
|
||||
this->ui->comboBox_encounterType->addItem(i.value(), i.key());
|
||||
this->ui->comboBox_EncounterType->addItem(i.value(), i.key());
|
||||
}
|
||||
this->ui->comboBox_encounterType->setMinimumContentsLength(0);
|
||||
this->ui->comboBox_EncounterType->setMinimumContentsLength(0);
|
||||
} else {
|
||||
this->ui->comboBox_encounterType->setVisible(false);
|
||||
this->ui->label_encounterType->setVisible(false);
|
||||
this->ui->frame_EncounterType->setVisible(false);
|
||||
}
|
||||
|
||||
// Layer Type
|
||||
if (!projectConfig.tripleLayerMetatilesEnabled) {
|
||||
this->ui->comboBox_layerType->addItem("Normal - Middle/Top", Metatile::LayerType::Normal);
|
||||
this->ui->comboBox_layerType->addItem("Covered - Bottom/Middle", Metatile::LayerType::Covered);
|
||||
this->ui->comboBox_layerType->addItem("Split - Bottom/Top", Metatile::LayerType::Split);
|
||||
this->ui->comboBox_layerType->setEditable(false);
|
||||
this->ui->comboBox_layerType->setMinimumContentsLength(0);
|
||||
this->ui->comboBox_LayerType->addItem("Normal - Middle/Top", Metatile::LayerType::Normal);
|
||||
this->ui->comboBox_LayerType->addItem("Covered - Bottom/Middle", Metatile::LayerType::Covered);
|
||||
this->ui->comboBox_LayerType->addItem("Split - Bottom/Top", Metatile::LayerType::Split);
|
||||
this->ui->comboBox_LayerType->setEditable(false);
|
||||
this->ui->comboBox_LayerType->setMinimumContentsLength(0);
|
||||
if (!projectConfig.metatileLayerTypeMask) {
|
||||
// User doesn't have triple layer metatiles, but has no layer type attribute.
|
||||
// Porymap is still using the layer type value to render metatiles, and with
|
||||
// no mask set every metatile will be "Middle/Top", so just display the combo
|
||||
// box but prevent the user from changing the value.
|
||||
this->ui->comboBox_layerType->setEnabled(false);
|
||||
this->ui->comboBox_LayerType->setEnabled(false);
|
||||
}
|
||||
} else {
|
||||
this->ui->comboBox_layerType->setVisible(false);
|
||||
this->ui->label_layerType->setVisible(false);
|
||||
this->ui->frame_LayerType->setVisible(false);
|
||||
this->ui->label_BottomTop->setText("Bottom/Middle/Top");
|
||||
}
|
||||
|
||||
// Raw attributes value
|
||||
ui->spinBox_rawAttributesValue->setMaximum(Metatile::getMaxAttributesMask());
|
||||
ui->spinBox_RawAttributesValue->setMaximum(Metatile::getMaxAttributesMask());
|
||||
setRawAttributesVisible(ui->actionShow_Raw_Metatile_Attributes->isChecked());
|
||||
connect(ui->spinBox_rawAttributesValue, &UIntHexSpinBox::editingFinished, this, &TilesetEditor::onRawAttributesEdited);
|
||||
connect(ui->spinBox_RawAttributesValue, &UIntHexSpinBox::editingFinished, this, &TilesetEditor::onRawAttributesEdited);
|
||||
connect(ui->actionShow_Raw_Metatile_Attributes, &QAction::toggled, this, &TilesetEditor::setRawAttributesVisible);
|
||||
|
||||
this->ui->frame_Properties->adjustSize();
|
||||
}
|
||||
|
||||
void TilesetEditor::setRawAttributesVisible(bool visible) {
|
||||
porymapConfig.showTilesetEditorRawAttributes = visible;
|
||||
ui->label_rawAttributesValue->setVisible(visible);
|
||||
ui->spinBox_rawAttributesValue->setVisible(visible);
|
||||
ui->frame_RawAttributesValue->setVisible(visible);
|
||||
rebuildMetatilePropertiesFrame();
|
||||
}
|
||||
|
||||
void TilesetEditor::initMetatileSelector()
|
||||
{
|
||||
this->metatileSelector = new TilesetEditorMetatileSelector(projectConfig.metatileSelectorWidth, this->primaryTileset, this->secondaryTileset, this->layout);
|
||||
connect(this->metatileSelector, &TilesetEditorMetatileSelector::hoveredMetatileChanged,
|
||||
this, &TilesetEditor::onHoveredMetatileChanged);
|
||||
connect(this->metatileSelector, &TilesetEditorMetatileSelector::hoveredMetatileCleared,
|
||||
this, &TilesetEditor::onHoveredMetatileCleared);
|
||||
connect(this->metatileSelector, &TilesetEditorMetatileSelector::selectedMetatileChanged,
|
||||
this, &TilesetEditor::onSelectedMetatileChanged);
|
||||
connect(this->metatileSelector, &TilesetEditorMetatileSelector::hoveredMetatileChanged, this, &TilesetEditor::onHoveredMetatileChanged);
|
||||
connect(this->metatileSelector, &TilesetEditorMetatileSelector::hoveredMetatileCleared, this, &TilesetEditor::onHoveredMetatileCleared);
|
||||
connect(this->metatileSelector, &TilesetEditorMetatileSelector::selectedMetatileChanged, this, &TilesetEditor::onSelectedMetatileChanged);
|
||||
connect(this->metatileSelector, &TilesetEditorMetatileSelector::swapRequested, this, &TilesetEditor::commitMetatileSwap);
|
||||
connect(ui->actionSwap_Metatiles, &QAction::triggered, this->metatileSelector, &TilesetEditorMetatileSelector::setSwapMode);
|
||||
|
||||
bool showGrid = porymapConfig.showTilesetEditorMetatileGrid;
|
||||
this->ui->actionMetatile_Grid->setChecked(showGrid);
|
||||
@@ -234,18 +233,89 @@ void TilesetEditor::initMetatileSelector()
|
||||
this->ui->horizontalSlider_MetatilesZoom->setValue(porymapConfig.tilesetEditorMetatilesZoom);
|
||||
}
|
||||
|
||||
void TilesetEditor::setMetatileLayerOrientation(Qt::Orientation orientation) {
|
||||
// Sync settings
|
||||
bool horizontal = (orientation == Qt::Horizontal);
|
||||
porymapConfig.tilesetEditorLayerOrientation = orientation;
|
||||
const QSignalBlocker b_Horizontal(ui->actionLayer_Arrangement_Horizontal);
|
||||
const QSignalBlocker b_Vertical(ui->actionLayer_Arrangement_Vertical);
|
||||
ui->actionLayer_Arrangement_Horizontal->setChecked(horizontal);
|
||||
ui->actionLayer_Arrangement_Vertical->setChecked(!horizontal);
|
||||
|
||||
this->metatileLayersItem->setOrientation(orientation);
|
||||
|
||||
int numTilesWide = Metatile::tileWidth();
|
||||
int numTilesTall = Metatile::tileHeight();
|
||||
int numLayers = projectConfig.getNumLayersInMetatile();
|
||||
if (horizontal) {
|
||||
numTilesWide *= numLayers;
|
||||
} else {
|
||||
numTilesTall *= numLayers;
|
||||
}
|
||||
this->tileSelector->setMaxSelectionSize(numTilesWide, numTilesTall);
|
||||
|
||||
const int scale = 2;
|
||||
int w = Tile::pixelWidth() * numTilesWide * scale + 2;
|
||||
int h = Tile::pixelHeight() * numTilesTall * scale + 2;
|
||||
ui->graphicsView_selectedTile->setFixedSize(w, h);
|
||||
ui->graphicsView_MetatileLayers->setFixedSize(w, h);
|
||||
|
||||
drawSelectedTiles();
|
||||
|
||||
// If the layers are laid out vertically then the orientation is obvious, no need to label them.
|
||||
// This also lets us give the vertical space of the label over to the layer view.
|
||||
ui->label_BottomTop->setVisible(horizontal);
|
||||
|
||||
rebuildMetatilePropertiesFrame();
|
||||
}
|
||||
|
||||
// We rearrange the metatile properties panel depending on the orientation and size of the metatile layer view.
|
||||
// If triple layer metatiles are in-use then layer type field is hidden, so there's an awkward amount of space
|
||||
// next to the layer view, especially in the vertical orientation.
|
||||
// We shift 1-2 widgets up to fill this space next to the layer view. This gets a little complicated because which
|
||||
// widgets are available to move changes depending on the user's settings.
|
||||
void TilesetEditor::rebuildMetatilePropertiesFrame() {
|
||||
if (porymapConfig.tilesetEditorLayerOrientation == Qt::Horizontal) {
|
||||
this->numLayerViewRows = 1;
|
||||
} else {
|
||||
this->numLayerViewRows = projectConfig.tripleLayerMetatilesEnabled ? 4 : 2;
|
||||
}
|
||||
|
||||
for (const auto &frame : ui->gridLayout_MetatileProperties->findChildren<QFrame*>()) {
|
||||
ui->gridLayout_MetatileProperties->removeWidget(frame);
|
||||
}
|
||||
ui->gridLayout_MetatileProperties->addWidget(ui->frame_Layers, 0, 0, this->numLayerViewRows, 1);
|
||||
|
||||
int row = 0;
|
||||
addWidgetToMetatileProperties(ui->frame_LayerType, &row, 2);
|
||||
if (porymapConfig.tilesetEditorLayerOrientation == Qt::Horizontal) {
|
||||
// When the layer view's orientation is horizontal we only allow the
|
||||
// layer type selector to share the row with the layer view.
|
||||
row = this->numLayerViewRows;
|
||||
}
|
||||
addWidgetToMetatileProperties(ui->frame_MetatileBehavior, &row, 2);
|
||||
addWidgetToMetatileProperties(ui->frame_EncounterType, &row, 2);
|
||||
addWidgetToMetatileProperties(ui->frame_TerrainType, &row, 2);
|
||||
addWidgetToMetatileProperties(ui->frame_RawAttributesValue, &row, 2);
|
||||
addWidgetToMetatileProperties(ui->frame_MetatileLabel, &row, 2);
|
||||
}
|
||||
|
||||
void TilesetEditor::addWidgetToMetatileProperties(QWidget *w, int *row, int rowSpan) {
|
||||
if (w->isVisibleTo(ui->frame_Properties)) {
|
||||
int col = (*row < this->numLayerViewRows) ? 1 : 0; // Shift widget over if it shares the row with the layer view
|
||||
ui->gridLayout_MetatileProperties->addWidget(w, *row, col, rowSpan, -1);
|
||||
*row += rowSpan;
|
||||
}
|
||||
}
|
||||
|
||||
void TilesetEditor::initMetatileLayersItem() {
|
||||
Metatile *metatile = Tileset::getMetatile(this->getSelectedMetatileId(), this->primaryTileset, this->secondaryTileset);
|
||||
this->metatileLayersItem = new MetatileLayersItem(metatile, this->primaryTileset, this->secondaryTileset);
|
||||
connect(this->metatileLayersItem, &MetatileLayersItem::tileChanged,
|
||||
this, &TilesetEditor::onMetatileLayerTileChanged);
|
||||
connect(this->metatileLayersItem, &MetatileLayersItem::selectedTilesChanged,
|
||||
this, &TilesetEditor::onMetatileLayerSelectionChanged);
|
||||
connect(this->metatileLayersItem, &MetatileLayersItem::hoveredTileChanged, [this](const Tile &tile) {
|
||||
onHoveredTileChanged(tile);
|
||||
});
|
||||
connect(this->metatileLayersItem, &MetatileLayersItem::hoveredTileCleared,
|
||||
this, &TilesetEditor::onHoveredTileCleared);
|
||||
connect(this->metatileLayersItem, &MetatileLayersItem::tileChanged, [this](const QPoint &pos) { paintSelectedLayerTiles(pos); });
|
||||
connect(this->metatileLayersItem, &MetatileLayersItem::paletteChanged, [this](const QPoint &pos) { paintSelectedLayerTiles(pos, true); });
|
||||
connect(this->metatileLayersItem, &MetatileLayersItem::selectedTilesChanged, this, &TilesetEditor::onMetatileLayerSelectionChanged);
|
||||
connect(this->metatileLayersItem, &MetatileLayersItem::hoveredTileChanged, [this](const Tile &tile) { onHoveredTileChanged(tile); });
|
||||
connect(this->metatileLayersItem, &MetatileLayersItem::hoveredTileCleared, this, &TilesetEditor::onHoveredTileCleared);
|
||||
|
||||
bool showGrid = porymapConfig.showTilesetEditorLayerGrid;
|
||||
this->ui->actionLayer_Grid->setChecked(showGrid);
|
||||
@@ -253,12 +323,11 @@ void TilesetEditor::initMetatileLayersItem() {
|
||||
|
||||
this->metatileLayersScene = new QGraphicsScene;
|
||||
this->metatileLayersScene->addItem(this->metatileLayersItem);
|
||||
this->ui->graphicsView_metatileLayers->setScene(this->metatileLayersScene);
|
||||
this->ui->graphicsView_MetatileLayers->setScene(this->metatileLayersScene);
|
||||
}
|
||||
|
||||
void TilesetEditor::initTileSelector()
|
||||
{
|
||||
this->tileSelector = new TilesetEditorTileSelector(this->primaryTileset, this->secondaryTileset, projectConfig.getNumLayersInMetatile());
|
||||
void TilesetEditor::initTileSelector() {
|
||||
this->tileSelector = new TilesetEditorTileSelector(this->primaryTileset, this->secondaryTileset);
|
||||
connect(this->tileSelector, &TilesetEditorTileSelector::hoveredTileChanged, [this](uint16_t tileId) {
|
||||
onHoveredTileChanged(tileId);
|
||||
});
|
||||
@@ -281,7 +350,6 @@ void TilesetEditor::initSelectedTileItem() {
|
||||
this->selectedTileScene = new QGraphicsScene;
|
||||
this->drawSelectedTiles();
|
||||
this->ui->graphicsView_selectedTile->setScene(this->selectedTileScene);
|
||||
this->ui->graphicsView_selectedTile->setFixedSize(this->selectedTilePixmapItem->pixmap().width() + 2, this->selectedTilePixmapItem->pixmap().height() + 2);
|
||||
}
|
||||
|
||||
void TilesetEditor::initShortcuts() {
|
||||
@@ -344,13 +412,6 @@ void TilesetEditor::onWindowActivated() {
|
||||
}
|
||||
}
|
||||
|
||||
void TilesetEditor::initMetatileHistory() {
|
||||
metatileHistory.clear();
|
||||
MetatileHistoryItem *commit = new MetatileHistoryItem(0, nullptr, new Metatile(), QString(), QString());
|
||||
metatileHistory.push(commit);
|
||||
this->hasUnsavedChanges = false;
|
||||
}
|
||||
|
||||
void TilesetEditor::reset() {
|
||||
this->setTilesets(this->primaryTileset->name, this->secondaryTileset->name);
|
||||
if (this->paletteEditor)
|
||||
@@ -392,17 +453,16 @@ void TilesetEditor::drawSelectedTiles() {
|
||||
const int imgTileHeight = 16;
|
||||
this->selectedTileScene->clear();
|
||||
QList<Tile> tiles = this->tileSelector->getSelectedTiles();
|
||||
QPoint dimensions = this->tileSelector->getSelectionDimensions();
|
||||
QImage selectionImage(imgTileWidth * dimensions.x(), imgTileHeight * dimensions.y(), QImage::Format_RGBA8888);
|
||||
QSize dimensions = this->tileSelector->getSelectionDimensions();
|
||||
QImage selectionImage(imgTileWidth * dimensions.width(), imgTileHeight * dimensions.height(), QImage::Format_RGBA8888);
|
||||
QPainter painter(&selectionImage);
|
||||
int tileIndex = 0;
|
||||
for (int j = 0; j < dimensions.y(); j++) {
|
||||
for (int i = 0; i < dimensions.x(); i++) {
|
||||
auto tile = tiles.at(tileIndex);
|
||||
for (int y = 0; y < dimensions.height(); y++) {
|
||||
for (int x = 0; x < dimensions.width(); x++) {
|
||||
auto tile = tiles.at(tileIndex++);
|
||||
QImage tileImage = getPalettedTileImage(tile.tileId, this->primaryTileset, this->secondaryTileset, tile.palette, true).scaled(imgTileWidth, imgTileHeight);
|
||||
tile.flip(&tileImage);
|
||||
tileIndex++;
|
||||
painter.drawImage(i * imgTileWidth, j * imgTileHeight, tileImage);
|
||||
painter.drawImage(x * imgTileWidth, y * imgTileHeight, tileImage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -411,7 +471,6 @@ void TilesetEditor::drawSelectedTiles() {
|
||||
|
||||
QSize size(this->selectedTilePixmapItem->pixmap().width(), this->selectedTilePixmapItem->pixmap().height());
|
||||
this->ui->graphicsView_selectedTile->setSceneRect(0, 0, size.width(), size.height());
|
||||
this->ui->graphicsView_selectedTile->setFixedSize(size.width() + 2, size.height() + 2);
|
||||
}
|
||||
|
||||
void TilesetEditor::onHoveredMetatileChanged(uint16_t metatileId) {
|
||||
@@ -429,6 +488,7 @@ void TilesetEditor::onHoveredMetatileCleared() {
|
||||
|
||||
void TilesetEditor::onSelectedMetatileChanged(uint16_t metatileId) {
|
||||
this->metatile = Tileset::getMetatile(metatileId, this->primaryTileset, this->secondaryTileset);
|
||||
if (!this->metatile) return;
|
||||
|
||||
// The scripting API allows users to change metatiles in the project, and these changes are saved to disk.
|
||||
// The Tileset Editor (if open) needs to reflect these changes when the metatile is next displayed.
|
||||
@@ -440,11 +500,10 @@ void TilesetEditor::onSelectedMetatileChanged(uint16_t metatileId) {
|
||||
|
||||
this->metatileLayersItem->setMetatile(metatile);
|
||||
this->metatileLayersItem->draw();
|
||||
this->ui->graphicsView_metatileLayers->setFixedSize(this->metatileLayersItem->pixmap().width() + 2, this->metatileLayersItem->pixmap().height() + 2);
|
||||
|
||||
MetatileLabelPair labels = Tileset::getMetatileLabelPair(metatileId, this->primaryTileset, this->secondaryTileset);
|
||||
this->ui->lineEdit_metatileLabel->setText(labels.owned);
|
||||
this->ui->lineEdit_metatileLabel->setPlaceholderText(labels.shared);
|
||||
this->ui->lineEdit_MetatileLabel->setText(labels.owned);
|
||||
this->ui->lineEdit_MetatileLabel->setPlaceholderText(labels.shared);
|
||||
|
||||
refreshMetatileAttributes();
|
||||
}
|
||||
@@ -470,45 +529,44 @@ void TilesetEditor::onHoveredTileCleared() {
|
||||
this->ui->statusbar->clearMessage();
|
||||
}
|
||||
|
||||
void TilesetEditor::onMetatileLayerTileChanged(int x, int y) {
|
||||
static const QList<QPoint> tileCoords = QList<QPoint>{
|
||||
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),
|
||||
};
|
||||
void TilesetEditor::paintSelectedLayerTiles(const QPoint &pos, bool paletteOnly) {
|
||||
if (!this->metatile) return;
|
||||
|
||||
bool changed = false;
|
||||
Metatile *prevMetatile = new Metatile(*this->metatile);
|
||||
QPoint dimensions = this->tileSelector->getSelectionDimensions();
|
||||
QSize dimensions = this->tileSelector->getSelectionDimensions();
|
||||
QList<Tile> tiles = this->tileSelector->getSelectedTiles();
|
||||
int selectedTileIndex = 0;
|
||||
int srcTileIndex = 0;
|
||||
int maxTileIndex = projectConfig.getNumTilesInMetatile();
|
||||
for (int j = 0; j < dimensions.y(); j++) {
|
||||
for (int i = 0; i < dimensions.x(); i++) {
|
||||
int tileIndex = ((x + i) / 2 * 4) + ((y + j) * 2) + ((x + i) % 2);
|
||||
if (tileIndex < maxTileIndex
|
||||
&& tileCoords.at(tileIndex).x() >= x
|
||||
&& tileCoords.at(tileIndex).y() >= y){
|
||||
Tile &tile = this->metatile->tiles[tileIndex];
|
||||
tile.tileId = tiles.at(selectedTileIndex).tileId;
|
||||
tile.xflip = tiles.at(selectedTileIndex).xflip;
|
||||
tile.yflip = tiles.at(selectedTileIndex).yflip;
|
||||
tile.palette = tiles.at(selectedTileIndex).palette;
|
||||
if (this->tileSelector->showUnused) {
|
||||
this->tileSelector->usedTiles[tile.tileId] += 1;
|
||||
this->tileSelector->usedTiles[prevMetatile->tiles[tileIndex].tileId] -= 1;
|
||||
for (int y = 0; y < dimensions.height(); y++) {
|
||||
for (int x = 0; x < dimensions.width(); x++) {
|
||||
int destTileIndex = this->metatileLayersItem->posToTileIndex(pos.x() + x, pos.y() + y);
|
||||
if (destTileIndex < maxTileIndex) {
|
||||
Tile &destTile = this->metatile->tiles[destTileIndex];
|
||||
const Tile srcTile = tiles.at(srcTileIndex++);
|
||||
if (paletteOnly) {
|
||||
if (srcTile.palette == destTile.palette)
|
||||
continue; // Ignore no-ops for edit history
|
||||
destTile.palette = srcTile.palette;
|
||||
} else {
|
||||
if (srcTile == destTile)
|
||||
continue; // Ignore no-ops for edit history
|
||||
|
||||
// Update tile usage count
|
||||
if (this->tileSelector->showUnused && destTile.tileId != srcTile.tileId) {
|
||||
this->tileSelector->usedTiles[srcTile.tileId] += 1;
|
||||
this->tileSelector->usedTiles[destTile.tileId] -= 1;
|
||||
}
|
||||
destTile = srcTile;
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
selectedTileIndex++;
|
||||
}
|
||||
}
|
||||
if (!changed) {
|
||||
delete prevMetatile;
|
||||
return;
|
||||
}
|
||||
|
||||
this->metatileSelector->drawSelectedMetatile();
|
||||
this->metatileLayersItem->draw();
|
||||
@@ -516,26 +574,19 @@ void TilesetEditor::onMetatileLayerTileChanged(int x, int y) {
|
||||
this->commitMetatileChange(prevMetatile);
|
||||
}
|
||||
|
||||
void TilesetEditor::onMetatileLayerSelectionChanged(QPoint selectionOrigin, int width, int height) {
|
||||
void TilesetEditor::onMetatileLayerSelectionChanged(const QPoint &selectionOrigin, const QSize &size) {
|
||||
QList<Tile> tiles;
|
||||
QList<int> tileIdxs;
|
||||
int x = selectionOrigin.x();
|
||||
int y = selectionOrigin.y();
|
||||
int maxTileIndex = projectConfig.getNumTilesInMetatile();
|
||||
for (int j = 0; j < height; j++) {
|
||||
for (int i = 0; i < width; i++) {
|
||||
int tileIndex = ((x + i) / 2 * 4) + ((y + j) * 2) + ((x + i) % 2);
|
||||
if (tileIndex < maxTileIndex) {
|
||||
tiles.append(this->metatile->tiles.at(tileIndex));
|
||||
tileIdxs.append(tileIndex);
|
||||
}
|
||||
for (int y = 0; y < size.height(); y++) {
|
||||
for (int x = 0; x < size.width(); x++) {
|
||||
int tileIndex = this->metatileLayersItem->posToTileIndex(selectionOrigin.x() + x, selectionOrigin.y() + y);
|
||||
tiles.append(this->metatile ? this->metatile->tiles.value(tileIndex) : Tile());
|
||||
}
|
||||
}
|
||||
|
||||
this->tileSelector->setExternalSelection(width, height, tiles, tileIdxs);
|
||||
if (width == 1 && height == 1) {
|
||||
this->tileSelector->setExternalSelection(size.width(), size.height(), tiles);
|
||||
if (size == QSize(1,1)) {
|
||||
setPaletteId(tiles[0].palette);
|
||||
this->tileSelector->highlight(static_cast<uint16_t>(tiles[0].tileId));
|
||||
this->tileSelector->highlight(tiles[0].tileId);
|
||||
this->redrawTileSelector();
|
||||
}
|
||||
this->metatileLayersItem->clearLastModifiedCoords();
|
||||
@@ -566,21 +617,17 @@ void TilesetEditor::refreshTileFlips() {
|
||||
|
||||
void TilesetEditor::setMetatileLabel(QString label)
|
||||
{
|
||||
this->ui->lineEdit_metatileLabel->setText(label);
|
||||
this->ui->lineEdit_MetatileLabel->setText(label);
|
||||
commitMetatileLabel();
|
||||
}
|
||||
|
||||
void TilesetEditor::on_lineEdit_metatileLabel_editingFinished()
|
||||
{
|
||||
commitMetatileLabel();
|
||||
}
|
||||
void TilesetEditor::commitMetatileLabel() {
|
||||
if (!this->metatile) return;
|
||||
|
||||
void TilesetEditor::commitMetatileLabel()
|
||||
{
|
||||
// Only commit if the field has changed.
|
||||
uint16_t metatileId = this->getSelectedMetatileId();
|
||||
QString oldLabel = Tileset::getOwnedMetatileLabel(metatileId, this->primaryTileset, this->secondaryTileset);
|
||||
QString newLabel = this->ui->lineEdit_metatileLabel->text();
|
||||
QString newLabel = this->ui->lineEdit_MetatileLabel->text();
|
||||
if (oldLabel != newLabel) {
|
||||
Metatile *prevMetatile = new Metatile(*this->metatile);
|
||||
Tileset::setMetatileLabel(metatileId, newLabel, this->primaryTileset, this->secondaryTileset);
|
||||
@@ -588,17 +635,17 @@ void TilesetEditor::commitMetatileLabel()
|
||||
}
|
||||
}
|
||||
|
||||
void TilesetEditor::commitMetatileAndLabelChange(Metatile * prevMetatile, QString prevLabel)
|
||||
{
|
||||
metatileHistory.push(new MetatileHistoryItem(this->getSelectedMetatileId(),
|
||||
prevMetatile, new Metatile(*this->metatile),
|
||||
prevLabel, this->ui->lineEdit_metatileLabel->text()));
|
||||
this->hasUnsavedChanges = true;
|
||||
void TilesetEditor::commitMetatileAndLabelChange(Metatile * prevMetatile, QString prevLabel) {
|
||||
if (!this->metatile) return;
|
||||
|
||||
commit(new MetatileHistoryItem(this->getSelectedMetatileId(),
|
||||
prevMetatile, new Metatile(*this->metatile),
|
||||
prevLabel, this->ui->lineEdit_MetatileLabel->text()));
|
||||
}
|
||||
|
||||
void TilesetEditor::commitMetatileChange(Metatile * prevMetatile)
|
||||
{
|
||||
this->commitMetatileAndLabelChange(prevMetatile, this->ui->lineEdit_metatileLabel->text());
|
||||
this->commitMetatileAndLabelChange(prevMetatile, this->ui->lineEdit_MetatileLabel->text());
|
||||
}
|
||||
|
||||
uint32_t TilesetEditor::attributeNameToValue(Metatile::Attr attribute, const QString &text, bool *ok) {
|
||||
@@ -617,15 +664,14 @@ uint32_t TilesetEditor::attributeNameToValue(Metatile::Attr attribute, const QSt
|
||||
}
|
||||
} else if (attribute == Metatile::Attr::LayerType) {
|
||||
// The layer type text is not editable, it uses special display names. Just get the index of the display name.
|
||||
int i = ui->comboBox_layerType->findText(text);
|
||||
int i = ui->comboBox_LayerType->findText(text);
|
||||
if (i >= 0) return i;
|
||||
}
|
||||
return text.toUInt(ok, 0);
|
||||
}
|
||||
|
||||
void TilesetEditor::commitAttributeFromComboBox(Metatile::Attr attribute, NoScrollComboBox *combo) {
|
||||
if (!this->metatile)
|
||||
return;
|
||||
if (!this->metatile) return;
|
||||
|
||||
bool ok;
|
||||
uint32_t newValue = this->attributeNameToValue(attribute, combo->currentText(), &ok);
|
||||
@@ -635,8 +681,8 @@ void TilesetEditor::commitAttributeFromComboBox(Metatile::Attr attribute, NoScro
|
||||
this->commitMetatileChange(prevMetatile);
|
||||
|
||||
// When an attribute changes we also need to update the raw value display.
|
||||
const QSignalBlocker b_RawAttributesValue(ui->spinBox_rawAttributesValue);
|
||||
ui->spinBox_rawAttributesValue->setValue(this->metatile->getAttributes());
|
||||
const QSignalBlocker b_RawAttributesValue(ui->spinBox_RawAttributesValue);
|
||||
ui->spinBox_RawAttributesValue->setValue(this->metatile->getAttributes());
|
||||
}
|
||||
|
||||
// Update the text in the combo box to reflect the final value.
|
||||
@@ -646,7 +692,9 @@ void TilesetEditor::commitAttributeFromComboBox(Metatile::Attr attribute, NoScro
|
||||
}
|
||||
|
||||
void TilesetEditor::onRawAttributesEdited() {
|
||||
uint32_t newAttributes = ui->spinBox_rawAttributesValue->value();
|
||||
if (!this->metatile) return;
|
||||
|
||||
uint32_t newAttributes = ui->spinBox_RawAttributesValue->value();
|
||||
if (newAttributes != this->metatile->getAttributes()) {
|
||||
Metatile *prevMetatile = new Metatile(*this->metatile);
|
||||
this->metatile->setAttributes(newAttributes);
|
||||
@@ -658,34 +706,34 @@ void TilesetEditor::onRawAttributesEdited() {
|
||||
void TilesetEditor::refreshMetatileAttributes() {
|
||||
if (!this->metatile) return;
|
||||
|
||||
const QSignalBlocker b_MetatileBehaviors(ui->comboBox_metatileBehaviors);
|
||||
const QSignalBlocker b_EncounterType(ui->comboBox_encounterType);
|
||||
const QSignalBlocker b_TerrainType(ui->comboBox_terrainType);
|
||||
const QSignalBlocker b_LayerType(ui->comboBox_layerType);
|
||||
const QSignalBlocker b_RawAttributesValue(ui->spinBox_rawAttributesValue);
|
||||
ui->comboBox_metatileBehaviors->setHexItem(this->metatile->behavior());
|
||||
ui->comboBox_encounterType->setHexItem(this->metatile->encounterType());
|
||||
ui->comboBox_terrainType->setHexItem(this->metatile->terrainType());
|
||||
ui->comboBox_layerType->setHexItem(this->metatile->layerType());
|
||||
ui->spinBox_rawAttributesValue->setValue(this->metatile->getAttributes());
|
||||
const QSignalBlocker b_MetatileBehaviors(ui->comboBox_MetatileBehaviors);
|
||||
const QSignalBlocker b_EncounterType(ui->comboBox_EncounterType);
|
||||
const QSignalBlocker b_TerrainType(ui->comboBox_TerrainType);
|
||||
const QSignalBlocker b_LayerType(ui->comboBox_LayerType);
|
||||
const QSignalBlocker b_RawAttributesValue(ui->spinBox_RawAttributesValue);
|
||||
ui->comboBox_MetatileBehaviors->setHexItem(this->metatile->behavior());
|
||||
ui->comboBox_EncounterType->setHexItem(this->metatile->encounterType());
|
||||
ui->comboBox_TerrainType->setHexItem(this->metatile->terrainType());
|
||||
ui->comboBox_LayerType->setHexItem(this->metatile->layerType());
|
||||
ui->spinBox_RawAttributesValue->setValue(this->metatile->getAttributes());
|
||||
|
||||
this->metatileSelector->drawSelectedMetatile();
|
||||
}
|
||||
|
||||
void TilesetEditor::commitMetatileBehavior() {
|
||||
commitAttributeFromComboBox(Metatile::Attr::Behavior, ui->comboBox_metatileBehaviors);
|
||||
commitAttributeFromComboBox(Metatile::Attr::Behavior, ui->comboBox_MetatileBehaviors);
|
||||
}
|
||||
|
||||
void TilesetEditor::commitEncounterType() {
|
||||
commitAttributeFromComboBox(Metatile::Attr::EncounterType, ui->comboBox_encounterType);
|
||||
commitAttributeFromComboBox(Metatile::Attr::EncounterType, ui->comboBox_EncounterType);
|
||||
}
|
||||
|
||||
void TilesetEditor::commitTerrainType() {
|
||||
commitAttributeFromComboBox(Metatile::Attr::TerrainType, ui->comboBox_terrainType);
|
||||
commitAttributeFromComboBox(Metatile::Attr::TerrainType, ui->comboBox_TerrainType);
|
||||
};
|
||||
|
||||
void TilesetEditor::commitLayerType() {
|
||||
commitAttributeFromComboBox(Metatile::Attr::LayerType, ui->comboBox_layerType);
|
||||
commitAttributeFromComboBox(Metatile::Attr::LayerType, ui->comboBox_LayerType);
|
||||
this->metatileSelector->drawSelectedMetatile(); // Changing the layer type can affect how fully transparent metatiles appear
|
||||
}
|
||||
|
||||
@@ -695,6 +743,7 @@ bool TilesetEditor::save() {
|
||||
this->lockSelection = true;
|
||||
|
||||
bool success = this->project->saveTilesets(this->primaryTileset, this->secondaryTileset);
|
||||
applyMetatileSwapsToLayouts();
|
||||
emit this->tilesetsSaved(this->primaryTileset->name, this->secondaryTileset->name);
|
||||
if (this->paletteEditor) {
|
||||
this->paletteEditor->setTilesets(this->primaryTileset, this->secondaryTileset);
|
||||
@@ -745,7 +794,7 @@ void TilesetEditor::importTilesetTiles(Tileset *tileset) {
|
||||
int numTilesWide = image.width() / Tile::pixelWidth();
|
||||
int numTilesHigh = image.height() / Tile::pixelHeight();
|
||||
int totalTiles = numTilesHigh * numTilesWide;
|
||||
int maxAllowedTiles = primary ? Project::getNumTilesPrimary() : Project::getNumTilesTotal() - Project::getNumTilesPrimary();
|
||||
int maxAllowedTiles = primary ? Project::getNumTilesPrimary() : Project::getNumTilesSecondary();
|
||||
if (totalTiles > maxAllowedTiles) {
|
||||
ErrorMessage::show(QStringLiteral("Failed to import tiles."),
|
||||
QString("The maximum number of tiles allowed in the %1 tileset is %2, but the provided image contains %3 total tiles.")
|
||||
@@ -846,8 +895,15 @@ void TilesetEditor::on_actionChange_Metatiles_Count_triggered()
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
this->primaryTileset->resizeMetatiles(primarySpinBox->value());
|
||||
this->secondaryTileset->resizeMetatiles(secondarySpinBox->value());
|
||||
this->metatileSelector->updateSelectedMetatile();
|
||||
this->refresh();
|
||||
|
||||
// Our selected metatile ID may have become invalid. Make sure it's in-bounds.
|
||||
uint16_t metatileId = this->metatileSelector->getSelectedMetatileId();
|
||||
Tileset *tileset = Tileset::getMetatileTileset(metatileId, this->primaryTileset, this->secondaryTileset);
|
||||
if (tileset && !tileset->containsMetatileId(metatileId)) {
|
||||
this->metatileSelector->select(qBound(tileset->firstMetatileId(), metatileId, tileset->lastMetatileId()));
|
||||
}
|
||||
|
||||
refresh();
|
||||
this->hasUnsavedChanges = true;
|
||||
}
|
||||
}
|
||||
@@ -869,23 +925,22 @@ void TilesetEditor::onPaletteEditorChangedPaletteColor() {
|
||||
this->hasUnsavedChanges = true;
|
||||
}
|
||||
|
||||
bool TilesetEditor::replaceMetatile(uint16_t metatileId, const Metatile * src, QString newLabel)
|
||||
{
|
||||
bool TilesetEditor::replaceMetatile(uint16_t metatileId, const Metatile &src, QString newLabel) {
|
||||
Metatile * dest = Tileset::getMetatile(metatileId, this->primaryTileset, this->secondaryTileset);
|
||||
QString oldLabel = Tileset::getOwnedMetatileLabel(metatileId, this->primaryTileset, this->secondaryTileset);
|
||||
if (!dest || !src || (*dest == *src && oldLabel == newLabel))
|
||||
if (!dest || (*dest == src && oldLabel == newLabel))
|
||||
return false;
|
||||
|
||||
Tileset::setMetatileLabel(metatileId, newLabel, this->primaryTileset, this->secondaryTileset);
|
||||
if (metatileId == this->getSelectedMetatileId())
|
||||
this->ui->lineEdit_metatileLabel->setText(newLabel);
|
||||
this->ui->lineEdit_MetatileLabel->setText(newLabel);
|
||||
|
||||
// Update tile usage if any tiles changed
|
||||
if (this->tileSelector && this->tileSelector->showUnused) {
|
||||
int numTiles = projectConfig.getNumTilesInMetatile();
|
||||
for (int i = 0; i < numTiles; i++) {
|
||||
if (src->tiles[i].tileId != dest->tiles[i].tileId) {
|
||||
this->tileSelector->usedTiles[src->tiles[i].tileId] += 1;
|
||||
if (src.tiles[i].tileId != dest->tiles[i].tileId) {
|
||||
this->tileSelector->usedTiles[src.tiles[i].tileId] += 1;
|
||||
this->tileSelector->usedTiles[dest->tiles[i].tileId] -= 1;
|
||||
}
|
||||
}
|
||||
@@ -893,7 +948,7 @@ bool TilesetEditor::replaceMetatile(uint16_t metatileId, const Metatile * src, Q
|
||||
}
|
||||
|
||||
this->metatile = dest;
|
||||
*this->metatile = *src;
|
||||
*this->metatile = src;
|
||||
this->metatileSelector->select(metatileId);
|
||||
this->metatileSelector->drawMetatile(metatileId);
|
||||
this->metatileLayersItem->draw();
|
||||
@@ -902,29 +957,52 @@ bool TilesetEditor::replaceMetatile(uint16_t metatileId, const Metatile * src, Q
|
||||
return true;
|
||||
}
|
||||
|
||||
void TilesetEditor::on_actionUndo_triggered()
|
||||
{
|
||||
MetatileHistoryItem *commit = this->metatileHistory.current();
|
||||
if (!commit) return;
|
||||
Metatile *prev = commit->prevMetatile;
|
||||
if (!prev) return;
|
||||
this->metatileHistory.back();
|
||||
this->replaceMetatile(commit->metatileId, prev, commit->prevLabel);
|
||||
void TilesetEditor::initMetatileHistory() {
|
||||
this->metatileHistory.clear();
|
||||
updateEditHistoryActions();
|
||||
this->hasUnsavedChanges = false;
|
||||
}
|
||||
|
||||
void TilesetEditor::on_actionRedo_triggered()
|
||||
{
|
||||
void TilesetEditor::commit(MetatileHistoryItem *item) {
|
||||
this->metatileHistory.push(item);
|
||||
updateEditHistoryActions();
|
||||
this->hasUnsavedChanges = true;
|
||||
}
|
||||
|
||||
void TilesetEditor::updateEditHistoryActions() {
|
||||
ui->actionUndo->setEnabled(this->metatileHistory.canUndo());
|
||||
ui->actionRedo->setEnabled(this->metatileHistory.canRedo());
|
||||
}
|
||||
|
||||
void TilesetEditor::on_actionUndo_triggered() {
|
||||
MetatileHistoryItem *commit = this->metatileHistory.current();
|
||||
if (!commit) return;
|
||||
this->metatileHistory.back();
|
||||
|
||||
if (commit->isSwap) {
|
||||
swapMetatiles(commit->swapMetatileId, commit->metatileId);
|
||||
} else if (commit->prevMetatile) {
|
||||
replaceMetatile(commit->metatileId, *commit->prevMetatile, commit->prevLabel);
|
||||
};
|
||||
updateEditHistoryActions();
|
||||
}
|
||||
|
||||
void TilesetEditor::on_actionRedo_triggered() {
|
||||
MetatileHistoryItem *commit = this->metatileHistory.next();
|
||||
if (!commit) return;
|
||||
this->replaceMetatile(commit->metatileId, commit->newMetatile, commit->newLabel);
|
||||
|
||||
if (commit->isSwap) {
|
||||
swapMetatiles(commit->metatileId, commit->swapMetatileId);
|
||||
} else if (commit->newMetatile) {
|
||||
replaceMetatile(commit->metatileId, *commit->newMetatile, commit->newLabel);
|
||||
}
|
||||
updateEditHistoryActions();
|
||||
}
|
||||
|
||||
void TilesetEditor::on_actionCut_triggered()
|
||||
{
|
||||
Metatile * empty = new Metatile(projectConfig.getNumTilesInMetatile());
|
||||
this->copyMetatile(true);
|
||||
this->pasteMetatile(empty, "");
|
||||
delete empty;
|
||||
this->pasteMetatile(Metatile(projectConfig.getNumTilesInMetatile()), "");
|
||||
}
|
||||
|
||||
void TilesetEditor::on_actionCopy_triggered()
|
||||
@@ -934,7 +1012,9 @@ void TilesetEditor::on_actionCopy_triggered()
|
||||
|
||||
void TilesetEditor::on_actionPaste_triggered()
|
||||
{
|
||||
this->pasteMetatile(this->copiedMetatile, this->copiedMetatileLabel);
|
||||
if (this->copiedMetatile) {
|
||||
this->pasteMetatile(*this->copiedMetatile, this->copiedMetatileLabel);
|
||||
}
|
||||
}
|
||||
|
||||
void TilesetEditor::copyMetatile(bool cut) {
|
||||
@@ -947,14 +1027,17 @@ void TilesetEditor::copyMetatile(bool cut) {
|
||||
else
|
||||
*this->copiedMetatile = *toCopy;
|
||||
|
||||
ui->actionPaste->setEnabled(true);
|
||||
|
||||
// Don't try to copy the label unless it's a cut, these should be unique to each metatile.
|
||||
this->copiedMetatileLabel = cut ? Tileset::getOwnedMetatileLabel(metatileId, this->primaryTileset, this->secondaryTileset) : QString();
|
||||
}
|
||||
|
||||
void TilesetEditor::pasteMetatile(const Metatile * toPaste, QString newLabel)
|
||||
{
|
||||
void TilesetEditor::pasteMetatile(const Metatile &toPaste, QString newLabel) {
|
||||
if (!this->metatile) return;
|
||||
|
||||
Metatile *prevMetatile = new Metatile(*this->metatile);
|
||||
QString prevLabel = this->ui->lineEdit_metatileLabel->text();
|
||||
QString prevLabel = this->ui->lineEdit_MetatileLabel->text();
|
||||
if (newLabel.isNull()) newLabel = prevLabel; // Don't change the label if one wasn't copied
|
||||
uint16_t metatileId = this->getSelectedMetatileId();
|
||||
if (!this->replaceMetatile(metatileId, toPaste, newLabel)) {
|
||||
@@ -1055,15 +1138,13 @@ void TilesetEditor::importAdvanceMapMetatiles(Tileset *tileset) {
|
||||
uint16_t metatileId = static_cast<uint16_t>(metatileIdBase + i);
|
||||
QString prevLabel = Tileset::getOwnedMetatileLabel(metatileId, this->primaryTileset, this->secondaryTileset);
|
||||
Metatile *prevMetatile = new Metatile(*tileset->metatileAt(i));
|
||||
MetatileHistoryItem *commit = new MetatileHistoryItem(metatileId,
|
||||
prevMetatile, new Metatile(*metatiles.at(i)),
|
||||
prevLabel, prevLabel);
|
||||
metatileHistory.push(commit);
|
||||
commit(new MetatileHistoryItem(metatileId,
|
||||
prevMetatile, new Metatile(*metatiles.at(i)),
|
||||
prevLabel, prevLabel));
|
||||
}
|
||||
|
||||
tileset->setMetatiles(metatiles);
|
||||
this->refresh();
|
||||
this->hasUnsavedChanges = true;
|
||||
}
|
||||
|
||||
void TilesetEditor::on_actionShow_Unused_toggled(bool checked) {
|
||||
@@ -1152,59 +1233,28 @@ void TilesetEditor::countTileUsage() {
|
||||
this->tileSelector->usedTiles.resize(Project::getNumTilesTotal());
|
||||
this->tileSelector->usedTiles.fill(0);
|
||||
|
||||
QSet<Tileset*> primaryTilesets;
|
||||
QSet<Tileset*> secondaryTilesets;
|
||||
|
||||
for (const auto &layoutId : this->project->layoutIds()) {
|
||||
Layout *layout = this->project->getLayout(layoutId);
|
||||
if (layout->tileset_primary_label == this->primaryTileset->name
|
||||
|| layout->tileset_secondary_label == this->secondaryTileset->name) {
|
||||
// need to check metatiles
|
||||
this->project->loadLayoutTilesets(layout);
|
||||
if (layout->tileset_primary && layout->tileset_secondary) {
|
||||
primaryTilesets.insert(layout->tileset_primary);
|
||||
secondaryTilesets.insert(layout->tileset_secondary);
|
||||
auto countTilesetTileUsage = [this](Tileset *searchTileset) {
|
||||
// Count usage of our search tileset's tiles (in itself, and in any tilesets it gets paired with).
|
||||
QSet<QString> tilesetNames = this->project->getPairedTilesetLabels(searchTileset);
|
||||
tilesetNames.insert(searchTileset->name);
|
||||
for (const auto &tilesetName : tilesetNames) {
|
||||
Tileset *tileset = this->project->getTileset(tilesetName);
|
||||
if (!tileset) continue;
|
||||
for (const auto &metatile : tileset->metatiles()) {
|
||||
for (const auto &tile : metatile->tiles) {
|
||||
if (searchTileset->containsTileId(tile.tileId)) {
|
||||
this->tileSelector->usedTiles[tile.tileId]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// check primary tilesets that are used with this secondary tileset for
|
||||
// reference to secondary tiles in primary metatiles
|
||||
for (const auto &tileset : primaryTilesets) {
|
||||
for (const auto &metatile : tileset->metatiles()) {
|
||||
for (const auto &tile : metatile->tiles) {
|
||||
if (tile.tileId >= Project::getNumTilesPrimary())
|
||||
this->tileSelector->usedTiles[tile.tileId]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// do the opposite for primary tiles in secondary metatiles
|
||||
for (Tileset *tileset : secondaryTilesets) {
|
||||
for (const auto &metatile : tileset->metatiles()) {
|
||||
for (const auto &tile : metatile->tiles) {
|
||||
if (tile.tileId < Project::getNumTilesPrimary())
|
||||
this->tileSelector->usedTiles[tile.tileId]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check this primary tileset metatiles
|
||||
for (const auto &metatile : this->primaryTileset->metatiles()) {
|
||||
for (const auto &tile : metatile->tiles) {
|
||||
this->tileSelector->usedTiles[tile.tileId]++;
|
||||
}
|
||||
}
|
||||
|
||||
// and the secondary metatiles
|
||||
for (const auto &metatile : this->secondaryTileset->metatiles()) {
|
||||
for (const auto &tile : metatile->tiles) {
|
||||
this->tileSelector->usedTiles[tile.tileId]++;
|
||||
}
|
||||
}
|
||||
countTilesetTileUsage(this->primaryTileset);
|
||||
countTilesetTileUsage(this->secondaryTileset);
|
||||
}
|
||||
|
||||
void TilesetEditor::on_copyButton_metatileLabel_clicked() {
|
||||
void TilesetEditor::on_copyButton_MetatileLabel_clicked() {
|
||||
uint16_t metatileId = this->getSelectedMetatileId();
|
||||
QString label = Tileset::getMetatileLabel(metatileId, this->primaryTileset, this->secondaryTileset);
|
||||
if (label.isEmpty()) return;
|
||||
@@ -1212,7 +1262,7 @@ void TilesetEditor::on_copyButton_metatileLabel_clicked() {
|
||||
if (tileset)
|
||||
label.prepend(tileset->getMetatileLabelPrefix());
|
||||
QGuiApplication::clipboard()->setText(label);
|
||||
QToolTip::showText(this->ui->copyButton_metatileLabel->mapToGlobal(QPoint(0, 0)), "Copied!");
|
||||
QToolTip::showText(this->ui->copyButton_MetatileLabel->mapToGlobal(QPoint(0, 0)), "Copied!");
|
||||
}
|
||||
|
||||
void TilesetEditor::on_horizontalSlider_MetatilesZoom_valueChanged(int value) {
|
||||
@@ -1267,3 +1317,118 @@ void TilesetEditor::redrawTileSelector() {
|
||||
this->ui->scrollArea_Tiles->ensureVisible(pos.x(), pos.y(), viewport->width() / 2, viewport->height() / 2);
|
||||
}
|
||||
}
|
||||
|
||||
void TilesetEditor::commitMetatileSwap(uint16_t metatileIdA, uint16_t metatileIdB) {
|
||||
if (swapMetatiles(metatileIdA, metatileIdB)) {
|
||||
commit(new MetatileHistoryItem(metatileIdA, metatileIdB));
|
||||
}
|
||||
}
|
||||
|
||||
bool TilesetEditor::swapMetatiles(uint16_t metatileIdA, uint16_t metatileIdB) {
|
||||
this->metatileSelector->clearSwapSelection();
|
||||
|
||||
QList<Metatile*> metatiles;
|
||||
for (const auto &metatileId : {metatileIdA, metatileIdB}) {
|
||||
Metatile *metatile = Tileset::getMetatile(metatileId, this->primaryTileset, this->secondaryTileset);
|
||||
if (metatile) {
|
||||
metatiles.append(metatile);
|
||||
} else {
|
||||
logError(QString("Failed to load metatile %1 for swap.").arg(Metatile::getMetatileIdString(metatileId)));
|
||||
}
|
||||
}
|
||||
if (metatiles.length() < 2)
|
||||
return false;
|
||||
|
||||
// Swap the metatile data in the tileset
|
||||
Metatile tempMetatile = *metatiles.at(0);
|
||||
QString tempLabel = Tileset::getOwnedMetatileLabel(metatileIdA, this->primaryTileset, this->secondaryTileset);
|
||||
replaceMetatile(metatileIdA, *metatiles.at(1), Tileset::getOwnedMetatileLabel(metatileIdB, this->primaryTileset, this->secondaryTileset));
|
||||
replaceMetatile(metatileIdB, tempMetatile, tempLabel);
|
||||
|
||||
// Record this swap so that we can update the layouts later.
|
||||
// If this is the inverse of the most recent swap (e.g. from Undo), we instead remove that swap to save time.
|
||||
if (!this->metatileIdSwaps.isEmpty()) {
|
||||
auto recentSwapPair = this->metatileIdSwaps.constLast();
|
||||
if (recentSwapPair.first == metatileIdB && recentSwapPair.second == metatileIdA) {
|
||||
this->metatileIdSwaps.removeLast();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
this->metatileIdSwaps.append(QPair<uint16_t,uint16_t>(metatileIdA, metatileIdB));
|
||||
return true;
|
||||
}
|
||||
|
||||
// If any metatiles swapped positions, apply the swap to all relevant layouts.
|
||||
// We only do this once changes in the Tileset Editor are saved.
|
||||
void TilesetEditor::applyMetatileSwapsToLayouts() {
|
||||
if (this->metatileIdSwaps.isEmpty())
|
||||
return;
|
||||
|
||||
QProgressDialog progress("", "", 0, this->metatileIdSwaps.length(), this);
|
||||
progress.setAutoClose(true);
|
||||
progress.setWindowModality(Qt::WindowModal);
|
||||
progress.setModal(true);
|
||||
progress.setMinimumDuration(1000);
|
||||
progress.setValue(progress.minimum());
|
||||
|
||||
for (const auto &swapPair : this->metatileIdSwaps) {
|
||||
progress.setLabelText(QString("Swapping metatiles %1 and %2 in map layouts...")
|
||||
.arg(Metatile::getMetatileIdString(swapPair.first))
|
||||
.arg(Metatile::getMetatileIdString(swapPair.second)));
|
||||
applyMetatileSwapToLayouts(swapPair.first, swapPair.second);
|
||||
progress.setValue(progress.value() + 1);
|
||||
}
|
||||
this->metatileIdSwaps.clear();
|
||||
}
|
||||
|
||||
void TilesetEditor::applyMetatileSwapToLayouts(uint16_t metatileIdA, uint16_t metatileIdB) {
|
||||
struct TilesetPair {
|
||||
Tileset* primary = nullptr;
|
||||
Tileset* secondary = nullptr;
|
||||
};
|
||||
TilesetPair tilesets;
|
||||
|
||||
// Get which tilesets our swapped metatiles belong to.
|
||||
auto addSourceTileset = [this](uint16_t metatileId, TilesetPair *tilesets) {
|
||||
if (this->primaryTileset->containsMetatileId(metatileId)) {
|
||||
tilesets->primary = this->primaryTileset;
|
||||
} else if (this->secondaryTileset->containsMetatileId(metatileId)) {
|
||||
tilesets->secondary = this->secondaryTileset;
|
||||
} else {
|
||||
// Invalid metatile, shouldn't happen
|
||||
this->metatileSelector->removeFromSwapSelection(metatileId);
|
||||
}
|
||||
};
|
||||
addSourceTileset(metatileIdA, &tilesets);
|
||||
addSourceTileset(metatileIdB, &tilesets);
|
||||
if (!tilesets.primary && !tilesets.secondary) {
|
||||
return;
|
||||
}
|
||||
|
||||
// In each layout that uses the appropriate tileset(s), swap the two metatiles.
|
||||
QSet<QString> layoutIds = this->project->getTilesetLayoutIds(tilesets.primary, tilesets.secondary);
|
||||
for (const auto &layoutId : layoutIds) {
|
||||
Layout *layout = this->project->loadLayout(layoutId);
|
||||
if (!layout) continue;
|
||||
// Perform swap(s) in layout's main data.
|
||||
for (int y = 0; y < layout->height; y++)
|
||||
for (int x = 0; x < layout->width; x++) {
|
||||
uint16_t metatileId = layout->getMetatileId(x, y);
|
||||
if (metatileId == metatileIdA) {
|
||||
layout->setMetatileId(x, y, metatileIdB);
|
||||
} else if (metatileId == metatileIdB) {
|
||||
layout->setMetatileId(x, y, metatileIdA);
|
||||
} else continue;
|
||||
layout->hasUnsavedDataChanges = true;
|
||||
}
|
||||
// Perform swap(s) in layout's border data.
|
||||
for (auto &borderBlock : layout->border) {
|
||||
if (borderBlock.metatileId() == metatileIdA) {
|
||||
borderBlock.setMetatileId(metatileIdB);
|
||||
} else if (borderBlock.metatileId() == metatileIdB) {
|
||||
borderBlock.setMetatileId(metatileIdA);
|
||||
} else continue;
|
||||
layout->hasUnsavedDataChanges = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,17 @@ void TilesetEditorMetatileSelector::draw() {
|
||||
drawDivider();
|
||||
drawFilters();
|
||||
|
||||
drawSelection();
|
||||
if (this->inSwapMode) {
|
||||
QSet<uint16_t> metatileIds(this->swapMetatileIds.constBegin(), this->swapMetatileIds.constEnd());
|
||||
metatileIds.insert(this->lastHoveredMetatileId);
|
||||
for (const auto &metatileId : metatileIds) {
|
||||
bool ok;
|
||||
QPoint pos = metatileIdToPos(metatileId, &ok);
|
||||
if (ok) drawSelectionRect(pos, QSize(1,1), Qt::DashLine);
|
||||
}
|
||||
} else if (isValidMetatileId(this->selectedMetatileId)) {
|
||||
drawSelection();
|
||||
}
|
||||
}
|
||||
|
||||
bool TilesetEditorMetatileSelector::select(uint16_t metatileId) {
|
||||
@@ -103,53 +113,103 @@ void TilesetEditorMetatileSelector::setTilesets(Tileset *primaryTileset, Tileset
|
||||
draw();
|
||||
}
|
||||
|
||||
void TilesetEditorMetatileSelector::updateSelectedMetatile() {
|
||||
bool ok;
|
||||
uint16_t metatileId = posToMetatileId(getSelectionStart(), &ok);
|
||||
if (!ok)
|
||||
void TilesetEditorMetatileSelector::addToSwapSelection(uint16_t metatileId) {
|
||||
if (this->swapMetatileIds.contains(metatileId)) {
|
||||
return;
|
||||
}
|
||||
if (this->swapMetatileIds.length() >= 2) {
|
||||
this->swapMetatileIds.clear();
|
||||
}
|
||||
|
||||
this->selectedMetatileId = metatileId;
|
||||
emit selectedMetatileChanged(this->selectedMetatileId);
|
||||
this->swapMetatileIds.append(metatileId);
|
||||
draw();
|
||||
|
||||
if (this->swapMetatileIds.length() == 2) {
|
||||
emit swapRequested(this->swapMetatileIds.at(0), this->swapMetatileIds.at(1));
|
||||
}
|
||||
}
|
||||
|
||||
bool TilesetEditorMetatileSelector::shouldAcceptEvent(QGraphicsSceneMouseEvent *event) {
|
||||
bool ok;
|
||||
posToMetatileId(getCellPos(event->pos()), &ok);
|
||||
return ok;
|
||||
void TilesetEditorMetatileSelector::removeFromSwapSelection(uint16_t metatileId) {
|
||||
if (this->swapMetatileIds.removeOne(metatileId)) {
|
||||
draw();
|
||||
}
|
||||
}
|
||||
|
||||
void TilesetEditorMetatileSelector::clearSwapSelection() {
|
||||
if (this->swapMetatileIds.isEmpty())
|
||||
return;
|
||||
this->swapMetatileIds.clear();
|
||||
draw();
|
||||
}
|
||||
|
||||
void TilesetEditorMetatileSelector::mousePressEvent(QGraphicsSceneMouseEvent *event) {
|
||||
if (!shouldAcceptEvent(event)) return;
|
||||
QPoint cellPos = getCellPos(event->pos());
|
||||
|
||||
bool ok;
|
||||
uint16_t metatileId = posToMetatileId(cellPos, &ok);
|
||||
if (!ok) return;
|
||||
|
||||
SelectablePixmapItem::mousePressEvent(event);
|
||||
this->updateSelectedMetatile();
|
||||
this->selectedMetatileId = this->lastHoveredMetatileId = metatileId;
|
||||
emit selectedMetatileChanged(this->selectedMetatileId);
|
||||
this->prevCellPos = cellPos;
|
||||
}
|
||||
|
||||
void TilesetEditorMetatileSelector::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
|
||||
if (!shouldAcceptEvent(event)) return;
|
||||
QPoint cellPos = getCellPos(event->pos());
|
||||
if (cellPos == this->prevCellPos) return;
|
||||
|
||||
bool ok;
|
||||
uint16_t metatileId = posToMetatileId(cellPos, &ok);
|
||||
if (!ok) return;
|
||||
|
||||
SelectablePixmapItem::mouseMoveEvent(event);
|
||||
this->updateSelectedMetatile();
|
||||
this->selectedMetatileId = this->lastHoveredMetatileId = metatileId;
|
||||
emit selectedMetatileChanged(this->selectedMetatileId);
|
||||
emit hoveredMetatileChanged(this->selectedMetatileId);
|
||||
this->prevCellPos = cellPos;
|
||||
}
|
||||
|
||||
void TilesetEditorMetatileSelector::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
|
||||
if (!shouldAcceptEvent(event)) return;
|
||||
QPoint cellPos = getCellPos(event->pos());
|
||||
|
||||
bool ok;
|
||||
uint16_t metatileId = posToMetatileId(cellPos, &ok);
|
||||
if (!ok) return;
|
||||
|
||||
if (this->inSwapMode) {
|
||||
if (this->swapMetatileIds.contains(metatileId)) {
|
||||
this->removeFromSwapSelection(metatileId);
|
||||
} else {
|
||||
this->addToSwapSelection(metatileId);
|
||||
}
|
||||
}
|
||||
|
||||
SelectablePixmapItem::mouseReleaseEvent(event);
|
||||
this->updateSelectedMetatile();
|
||||
this->selectedMetatileId = this->lastHoveredMetatileId = metatileId;
|
||||
emit selectedMetatileChanged(this->selectedMetatileId);
|
||||
this->prevCellPos = cellPos;
|
||||
}
|
||||
|
||||
void TilesetEditorMetatileSelector::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
|
||||
QPoint cellPos = getCellPos(event->pos());
|
||||
if (cellPos == this->prevCellPos) return;
|
||||
|
||||
bool ok;
|
||||
uint16_t metatileId = posToMetatileId(getCellPos(event->pos()), &ok);
|
||||
uint16_t metatileId = posToMetatileId(cellPos, &ok);
|
||||
if (ok) {
|
||||
this->lastHoveredMetatileId = metatileId;
|
||||
emit this->hoveredMetatileChanged(metatileId);
|
||||
if (this->inSwapMode) draw();
|
||||
} else {
|
||||
emit this->hoveredMetatileCleared();
|
||||
}
|
||||
this->prevCellPos = cellPos;
|
||||
}
|
||||
|
||||
void TilesetEditorMetatileSelector::hoverLeaveEvent(QGraphicsSceneHoverEvent*) {
|
||||
emit this->hoveredMetatileCleared();
|
||||
this->prevCellPos = QPoint(-1,-1);
|
||||
}
|
||||
|
||||
uint16_t TilesetEditorMetatileSelector::posToMetatileId(const QPoint &pos, bool *ok) const {
|
||||
@@ -160,7 +220,7 @@ uint16_t TilesetEditorMetatileSelector::posToMetatileId(int x, int y, bool *ok)
|
||||
if (ok) *ok = true;
|
||||
int index = y * this->numMetatilesWide + x;
|
||||
uint16_t metatileId = static_cast<uint16_t>(index);
|
||||
if (this->primaryTileset && this->primaryTileset->contains(metatileId)) {
|
||||
if (this->primaryTileset && this->primaryTileset->containsMetatileId(metatileId)) {
|
||||
return metatileId;
|
||||
}
|
||||
|
||||
@@ -171,7 +231,7 @@ uint16_t TilesetEditorMetatileSelector::posToMetatileId(int x, int y, bool *ok)
|
||||
int numPrimaryRounded = numPrimaryMetatilesRounded();
|
||||
int firstSecondaryRow = numPrimaryRounded / this->numMetatilesWide;
|
||||
metatileId = static_cast<uint16_t>(Project::getNumMetatilesPrimary() + index - numPrimaryRounded);
|
||||
if (this->secondaryTileset && this->secondaryTileset->contains(metatileId) && y >= firstSecondaryRow) {
|
||||
if (this->secondaryTileset && this->secondaryTileset->containsMetatileId(metatileId) && y >= firstSecondaryRow) {
|
||||
return metatileId;
|
||||
}
|
||||
|
||||
@@ -180,12 +240,12 @@ uint16_t TilesetEditorMetatileSelector::posToMetatileId(int x, int y, bool *ok)
|
||||
}
|
||||
|
||||
QPoint TilesetEditorMetatileSelector::metatileIdToPos(uint16_t metatileId, bool *ok) const {
|
||||
if (this->primaryTileset && this->primaryTileset->contains(metatileId)) {
|
||||
if (this->primaryTileset && this->primaryTileset->containsMetatileId(metatileId)) {
|
||||
if (ok) *ok = true;
|
||||
int index = metatileId;
|
||||
return QPoint(index % this->numMetatilesWide, index / this->numMetatilesWide);
|
||||
}
|
||||
if (this->secondaryTileset && this->secondaryTileset->contains(metatileId)) {
|
||||
if (this->secondaryTileset && this->secondaryTileset->containsMetatileId(metatileId)) {
|
||||
if (ok) *ok = true;
|
||||
int index = metatileId - Project::getNumMetatilesPrimary() + numPrimaryMetatilesRounded();
|
||||
return QPoint(index % this->numMetatilesWide, index / this->numMetatilesWide);
|
||||
@@ -195,6 +255,12 @@ QPoint TilesetEditorMetatileSelector::metatileIdToPos(uint16_t metatileId, bool
|
||||
return QPoint(0,0);
|
||||
}
|
||||
|
||||
bool TilesetEditorMetatileSelector::isValidMetatileId(uint16_t metatileId) const {
|
||||
bool ok;
|
||||
metatileIdToPos(metatileId, &ok);
|
||||
return ok;
|
||||
}
|
||||
|
||||
QPoint TilesetEditorMetatileSelector::getMetatileIdCoordsOnWidget(uint16_t metatileId) const {
|
||||
QPoint pos = metatileIdToPos(metatileId);
|
||||
pos.rx() = (pos.x() * this->cellWidth) + (this->cellWidth / 2);
|
||||
@@ -323,3 +389,19 @@ void TilesetEditorMetatileSelector::drawCounts() {
|
||||
|
||||
this->setPixmap(metatilesPixmap);
|
||||
}
|
||||
|
||||
void TilesetEditorMetatileSelector::setSwapMode(bool enabled) {
|
||||
if (enabled == this->inSwapMode)
|
||||
return;
|
||||
this->inSwapMode = enabled;
|
||||
this->swapMetatileIds.clear();
|
||||
if (porymapConfig.prettyCursors) {
|
||||
if (enabled) {
|
||||
static const QCursor cursor = QCursor(QPixmap(":/icons/swap_cursor.ico"), 10, 10);
|
||||
setCursor(cursor);
|
||||
} else {
|
||||
unsetCursor();
|
||||
}
|
||||
}
|
||||
draw();
|
||||
}
|
||||
|
||||
@@ -4,14 +4,38 @@
|
||||
#include <QPainter>
|
||||
#include <QVector>
|
||||
|
||||
QPoint TilesetEditorTileSelector::getSelectionDimensions() const {
|
||||
QSize TilesetEditorTileSelector::getSelectionDimensions() const {
|
||||
if (this->externalSelection) {
|
||||
return QPoint(this->externalSelectionWidth, this->externalSelectionHeight);
|
||||
return QSize(this->externalSelectionWidth, this->externalSelectionHeight);
|
||||
} else {
|
||||
return SelectablePixmapItem::getSelectionDimensions();
|
||||
}
|
||||
}
|
||||
|
||||
void TilesetEditorTileSelector::setMaxSelectionSize(int width, int height) {
|
||||
width = qMax(1, width);
|
||||
height = qMax(1, height);
|
||||
SelectablePixmapItem::setMaxSelectionSize(width, height);
|
||||
if (this->externalSelection) {
|
||||
if (this->externalSelectionWidth > this->maxSelectionWidth || this->externalSelectionHeight > this->maxSelectionHeight) {
|
||||
// Crop external selection to new max size.
|
||||
QList<Tile> cropped;
|
||||
int croppedWidth = qMin(this->externalSelectionWidth, this->maxSelectionWidth);
|
||||
int croppedHeight = qMin(this->externalSelectionHeight, this->maxSelectionHeight);
|
||||
for (int y = 0; y < croppedHeight; y++)
|
||||
for (int x = 0; x < croppedWidth; x++) {
|
||||
int index = y * this->externalSelectionWidth + x;
|
||||
cropped.append(this->externalSelectedTiles.value(index));
|
||||
}
|
||||
this->externalSelectionWidth = croppedWidth;
|
||||
this->externalSelectionHeight = croppedHeight;
|
||||
this->externalSelectedTiles = cropped;
|
||||
}
|
||||
} else {
|
||||
updateSelectedTiles();
|
||||
}
|
||||
}
|
||||
|
||||
void TilesetEditorTileSelector::updateBasePixmap() {
|
||||
if (!this->primaryTileset || !this->secondaryTileset || this->numTilesWide == 0) {
|
||||
this->basePixmap = QPixmap();
|
||||
@@ -30,22 +54,26 @@ void TilesetEditorTileSelector::updateBasePixmap() {
|
||||
int y = (tileId / this->numTilesWide) * this->cellHeight;
|
||||
painter.drawImage(x, y, tileImage);
|
||||
}
|
||||
|
||||
if (this->showDivider) {
|
||||
int row = Util::roundUpToMultiple(Project::getNumTilesPrimary(), this->numTilesWide) / this->numTilesWide;
|
||||
const int y = row * this->cellHeight;
|
||||
painter.setPen(Qt::white);
|
||||
painter.drawLine(0, y, this->numTilesWide * this->cellWidth, y);
|
||||
}
|
||||
|
||||
painter.end();
|
||||
|
||||
this->basePixmap = QPixmap::fromImage(image);
|
||||
}
|
||||
|
||||
void TilesetEditorTileSelector::draw() {
|
||||
if (this->basePixmap.isNull())
|
||||
updateBasePixmap();
|
||||
setPixmap(this->basePixmap);
|
||||
|
||||
QPixmap pixmap = this->basePixmap;
|
||||
|
||||
if (this->showDivider) {
|
||||
QPainter painter(&pixmap);
|
||||
int row = Util::roundUpToMultiple(Project::getNumTilesPrimary(), this->numTilesWide) / this->numTilesWide;
|
||||
const int y = row * this->cellHeight;
|
||||
painter.setPen(Qt::white);
|
||||
painter.drawLine(0, y, this->numTilesWide * this->cellWidth, y);
|
||||
}
|
||||
|
||||
setPixmap(pixmap);
|
||||
|
||||
if (!this->externalSelection || (this->externalSelectionWidth == 1 && this->externalSelectionHeight == 1)) {
|
||||
this->drawSelection();
|
||||
@@ -90,9 +118,9 @@ void TilesetEditorTileSelector::updateSelectedTiles() {
|
||||
this->externalSelection = false;
|
||||
this->selectedTiles.clear();
|
||||
QPoint origin = this->getSelectionStart();
|
||||
QPoint dimensions = this->getSelectionDimensions();
|
||||
for (int j = 0; j < dimensions.y(); j++) {
|
||||
for (int i = 0; i < dimensions.x(); i++) {
|
||||
QSize dimensions = this->getSelectionDimensions();
|
||||
for (int j = 0; j < dimensions.height(); j++) {
|
||||
for (int i = 0; i < dimensions.width(); i++) {
|
||||
uint16_t metatileId = this->getTileId(origin.x() + i, origin.y() + j);
|
||||
this->selectedTiles.append(metatileId);
|
||||
}
|
||||
@@ -103,17 +131,17 @@ QList<Tile> TilesetEditorTileSelector::getSelectedTiles() {
|
||||
if (this->externalSelection) {
|
||||
return buildSelectedTiles(this->externalSelectionWidth, this->externalSelectionHeight, this->externalSelectedTiles);
|
||||
} else {
|
||||
QPoint dimensions = this->getSelectionDimensions();
|
||||
QSize dimensions = this->getSelectionDimensions();
|
||||
QList<Tile> tiles;
|
||||
for (int i = 0; i < this->selectedTiles.length(); i++) {
|
||||
uint16_t tile = this->selectedTiles.at(i);
|
||||
tiles.append(Tile(tile, false, false, this->paletteId));
|
||||
}
|
||||
return buildSelectedTiles(dimensions.x(), dimensions.y(), tiles);
|
||||
return buildSelectedTiles(dimensions.width(), dimensions.height(), tiles);
|
||||
}
|
||||
}
|
||||
|
||||
QList<Tile> TilesetEditorTileSelector::buildSelectedTiles(int width, int height, QList<Tile> selected) {
|
||||
QList<Tile> TilesetEditorTileSelector::buildSelectedTiles(int width, int height, const QList<Tile> &selected) {
|
||||
QList<Tile> tiles;
|
||||
QList<QList<Tile>> tileMatrix;
|
||||
for (int j = 0; j < height; j++) {
|
||||
@@ -121,7 +149,7 @@ QList<Tile> TilesetEditorTileSelector::buildSelectedTiles(int width, int height,
|
||||
QList<Tile> layerRow;
|
||||
for (int i = 0; i < width; i++) {
|
||||
int index = i + j * width;
|
||||
Tile tile = selected.at(index);
|
||||
Tile tile = selected.value(index);
|
||||
tile.xflip ^= this->xFlip;
|
||||
tile.yflip ^= this->yFlip;
|
||||
if (this->paletteChanged)
|
||||
@@ -134,7 +162,7 @@ QList<Tile> TilesetEditorTileSelector::buildSelectedTiles(int width, int height,
|
||||
// If we've completed a layer row, or its the last tile of an incompletely
|
||||
// selected layer, then append the layer row to the full row
|
||||
// If not an external selection, treat the whole row as 1 "layer"
|
||||
if (i == width - 1 || (this->externalSelection && (this->externalSelectedPos.at(index) % 4) & 1)) {
|
||||
if (i == width - 1) {
|
||||
row.append(layerRow);
|
||||
layerRow.clear();
|
||||
}
|
||||
@@ -152,15 +180,14 @@ QList<Tile> TilesetEditorTileSelector::buildSelectedTiles(int width, int height,
|
||||
return tiles;
|
||||
}
|
||||
|
||||
void TilesetEditorTileSelector::setExternalSelection(int width, int height, QList<Tile> tiles, QList<int> tileIdxs) {
|
||||
void TilesetEditorTileSelector::setExternalSelection(int width, int height, const QList<Tile> &tiles) {
|
||||
width = qBound(1, width, this->maxSelectionWidth);
|
||||
height = qBound(1, height, this->maxSelectionHeight);
|
||||
this->externalSelection = true;
|
||||
this->paletteChanged = false;
|
||||
this->externalSelectionWidth = width;
|
||||
this->externalSelectionHeight = height;
|
||||
this->externalSelectedTiles.clear();
|
||||
this->externalSelectedTiles.append(tiles);
|
||||
this->externalSelectedPos.clear();
|
||||
this->externalSelectedPos.append(tileIdxs);
|
||||
this->externalSelectedTiles = tiles.mid(0, width * height);
|
||||
this->draw();
|
||||
emit selectedTilesChanged();
|
||||
}
|
||||
@@ -170,16 +197,20 @@ uint16_t TilesetEditorTileSelector::getTileId(int x, int y) {
|
||||
}
|
||||
|
||||
void TilesetEditorTileSelector::mousePressEvent(QGraphicsSceneMouseEvent *event) {
|
||||
this->prevCellPos = getCellPos(event->pos());
|
||||
SelectablePixmapItem::mousePressEvent(event);
|
||||
this->updateSelectedTiles();
|
||||
emit selectedTilesChanged();
|
||||
}
|
||||
|
||||
void TilesetEditorTileSelector::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
|
||||
QPoint pos = getCellPos(event->pos());
|
||||
if (this->prevCellPos == pos)
|
||||
return;
|
||||
this->prevCellPos = pos;
|
||||
|
||||
SelectablePixmapItem::mouseMoveEvent(event);
|
||||
this->updateSelectedTiles();
|
||||
|
||||
QPoint pos = this->getCellPos(event->pos());
|
||||
uint16_t tile = this->getTileId(pos.x(), pos.y());
|
||||
emit hoveredTileChanged(tile);
|
||||
emit selectedTilesChanged();
|
||||
|
||||
Reference in New Issue
Block a user