Merge pull request #602 from GriffinRichards/connections
Redesign Connections tab
This commit is contained in:
commit
91be6c1fa3
38 changed files with 2560 additions and 1179 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
@ -8,10 +8,14 @@ The **"Breaking Changes"** listed below are changes that have been made in the d
|
|||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- Redesigned the Connections tab, adding a number of new features including the option to open or display diving maps and a list UI for easier edit access.
|
||||
- Add a `Close Project` option
|
||||
- An alert will be displayed when attempting to open a seemingly invalid project.
|
||||
|
||||
### Changed
|
||||
- Edits to map connections now have Undo/Redo and can be viewed in exported timelapses.
|
||||
- Changes to the "Mirror to Connecting Maps" setting will now be saved between sessions.
|
||||
- A notice will be displayed when attempting to open the "Dynamic" map, rather than nothing happening.
|
||||
- The base game version is now auto-detected if the project name contains only one of "emerald", "firered/leafgreen", or "ruby/sapphire".
|
||||
- It's now possible to cancel quitting if there are unsaved changes in sub-windows.
|
||||
|
||||
|
@ -25,6 +29,13 @@ The **"Breaking Changes"** listed below are changes that have been made in the d
|
|||
- Fix selections with multiple Events not always clearing when making a new selection.
|
||||
- Fix `About porymap` opening a new window each time it's activated.
|
||||
- Fix the `Edit History` window not raising to the front when reactivated.
|
||||
- New maps are now always inserted in map dropdowns at the correct position, rather than at the bottom of the list until the project is reloaded.
|
||||
- Fix changes to map connections not marking connected maps as unsaved.
|
||||
- Fix numerous issues related to connecting a map to itself.
|
||||
- Fix incorrect map connections getting selected when opening a map by double-clicking a map connection.
|
||||
- Fix a visual issue when quickly dragging map connections around.
|
||||
- Fix map connections rendering incorrectly if their direction name was unknown.
|
||||
- Fix map connections rendering incorrectly if their dimensions were smaller than the border draw distance.
|
||||
|
||||
## [5.4.1] - 2024-03-21
|
||||
### Fixed
|
||||
|
|
|
@ -2,35 +2,40 @@
|
|||
Editing Map Connections
|
||||
***********************
|
||||
|
||||
Maps can be connected together so that the player can seamlessly walk between them. These connections can be edited in the Connections tab.
|
||||
Maps can be connected together so that the player can seamlessly walk between them. These connections can be edited in the Connections tab.
|
||||
|
||||
.. figure:: images/editing-map-connections/map-connections.png
|
||||
:alt: Map Connections View
|
||||
|
||||
Map Connections View
|
||||
|
||||
A connection has a direction, offset, and destination map. To add new connection, press the plus button |add-connection-button|. To delete a connection, select it and press the delete button |remove-connection-button|.
|
||||
A connection has a direction, offset, and destination map. To add a new connection, press the |add-connection-button| button. To delete a connection you can either press the |remove-connection-button| button on its entry in the list, or select the connection and press the delete key.
|
||||
|
||||
The |open-connection-button| button will open the destination map. You may also open the destination map by double-clicking the connection itself (this can be done from the ``Map`` and ``Events`` tabs as well).
|
||||
|
||||
.. |add-connection-button|
|
||||
image:: images/editing-map-connections/add-connection-button.png
|
||||
:height: 24
|
||||
|
||||
.. |remove-connection-button|
|
||||
image:: images/editing-map-connections/remove-connection-button.png
|
||||
:height: 24
|
||||
|
||||
.. |open-connection-button|
|
||||
image:: images/editing-map-connections/open-connection-button.png
|
||||
:height: 24
|
||||
|
||||
To change the connection's vertical or horizontal offset, it's easiest to click and drag the connection to the desired offset.
|
||||
|
||||
Dive & Emerge Warps
|
||||
-------------------
|
||||
|
||||
Dive & emerge warps are used for the HM move Dive. They don't have offsets or directions--only a destination map. To add a dive or emerge warp, simply add a value in the Dive Map and/or Emerge Map dropdown menus.
|
||||
Dive & emerge warps are used for the HM move Dive. They don't have offsets or directions--only a destination map. To add a dive or emerge warp, simply add a value in the Dive Map and/or Emerge Map dropdown menus.
|
||||
|
||||
You can select the ``Show Emerge/Dive Maps`` checkbox to view your connected dive/emerge maps overlaid on the current map. The slider will change the opacity of this overlay. If you have both an emerge and a dive map connected you will see two sliders; the top slider is for the emerge map's opacity, and the bottom slider is for the dive map's opacity.
|
||||
|
||||
|
||||
Mirror Connections
|
||||
------------------
|
||||
|
||||
An extremely useful feature is the *Mirror to Connecting Maps* checkbox in the top-right corner. Connections are one-way, which means that you must keep the two connections in sync between the two maps. For example, Petalburg City has a west connection to Route 104, and Route 104 has an east connection to Petalburg City. If *Mirror to Connecting Maps* is enabled, then Porymap will automatically update both sides of the connection. Be sure to *File -> Save All* (``Ctrl+Shift+S``) when saving, since you will need to save both maps' connections.
|
||||
|
||||
Follow Connections
|
||||
------------------
|
||||
|
||||
Double-clicking on a connection will open the destination map. This is very useful for navigating through your maps, similar to double-clicking on :ref:`Warp Events <event-warps>`.
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 890 B After Width: | Height: | Size: 10 KiB |
Binary file not shown.
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 431 KiB |
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
132
forms/connectionslistitem.ui
Normal file
132
forms/connectionslistitem.ui
Normal file
|
@ -0,0 +1,132 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ConnectionsListItem</class>
|
||||
<widget class="QFrame" name="ConnectionsListItem">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>178</width>
|
||||
<height>157</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">.ConnectionsListItem { border-width: 1px; }</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_Map">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_Offset">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Offset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_Direction">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Direction</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QToolButton" name="button_Delete">
|
||||
<property name="toolTip">
|
||||
<string>Remove this connection.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/delete.ico</normaloff>:/icons/delete.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<widget class="NoScrollComboBox" name="comboBox_Direction">
|
||||
<property name="toolTip">
|
||||
<string>Where the connected map should be positioned relative to the current map.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="NoScrollComboBox" name="comboBox_Map">
|
||||
<property name="toolTip">
|
||||
<string>The name of the map to connect to the current map.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_Offset">
|
||||
<property name="toolTip">
|
||||
<string>The number of spaces to move the connected map perpendicular to its connected direction.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QToolButton" name="button_OpenMap">
|
||||
<property name="toolTip">
|
||||
<string>Open the connected map.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/map_go.ico</normaloff>:/icons/map_go.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>NoScrollComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>noscrollcombobox.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>NoScrollSpinBox</class>
|
||||
<extends>QSpinBox</extends>
|
||||
<header>noscrollspinbox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../resources/images.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -1715,7 +1715,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>100</width>
|
||||
<height>16</height>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -1809,7 +1809,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>100</width>
|
||||
<height>16</height>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -1903,7 +1903,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>100</width>
|
||||
<height>16</height>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -2003,7 +2003,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>100</width>
|
||||
<height>16</height>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -2097,7 +2097,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>100</width>
|
||||
<height>16</height>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -2541,7 +2541,7 @@
|
|||
<number>0</number>
|
||||
</property>
|
||||
<item row="3" column="0">
|
||||
<widget class="QFrame" name="gridFrame">
|
||||
<widget class="QFrame" name="frame_Connections">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
|
@ -2554,24 +2554,9 @@
|
|||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_11">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="2" column="0">
|
||||
<widget class="QFrame" name="horizontalFrame">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_18">
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_ConnectionsTopBar">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
|
@ -2590,10 +2575,7 @@
|
|||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<property name="spacing">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_10">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
|
@ -2606,82 +2588,20 @@
|
|||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_AddConnection">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<item row="1" column="3">
|
||||
<widget class="NoScrollComboBox" name="comboBox_DiveMap">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Add a new connection.</p></body></html></string>
|
||||
<string><html><head/><body><p>Destination map name when using <span style=" font-weight:600;">Dive</span>. If empty, no such connection will exist.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<activeon>:/icons/add.ico</activeon>
|
||||
</iconset>
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_RemoveConnection">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Remove the currently-selected connection.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<activeon>:/icons/delete.ico</activeon>
|
||||
</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>Number of Connections:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_NumConnections">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_11">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<item row="0" column="7">
|
||||
<widget class="QCheckBox" name="checkBox_MirrorConnections">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>If enabled, connections will automatically be updated on the connected map.</p></body></html></string>
|
||||
<string>If enabled, connections will automatically be updated on the connected map.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Mirror to Connecting Maps</string>
|
||||
|
@ -2691,144 +2611,31 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QGraphicsView" name="graphicsView_Connections">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="mouseTracking">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustIgnored</enum>
|
||||
</property>
|
||||
<property name="dragMode">
|
||||
<enum>QGraphicsView::NoDrag</enum>
|
||||
</property>
|
||||
<property name="transformationAnchor">
|
||||
<enum>QGraphicsView::AnchorUnderMouse</enum>
|
||||
</property>
|
||||
<property name="resizeAnchor">
|
||||
<enum>QGraphicsView::AnchorUnderMouse</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QFrame" name="horizontalFrame2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,0,0,0,0,0">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_11">
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_DiveMap">
|
||||
<property name="text">
|
||||
<string>Map</string>
|
||||
<string>Dive Map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="NoScrollComboBox" name="comboBox_ConnectedMap">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_EmergeMap">
|
||||
<property name="text">
|
||||
<string>Emerge Map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="NoScrollComboBox" name="comboBox_EmergeMap">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The destination map name of the connection.</p></body></html></string>
|
||||
<string><html><head/><body><p>Destination map name when emerging using <span style=" font-weight:600;">Dive</span>. If empty, no such connection will exist.</p></body></html></string>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Offset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinBox_ConnectionOffset">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The number of metatiles to offset the connection.</p></body></html></string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-999</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="NoScrollComboBox" name="comboBox_ConnectionDirection">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The direction of the connection.</p></body></html></string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>up</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>right</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>down</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>left</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item row="0" column="6">
|
||||
<spacer name="horizontalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
|
@ -2841,87 +2648,274 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QToolButton" name="button_OpenDiveMap">
|
||||
<property name="toolTip">
|
||||
<string>Open the selected Dive Map</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/map_go.ico</normaloff>:/icons/map_go.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4" rowspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_DiveMapOpacity">
|
||||
<property name="toolTip">
|
||||
<string>If enabled, the connected Emerge and/or Dive maps will be displayed with an opacity set using the slider.</string>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Show Emerge/Dive Maps</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_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>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="stackedWidget_DiveMapOpacity">
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page_OpacitySeparate">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_19">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QSlider" name="slider_EmergeMapOpacity">
|
||||
<property name="minimum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>90</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="slider_DiveMapOpacity">
|
||||
<property name="minimum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>90</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_OpacityCombined">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_20">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QSlider" name="slider_DiveEmergeMapOpacity">
|
||||
<property name="minimum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>90</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QToolButton" name="button_OpenEmergeMap">
|
||||
<property name="toolTip">
|
||||
<string>Open the selected Emerge Map</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/map_go.ico</normaloff>:/icons/map_go.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QFrame" name="horizontalFrame3">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter_Connections">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<property name="spacing">
|
||||
<number>4</number>
|
||||
<widget class="QGraphicsView" name="graphicsView_Connections">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
<property name="mouseTracking">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>Dive Map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="NoScrollComboBox" name="comboBox_DiveMap">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Destination map name when using <span style=" font-weight:600;">Dive</span>. If empty, no such connection will exist.</p></body></html></string>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Emerge Map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="NoScrollComboBox" name="comboBox_EmergeMap">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Destination map name when emerging using <span style=" font-weight:600;">Dive</span>. If empty, no such connection will exist.</p></body></html></string>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_10">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustIgnored</enum>
|
||||
</property>
|
||||
<property name="dragMode">
|
||||
<enum>QGraphicsView::NoDrag</enum>
|
||||
</property>
|
||||
<property name="transformationAnchor">
|
||||
<enum>QGraphicsView::AnchorUnderMouse</enum>
|
||||
</property>
|
||||
<property name="resizeAnchor">
|
||||
<enum>QGraphicsView::AnchorUnderMouse</enum>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QFrame" name="frame_EditConnectionsPanel">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>230</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_17">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_AddConnection">
|
||||
<property name="text">
|
||||
<string>Add Connection</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/add.ico</normaloff>:/icons/add.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea_ConnectionsList">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaContents_ConnectionsList">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>365</width>
|
||||
<height>651</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="layout_ConnectionsList">
|
||||
<property name="spacing">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -3085,6 +3079,7 @@
|
|||
<addaction name="actionCursor_Tile_Outline"/>
|
||||
<addaction name="actionPlayer_View_Rectangle"/>
|
||||
<addaction name="actionBetter_Cursors"/>
|
||||
<addaction name="actionDive_Emerge_Map"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuTools">
|
||||
<property name="title">
|
||||
|
@ -3424,6 +3419,17 @@
|
|||
<string>Ctrl+W</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDive_Emerge_Map">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Dive/Emerge Map</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
|
|
136
forms/newmapconnectiondialog.ui
Normal file
136
forms/newmapconnectiondialog.ui
Normal file
|
@ -0,0 +1,136 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>NewMapConnectionDialog</class>
|
||||
<widget class="QDialog" name="NewMapConnectionDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>234</width>
|
||||
<height>162</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Add New Map Connection</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_Map">
|
||||
<property name="text">
|
||||
<string>Map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="NoScrollComboBox" name="comboBox_Map">
|
||||
<property name="toolTip">
|
||||
<string>The name of the map to connect to the current map.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_Direction">
|
||||
<property name="text">
|
||||
<string>Direction</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="NoScrollComboBox" name="comboBox_Direction">
|
||||
<property name="toolTip">
|
||||
<string>Where the connected map should be positioned relative to the current map.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_Warning">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: rgb(255, 0, 0)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>'Map' must be the name of an existing map.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>NoScrollComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>noscrollcombobox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>NewMapConnectionDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>NewMapConnectionDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
|
@ -58,6 +58,11 @@ public:
|
|||
this->reopenOnLaunch = true;
|
||||
this->mapSortOrder = MapSortOrder::Group;
|
||||
this->prettyCursors = true;
|
||||
this->mirrorConnectingMaps = true;
|
||||
this->showDiveEmergeMaps = false;
|
||||
this->diveEmergeMapOpacity = 30;
|
||||
this->diveMapOpacity = 15;
|
||||
this->emergeMapOpacity = 15;
|
||||
this->collisionOpacity = 50;
|
||||
this->collisionZoom = 30;
|
||||
this->metatilesZoom = 30;
|
||||
|
@ -103,6 +108,11 @@ public:
|
|||
bool projectManuallyClosed;
|
||||
MapSortOrder mapSortOrder;
|
||||
bool prettyCursors;
|
||||
bool mirrorConnectingMaps;
|
||||
bool showDiveEmergeMaps;
|
||||
int diveEmergeMapOpacity;
|
||||
int diveMapOpacity;
|
||||
int emergeMapOpacity;
|
||||
int collisionOpacity;
|
||||
int collisionZoom;
|
||||
int metatilesZoom;
|
||||
|
|
|
@ -3,9 +3,11 @@
|
|||
#define EDITCOMMANDS_H
|
||||
|
||||
#include "blockdata.h"
|
||||
#include "mapconnection.h"
|
||||
|
||||
#include <QUndoCommand>
|
||||
#include <QList>
|
||||
#include <QPointer>
|
||||
|
||||
class MapPixmapItem;
|
||||
class Map;
|
||||
|
@ -31,6 +33,11 @@ enum CommandId {
|
|||
ID_EventDelete,
|
||||
ID_EventDuplicate,
|
||||
ID_EventPaste,
|
||||
ID_MapConnectionMove,
|
||||
ID_MapConnectionChangeDirection,
|
||||
ID_MapConnectionChangeMap,
|
||||
ID_MapConnectionAdd,
|
||||
ID_MapConnectionRemove,
|
||||
};
|
||||
|
||||
#define IDMask_EventType_Object (1 << 8)
|
||||
|
@ -379,4 +386,113 @@ private:
|
|||
int newBorderHeight;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// Implements a command to commit Map Connectien move actions.
|
||||
/// Actions are merged into one until the mouse is released when editing by click-and-drag,
|
||||
/// or when the offset spin box loses focus when editing with the list UI.
|
||||
class MapConnectionMove : public QUndoCommand {
|
||||
public:
|
||||
MapConnectionMove(MapConnection *connection, int newOffset, unsigned actionId,
|
||||
QUndoCommand *parent = nullptr);
|
||||
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
bool mergeWith(const QUndoCommand *command) override;
|
||||
int id() const override { return CommandId::ID_MapConnectionMove; }
|
||||
|
||||
private:
|
||||
MapConnection *connection;
|
||||
int newOffset;
|
||||
int oldOffset;
|
||||
bool mirrored;
|
||||
unsigned actionId;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// Implements a command to commit changes to a Map Connectien's 'direction' field.
|
||||
class MapConnectionChangeDirection : public QUndoCommand {
|
||||
public:
|
||||
MapConnectionChangeDirection(MapConnection *connection, QString newDirection,
|
||||
QUndoCommand *parent = nullptr);
|
||||
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
int id() const override { return CommandId::ID_MapConnectionChangeDirection; }
|
||||
|
||||
private:
|
||||
QPointer<MapConnection> connection;
|
||||
QString newDirection;
|
||||
QString oldDirection;
|
||||
int oldOffset;
|
||||
int newOffset;
|
||||
bool mirrored;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// Implements a command to commit changes to a Map Connectien's 'map' field.
|
||||
class MapConnectionChangeMap : public QUndoCommand {
|
||||
public:
|
||||
MapConnectionChangeMap(MapConnection *connection, QString newMapName,
|
||||
QUndoCommand *parent = nullptr);
|
||||
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
int id() const override { return CommandId::ID_MapConnectionChangeMap; }
|
||||
|
||||
private:
|
||||
QPointer<MapConnection> connection;
|
||||
QString newMapName;
|
||||
QString oldMapName;
|
||||
int oldOffset;
|
||||
int newOffset;
|
||||
bool mirrored;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// Implements a command to commit adding a Map Connection to a map.
|
||||
class MapConnectionAdd : public QUndoCommand {
|
||||
public:
|
||||
MapConnectionAdd(Map *map, MapConnection *connection,
|
||||
QUndoCommand *parent = nullptr);
|
||||
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
int id() const override { return CommandId::ID_MapConnectionAdd; }
|
||||
|
||||
private:
|
||||
Map *map = nullptr;
|
||||
Map *mirrorMap = nullptr;
|
||||
QPointer<MapConnection> connection = nullptr;
|
||||
QPointer<MapConnection> mirror = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// Implements a command to commit removing a Map Connection from a map.
|
||||
class MapConnectionRemove : public QUndoCommand {
|
||||
public:
|
||||
MapConnectionRemove(Map *map, MapConnection *connection,
|
||||
QUndoCommand *parent = nullptr);
|
||||
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
int id() const override { return CommandId::ID_MapConnectionRemove; }
|
||||
|
||||
private:
|
||||
Map *map = nullptr;
|
||||
Map *mirrorMap = nullptr;
|
||||
QPointer<MapConnection> connection = nullptr;
|
||||
QPointer<MapConnection> mirror = nullptr;
|
||||
};
|
||||
|
||||
|
||||
#endif // EDITCOMMANDS_H
|
||||
|
|
|
@ -69,7 +69,6 @@ public:
|
|||
QMap<Event::Group, QList<Event *>> events;
|
||||
QList<Event *> ownedEvents; // for memory management
|
||||
|
||||
QList<MapConnection*> connections;
|
||||
QList<int> metatileLayerOrder;
|
||||
QList<float> metatileLayerOpacity;
|
||||
|
||||
|
@ -98,7 +97,13 @@ public:
|
|||
QStringList getScriptLabels(Event::Group group = Event::Group::None);
|
||||
void removeEvent(Event *);
|
||||
void addEvent(Event *);
|
||||
QPixmap renderConnection(MapConnection, MapLayout *);
|
||||
void deleteConnections();
|
||||
QList<MapConnection*> getConnections() const;
|
||||
void removeConnection(MapConnection *);
|
||||
void addConnection(MapConnection *);
|
||||
void loadConnection(MapConnection *);
|
||||
QRect getConnectionRect(const QString &direction, MapLayout *fromLayout = nullptr);
|
||||
QPixmap renderConnection(const QString &direction, MapLayout *fromLayout = nullptr);
|
||||
QPixmap renderBorder(bool ignoreCache = false);
|
||||
void setDimensions(int newWidth, int newHeight, bool setNewBlockdata = true, bool enableScriptCallback = false);
|
||||
void setBorderDimensions(int newWidth, int newHeight, bool setNewBlockdata = true, bool enableScriptCallback = false);
|
||||
|
@ -122,17 +127,24 @@ public:
|
|||
QUndoStack editHistory;
|
||||
void modify();
|
||||
void clean();
|
||||
void pruneEditHistory();
|
||||
|
||||
private:
|
||||
void setNewDimensionsBlockdata(int newWidth, int newHeight);
|
||||
void setNewBorderDimensionsBlockdata(int newWidth, int newHeight);
|
||||
void trackConnection(MapConnection*);
|
||||
|
||||
// MapConnections in 'ownedConnections' but not 'connections' persist in the edit history.
|
||||
QList<MapConnection*> connections;
|
||||
QSet<MapConnection*> ownedConnections;
|
||||
|
||||
signals:
|
||||
void mapChanged(Map *map);
|
||||
void modified();
|
||||
void mapDimensionsChanged(const QSize &size);
|
||||
void mapNeedsRedrawing();
|
||||
void openScriptRequested(QString label);
|
||||
void connectionAdded(MapConnection*);
|
||||
void connectionRemoved(MapConnection*);
|
||||
};
|
||||
|
||||
#endif // MAP_H
|
||||
|
|
|
@ -3,21 +3,61 @@
|
|||
#define MAPCONNECTION_H
|
||||
|
||||
#include <QString>
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
#include <QMap>
|
||||
|
||||
class MapConnection {
|
||||
class Project;
|
||||
class Map;
|
||||
|
||||
class MapConnection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QString direction;
|
||||
int offset;
|
||||
QString map_name;
|
||||
MapConnection(const QString &targetMapName, const QString &direction, int offset = 0);
|
||||
|
||||
Map* parentMap() const { return m_parentMap; }
|
||||
QString parentMapName() const;
|
||||
void setParentMap(Map* map, bool mirror = true);
|
||||
|
||||
Map* targetMap() const;
|
||||
QString targetMapName() const { return m_targetMapName; }
|
||||
void setTargetMapName(const QString &targetMapName, bool mirror = true);
|
||||
|
||||
QString direction() const { return m_direction; }
|
||||
void setDirection(const QString &direction, bool mirror = true);
|
||||
|
||||
int offset() const { return m_offset; }
|
||||
void setOffset(int offset, bool mirror = true);
|
||||
|
||||
MapConnection* findMirror();
|
||||
MapConnection* createMirror();
|
||||
|
||||
QPixmap getPixmap();
|
||||
|
||||
static QPointer<Project> project;
|
||||
static const QMap<QString, QString> oppositeDirections;
|
||||
static const QStringList cardinalDirections;
|
||||
static bool isCardinal(const QString &direction);
|
||||
static bool isHorizontal(const QString &direction);
|
||||
static bool isVertical(const QString &direction);
|
||||
static bool isDiving(const QString &direction);
|
||||
static QString oppositeDirection(const QString &direction) { return oppositeDirections.value(direction, direction); }
|
||||
static bool areMirrored(const MapConnection*, const MapConnection*);
|
||||
|
||||
private:
|
||||
Map* m_parentMap;
|
||||
QString m_targetMapName;
|
||||
QString m_direction;
|
||||
int m_offset;
|
||||
|
||||
void markMapEdited();
|
||||
Map* getMap(const QString& mapName) const;
|
||||
|
||||
signals:
|
||||
void parentMapChanged(Map* before, Map* after);
|
||||
void targetMapNameChanged(QString before, QString after);
|
||||
void directionChanged(QString before, QString after);
|
||||
void offsetChanged(int before, int after);
|
||||
};
|
||||
|
||||
inline bool operator==(const MapConnection &c1, const MapConnection &c2) {
|
||||
return c1.map_name == c2.map_name;
|
||||
}
|
||||
|
||||
inline uint qHash(const MapConnection &key) {
|
||||
return qHash(key.map_name);
|
||||
}
|
||||
|
||||
#endif // MAPCONNECTION_H
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "ui_mainwindow.h"
|
||||
#include "bordermetatilespixmapitem.h"
|
||||
#include "connectionpixmapitem.h"
|
||||
#include "divingmappixmapitem.h"
|
||||
#include "currentselectedmetatilespixmapitem.h"
|
||||
#include "collisionpixmapitem.h"
|
||||
#include "mappixmapitem.h"
|
||||
|
@ -46,6 +47,7 @@ public:
|
|||
QPointer<Project> project = nullptr;
|
||||
Map *map = nullptr;
|
||||
Settings *settings;
|
||||
void setProject(Project * project);
|
||||
void saveProject();
|
||||
void save();
|
||||
void closeProject();
|
||||
|
@ -74,18 +76,17 @@ public:
|
|||
void setEditingObjects();
|
||||
void setEditingConnections();
|
||||
void setMapEditingButtonsEnabled(bool enabled);
|
||||
void setCurrentConnectionDirection(QString curDirection);
|
||||
void updateCurrentConnectionDirection(QString curDirection);
|
||||
void setConnectionsVisibility(bool visible);
|
||||
void updateConnectionOffset(int offset);
|
||||
void setConnectionMap(QString mapName);
|
||||
void addNewConnection();
|
||||
void removeCurrentConnection();
|
||||
void updateDivingMapsVisibility();
|
||||
void renderDivingConnections();
|
||||
void addConnection(MapConnection* connection);
|
||||
void removeConnection(MapConnection* connection);
|
||||
void removeSelectedConnection();
|
||||
void addNewWildMonGroup(QWidget *window);
|
||||
void deleteWildMonGroup();
|
||||
void updateDiveMap(QString mapName);
|
||||
void updateEmergeMap(QString mapName);
|
||||
void setSelectedConnectionFromMap(QString mapName);
|
||||
void setSelectedConnection(MapConnection *connection);
|
||||
void updatePrimaryTileset(QString tilesetLabel, bool forceLoad = false);
|
||||
void updateSecondaryTileset(QString tilesetLabel, bool forceLoad = false);
|
||||
void toggleBorderVisibility(bool visible, bool enableScriptCallback = true);
|
||||
|
@ -110,8 +111,8 @@ public:
|
|||
QPointer<QGraphicsScene> scene = nullptr;
|
||||
QGraphicsPixmapItem *current_view = nullptr;
|
||||
QPointer<MapPixmapItem> map_item = nullptr;
|
||||
ConnectionPixmapItem* selected_connection_item = nullptr;
|
||||
QList<ConnectionPixmapItem*> connection_items;
|
||||
QList<QPointer<ConnectionPixmapItem>> connection_items;
|
||||
QMap<QString, QPointer<DivingMapPixmapItem>> diving_map_items;
|
||||
QGraphicsPathItem *connection_mask = nullptr;
|
||||
QPointer<CollisionPixmapItem> collision_item = nullptr;
|
||||
QGraphicsItemGroup *events_group = nullptr;
|
||||
|
@ -132,6 +133,8 @@ public:
|
|||
QPointer<MovementPermissionsSelector> movement_permissions_selector_item = nullptr;
|
||||
|
||||
QList<DraggablePixmapItem *> *selected_events = nullptr;
|
||||
QPointer<ConnectionPixmapItem> selected_connection_item = nullptr;
|
||||
QPointer<MapConnection> connection_to_select = nullptr;
|
||||
|
||||
QString map_edit_mode = "paint";
|
||||
QString obj_edit_mode = "select";
|
||||
|
@ -175,25 +178,20 @@ private:
|
|||
void clearBorderMetatiles();
|
||||
void clearCurrentMetatilesSelection();
|
||||
void clearMapEvents();
|
||||
//void clearMapConnections();
|
||||
void clearMapConnections();
|
||||
void clearConnectionMask();
|
||||
void clearMapBorder();
|
||||
void clearMapGrid();
|
||||
void clearWildMonTables();
|
||||
void setConnectionItemsVisible(bool);
|
||||
void setBorderItemsVisible(bool, qreal = 1);
|
||||
void setConnectionEditControlValues(MapConnection*);
|
||||
void setConnectionEditControlsEnabled(bool);
|
||||
void setConnectionsEditable(bool);
|
||||
void createConnectionItem(MapConnection* connection);
|
||||
void populateConnectionMapPickers();
|
||||
void setDiveEmergeControls();
|
||||
void updateDiveEmergeMap(QString mapName, QString direction);
|
||||
void onConnectionOffsetChanged(int newOffset);
|
||||
void removeMirroredConnection(MapConnection*);
|
||||
void updateMirroredConnectionOffset(MapConnection*);
|
||||
void updateMirroredConnectionDirection(MapConnection*, QString);
|
||||
void updateMirroredConnectionMap(MapConnection*, QString);
|
||||
void updateMirroredConnection(MapConnection*, QString, QString, bool isDelete = false);
|
||||
void updateBorderVisibility();
|
||||
void disconnectMapConnection(MapConnection *connection);
|
||||
QPoint getConnectionOrigin(MapConnection *connection);
|
||||
void removeConnectionPixmap(MapConnection *connection);
|
||||
void updateConnectionPixmap(ConnectionPixmapItem *connectionItem);
|
||||
void displayConnection(MapConnection *connection);
|
||||
void displayDivingConnection(MapConnection *connection);
|
||||
void setDivingMapName(QString mapName, QString direction);
|
||||
void removeDivingMapPixmap(MapConnection *connection);
|
||||
void updateEncounterFields(EncounterFields newFields);
|
||||
QString getMovementPermissionText(uint16_t collision, uint16_t elevation);
|
||||
QString getMetatileDisplayMessage(uint16_t metatileId);
|
||||
|
@ -209,10 +207,7 @@ private slots:
|
|||
void setStraightPathCursorMode(QGraphicsSceneMouseEvent *event);
|
||||
void mouseEvent_map(QGraphicsSceneMouseEvent *event, MapPixmapItem *item);
|
||||
void mouseEvent_collision(QGraphicsSceneMouseEvent *event, CollisionPixmapItem *item);
|
||||
void onConnectionMoved(MapConnection*);
|
||||
void onConnectionItemSelected(ConnectionPixmapItem* connectionItem);
|
||||
void onConnectionItemDoubleClicked(ConnectionPixmapItem* connectionItem);
|
||||
void onConnectionDirectionChanged(QString newDirection);
|
||||
void setSelectedConnectionItem(ConnectionPixmapItem *connectionItem);
|
||||
void onHoveredMovementPermissionChanged(uint16_t, uint16_t);
|
||||
void onHoveredMovementPermissionCleared();
|
||||
void onHoveredMetatileSelectionChanged(uint16_t);
|
||||
|
@ -227,12 +222,11 @@ private slots:
|
|||
|
||||
signals:
|
||||
void objectsChanged();
|
||||
void loadMapRequested(QString, QString);
|
||||
void openConnectedMap(MapConnection*);
|
||||
void wildMonDataChanged();
|
||||
void warpEventDoubleClicked(QString, int, Event::Group);
|
||||
void currentMetatilesSelectionChanged();
|
||||
void mapRulerStatusChanged(const QString &);
|
||||
void editedMapData();
|
||||
void tilesetUpdated(QString);
|
||||
};
|
||||
|
||||
|
|
|
@ -179,14 +179,14 @@ private slots:
|
|||
void copy();
|
||||
void paste();
|
||||
|
||||
void onLoadMapRequested(QString, QString);
|
||||
void onMapChanged(Map *map);
|
||||
void onOpenConnectedMap(MapConnection*);
|
||||
void onMapNeedsRedrawing();
|
||||
void onTilesetsSaved(QString, QString);
|
||||
void onWildMonDataChanged();
|
||||
void openNewMapPopupWindow();
|
||||
void onNewMapCreated();
|
||||
void onMapCacheCleared();
|
||||
void onMapLoaded(Map *map);
|
||||
void importMapFromAdvanceMap1_92();
|
||||
void onMapRulerStatusChanged(const QString &);
|
||||
void applyUserShortcuts();
|
||||
|
@ -219,6 +219,7 @@ private slots:
|
|||
void on_actionMove_triggered();
|
||||
void on_actionMap_Shift_triggered();
|
||||
|
||||
void onDeleteKeyPressed();
|
||||
void on_toolButton_deleteObject_clicked();
|
||||
|
||||
void addNewEvent(Event::Type type);
|
||||
|
@ -245,11 +246,9 @@ private slots:
|
|||
void on_actionExport_Map_Timelapse_Image_triggered();
|
||||
void on_actionImport_Map_from_Advance_Map_1_92_triggered();
|
||||
|
||||
void on_comboBox_ConnectionDirection_currentTextChanged(const QString &arg1);
|
||||
void on_spinBox_ConnectionOffset_valueChanged(int offset);
|
||||
void on_comboBox_ConnectedMap_currentTextChanged(const QString &mapName);
|
||||
void on_pushButton_AddConnection_clicked();
|
||||
void on_pushButton_RemoveConnection_clicked();
|
||||
void on_button_OpenDiveMap_clicked();
|
||||
void on_button_OpenEmergeMap_clicked();
|
||||
void on_comboBox_DiveMap_currentTextChanged(const QString &mapName);
|
||||
void on_comboBox_EmergeMap_currentTextChanged(const QString &mapName);
|
||||
void on_comboBox_PrimaryTileset_currentTextChanged(const QString &arg1);
|
||||
|
@ -272,6 +271,12 @@ private slots:
|
|||
|
||||
void eventTabChanged(int index);
|
||||
|
||||
void on_checkBox_MirrorConnections_stateChanged(int selected);
|
||||
void on_actionDive_Emerge_Map_triggered();
|
||||
void on_groupBox_DiveMapOpacity_toggled(bool on);
|
||||
void on_slider_DiveEmergeMapOpacity_valueChanged(int value);
|
||||
void on_slider_DiveMapOpacity_valueChanged(int value);
|
||||
void on_slider_EmergeMapOpacity_valueChanged(int value);
|
||||
void on_horizontalSlider_CollisionTransparency_valueChanged(int value);
|
||||
void on_toolButton_ExpandAll_clicked();
|
||||
void on_toolButton_CollapseAll_clicked();
|
||||
|
@ -318,9 +323,7 @@ private:
|
|||
QStandardItemModel *mapListModel;
|
||||
QList<QStandardItem*> *mapGroupItemsList;
|
||||
QMap<QString, QModelIndex> mapListIndexes;
|
||||
QIcon* mapIcon;
|
||||
QIcon* mapEditedIcon;
|
||||
QIcon* mapOpenedIcon;
|
||||
QIcon mapIcon;
|
||||
|
||||
QAction *undoAction = nullptr;
|
||||
QAction *redoAction = nullptr;
|
||||
|
@ -331,10 +334,10 @@ private:
|
|||
QMap<Event::Group, DraggablePixmapItem*> lastSelectedEvent;
|
||||
|
||||
bool isProgrammaticEventTabChange;
|
||||
bool projectHasUnsavedChanges;
|
||||
bool newMapDefaultsSet = false;
|
||||
bool tilesetNeedsRedraw = false;
|
||||
|
||||
bool userSetMap(QString, bool scrollTreeView = false);
|
||||
bool setMap(QString, bool scrollTreeView = false);
|
||||
void redrawMapScene();
|
||||
void refreshMapScene();
|
||||
|
@ -353,7 +356,7 @@ private:
|
|||
QStandardItem* createMapItem(QString mapName, int groupNum, int inGroupNum);
|
||||
void refreshRecentProjectsMenu();
|
||||
|
||||
void drawMapListIcons(QAbstractItemModel *model);
|
||||
void updateMapListIcon(const QString &mapName);
|
||||
void updateMapList();
|
||||
|
||||
void displayMapProperties();
|
||||
|
@ -361,6 +364,7 @@ private:
|
|||
void clickToolButtonFromEditMode(QString editMode);
|
||||
|
||||
void markMapEdited();
|
||||
void markMapEdited(Map*);
|
||||
void showWindowTitle();
|
||||
|
||||
void initWindow();
|
||||
|
@ -398,6 +402,7 @@ private:
|
|||
int insertTilesetLabel(QStringList * list, QString label);
|
||||
|
||||
void checkForUpdates(bool requestedByUser);
|
||||
void setDivingMapsVisible(bool visible);
|
||||
};
|
||||
|
||||
enum MapListUserRoles {
|
||||
|
@ -406,4 +411,23 @@ enum MapListUserRoles {
|
|||
TypeRole2, // Used for various extra data needed.
|
||||
};
|
||||
|
||||
// These are namespaced in a struct to avoid colliding with e.g. class Map.
|
||||
struct MainTab {
|
||||
enum {
|
||||
Map,
|
||||
Events,
|
||||
Header,
|
||||
Connections,
|
||||
WildPokemon,
|
||||
};
|
||||
};
|
||||
|
||||
struct MapViewTab {
|
||||
enum {
|
||||
Metatiles,
|
||||
Collision,
|
||||
Prefabs,
|
||||
};
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
|
|
@ -257,6 +257,7 @@ signals:
|
|||
void reloadProject();
|
||||
void uncheckMonitorFilesAction();
|
||||
void mapCacheCleared();
|
||||
void mapLoaded(Map *map);
|
||||
};
|
||||
|
||||
#endif // PROJECT_H
|
||||
|
|
|
@ -4,44 +4,46 @@
|
|||
#include "mapconnection.h"
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QPainter>
|
||||
#include <QPointer>
|
||||
|
||||
class ConnectionPixmapItem : public QObject, public QGraphicsPixmapItem {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ConnectionPixmapItem(QPixmap pixmap, MapConnection* connection, int x, int y, int baseMapWidth, int baseMapHeight): QGraphicsPixmapItem(pixmap) {
|
||||
this->basePixmap = pixmap;
|
||||
this->connection = connection;
|
||||
setFlag(ItemIsMovable);
|
||||
setFlag(ItemSendsGeometryChanges);
|
||||
this->initialX = x;
|
||||
this->initialY = y;
|
||||
this->initialOffset = connection->offset;
|
||||
this->baseMapWidth = baseMapWidth;
|
||||
this->baseMapHeight = baseMapHeight;
|
||||
}
|
||||
QPixmap basePixmap;
|
||||
MapConnection* connection;
|
||||
int initialX;
|
||||
int initialY;
|
||||
int initialOffset;
|
||||
int baseMapWidth;
|
||||
int baseMapHeight;
|
||||
void render(qreal opacity = 1);
|
||||
int getMinOffset();
|
||||
int getMaxOffset();
|
||||
ConnectionPixmapItem(MapConnection* connection, int originX, int originY);
|
||||
ConnectionPixmapItem(MapConnection* connection, QPoint origin);
|
||||
|
||||
const QPointer<MapConnection> connection;
|
||||
|
||||
void setOrigin(int x, int y);
|
||||
void setOrigin(QPoint pos);
|
||||
|
||||
void setEditable(bool editable);
|
||||
bool getEditable();
|
||||
void updateHighlight(bool selected);
|
||||
|
||||
void setSelected(bool selected);
|
||||
|
||||
void updatePos();
|
||||
void render(bool ignoreCache = false);
|
||||
|
||||
private:
|
||||
QPixmap basePixmap;
|
||||
qreal originX;
|
||||
qreal originY;
|
||||
bool selected = false;
|
||||
unsigned actionId = 0;
|
||||
|
||||
static const int mWidth = 16;
|
||||
static const int mHeight = 16;
|
||||
|
||||
protected:
|
||||
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent*);
|
||||
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent*);
|
||||
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent*) override;
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent*) override;
|
||||
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent*) override;
|
||||
|
||||
signals:
|
||||
void connectionItemSelected(ConnectionPixmapItem* connectionItem);
|
||||
void connectionItemDoubleClicked(ConnectionPixmapItem* connectionItem);
|
||||
void connectionMoved(MapConnection*);
|
||||
void connectionItemDoubleClicked(MapConnection*);
|
||||
void selectionChanged(bool selected);
|
||||
};
|
||||
|
||||
#endif // CONNECTIONPIXMAPITEM_H
|
||||
|
|
52
include/ui/connectionslistitem.h
Normal file
52
include/ui/connectionslistitem.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
#ifndef CONNECTIONSLISTITEM_H
|
||||
#define CONNECTIONSLISTITEM_H
|
||||
|
||||
#include "mapconnection.h"
|
||||
#include "map.h"
|
||||
|
||||
#include <QFrame>
|
||||
#include <QMouseEvent>
|
||||
#include <QPointer>
|
||||
|
||||
namespace Ui {
|
||||
class ConnectionsListItem;
|
||||
}
|
||||
|
||||
// We show the data for each map connection in the panel on the right side of the Connections tab.
|
||||
// An instance of this class is used for each item in that list.
|
||||
// It communicates with the ConnectionPixmapItem on the map through a shared MapConnection pointer.
|
||||
class ConnectionsListItem : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConnectionsListItem(QWidget *parent, MapConnection *connection, const QStringList &mapNames);
|
||||
~ConnectionsListItem();
|
||||
|
||||
void updateUI();
|
||||
void setSelected(bool selected);
|
||||
|
||||
private:
|
||||
Ui::ConnectionsListItem *ui;
|
||||
QPointer<MapConnection> connection;
|
||||
Map *map;
|
||||
bool isSelected = false;
|
||||
unsigned actionId = 0;
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent*) override;
|
||||
|
||||
signals:
|
||||
void selected();
|
||||
void removed(MapConnection*);
|
||||
void openMapClicked(MapConnection*);
|
||||
|
||||
private slots:
|
||||
void on_comboBox_Direction_currentTextChanged(QString direction);
|
||||
void on_comboBox_Map_currentTextChanged(QString mapName);
|
||||
void on_spinBox_Offset_valueChanged(int offset);
|
||||
void on_button_Delete_clicked();
|
||||
void on_button_OpenMap_clicked();
|
||||
};
|
||||
|
||||
#endif // CONNECTIONSLISTITEM_H
|
30
include/ui/divingmappixmapitem.h
Normal file
30
include/ui/divingmappixmapitem.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef DIVINGMAPPIXMAPITEM_H
|
||||
#define DIVINGMAPPIXMAPITEM_H
|
||||
|
||||
#include "mapconnection.h"
|
||||
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QPointer>
|
||||
#include <QComboBox>
|
||||
|
||||
class DivingMapPixmapItem : public QObject, public QGraphicsPixmapItem {
|
||||
Q_OBJECT
|
||||
public:
|
||||
DivingMapPixmapItem(MapConnection *connection, QComboBox *combo);
|
||||
~DivingMapPixmapItem();
|
||||
|
||||
MapConnection* connection() const { return m_connection; }
|
||||
void updatePixmap();
|
||||
|
||||
private:
|
||||
QPointer<MapConnection> m_connection;
|
||||
QPointer<QComboBox> m_combo;
|
||||
|
||||
void setComboText(const QString &text);
|
||||
static QPixmap getBasePixmap(MapConnection* connection);
|
||||
|
||||
private slots:
|
||||
void onTargetMapChanged();
|
||||
};
|
||||
|
||||
#endif // DIVINGMAPPIXMAPITEM_H
|
|
@ -50,9 +50,10 @@ private:
|
|||
ImageExporterMode mode = ImageExporterMode::Normal;
|
||||
|
||||
void updatePreview();
|
||||
void updateShowBorderState();
|
||||
void saveImage();
|
||||
QPixmap getStitchedImage(QProgressDialog *progress, bool includeBorder);
|
||||
QPixmap getFormattedMapPixmap(Map *map, bool ignoreBorder);
|
||||
QPixmap getFormattedMapPixmap(Map *map, bool ignoreBorder = false);
|
||||
bool historyItemAppliesToFrame(const QUndoCommand *command);
|
||||
|
||||
private slots:
|
||||
|
|
32
include/ui/newmapconnectiondialog.h
Normal file
32
include/ui/newmapconnectiondialog.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef NEWMAPCONNECTIONDIALOG_H
|
||||
#define NEWMAPCONNECTIONDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "map.h"
|
||||
#include "mapconnection.h"
|
||||
|
||||
namespace Ui {
|
||||
class NewMapConnectionDialog;
|
||||
}
|
||||
|
||||
class NewMapConnectionDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit NewMapConnectionDialog(QWidget *parent, Map* map, const QStringList &mapNames);
|
||||
~NewMapConnectionDialog();
|
||||
|
||||
virtual void accept() override;
|
||||
|
||||
signals:
|
||||
void accepted(MapConnection *result);
|
||||
|
||||
private:
|
||||
Ui::NewMapConnectionDialog *ui;
|
||||
|
||||
bool mapNameIsValid();
|
||||
void setWarningVisible(bool visible);
|
||||
};
|
||||
|
||||
#endif // NEWMAPCONNECTIONDIALOG_H
|
|
@ -13,11 +13,15 @@ public:
|
|||
void setTextItem(const QString &text);
|
||||
void setNumberItem(int value);
|
||||
void setHexItem(uint32_t value);
|
||||
void setClearButtonEnabled(bool enabled);
|
||||
void setEditable(bool editable);
|
||||
void setLineEdit(QLineEdit *edit);
|
||||
void setFocusedScrollingEnabled(bool enabled);
|
||||
|
||||
private:
|
||||
void setItem(int index, const QString &text);
|
||||
|
||||
bool focusedScrollingEnabled = true;
|
||||
};
|
||||
|
||||
#endif // NOSCROLLCOMBOBOX_H
|
||||
|
|
|
@ -24,6 +24,7 @@ SOURCES += src/core/block.cpp \
|
|||
src/core/heallocation.cpp \
|
||||
src/core/imageexport.cpp \
|
||||
src/core/map.cpp \
|
||||
src/core/mapconnection.cpp \
|
||||
src/core/maplayout.cpp \
|
||||
src/core/mapparser.cpp \
|
||||
src/core/metatile.cpp \
|
||||
|
@ -46,13 +47,16 @@ SOURCES += src/core/block.cpp \
|
|||
src/scriptapi/apiutility.cpp \
|
||||
src/scriptapi/scripting.cpp \
|
||||
src/ui/aboutporymap.cpp \
|
||||
src/ui/connectionslistitem.cpp \
|
||||
src/ui/customscriptseditor.cpp \
|
||||
src/ui/customscriptslistitem.cpp \
|
||||
src/ui/divingmappixmapitem.cpp \
|
||||
src/ui/draggablepixmapitem.cpp \
|
||||
src/ui/bordermetatilespixmapitem.cpp \
|
||||
src/ui/collisionpixmapitem.cpp \
|
||||
src/ui/connectionpixmapitem.cpp \
|
||||
src/ui/currentselectedmetatilespixmapitem.cpp \
|
||||
src/ui/newmapconnectiondialog.cpp \
|
||||
src/ui/overlay.cpp \
|
||||
src/ui/prefab.cpp \
|
||||
src/ui/projectsettingseditor.cpp \
|
||||
|
@ -139,13 +143,16 @@ HEADERS += include/core/block.h \
|
|||
include/lib/orderedmap.h \
|
||||
include/lib/orderedjson.h \
|
||||
include/ui/aboutporymap.h \
|
||||
include/ui/connectionslistitem.h \
|
||||
include/ui/customscriptseditor.h \
|
||||
include/ui/customscriptslistitem.h \
|
||||
include/ui/divingmappixmapitem.h \
|
||||
include/ui/draggablepixmapitem.h \
|
||||
include/ui/bordermetatilespixmapitem.h \
|
||||
include/ui/collisionpixmapitem.h \
|
||||
include/ui/connectionpixmapitem.h \
|
||||
include/ui/currentselectedmetatilespixmapitem.h \
|
||||
include/ui/newmapconnectiondialog.h \
|
||||
include/ui/prefabframe.h \
|
||||
include/ui/projectsettingseditor.h \
|
||||
include/ui/regionmaplayoutpixmapitem.h \
|
||||
|
@ -205,6 +212,8 @@ HEADERS += include/core/block.h \
|
|||
include/ui/updatepromoter.h
|
||||
|
||||
FORMS += forms/mainwindow.ui \
|
||||
forms/connectionslistitem.ui \
|
||||
forms/newmapconnectiondialog.ui \
|
||||
forms/prefabcreationdialog.ui \
|
||||
forms/prefabframe.ui \
|
||||
forms/tileseteditor.ui \
|
||||
|
|
BIN
resources/icons/map_go.ico
Executable file
BIN
resources/icons/map_go.ico
Executable file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
|
@ -65,5 +65,6 @@
|
|||
<file>images/Entities_16x16.png</file>
|
||||
<file>images/pokemon_icon_placeholder.png</file>
|
||||
<file>icons/clipboard.ico</file>
|
||||
<file>icons/map_go.ico</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -330,6 +330,16 @@ void PorymapConfig::parseConfigKeyValue(QString key, QString value) {
|
|||
this->mainSplitterState = bytesFromString(value);
|
||||
} else if (key == "metatiles_splitter_state") {
|
||||
this->metatilesSplitterState = bytesFromString(value);
|
||||
} else if (key == "mirror_connecting_maps") {
|
||||
this->mirrorConnectingMaps = getConfigBool(key, value);
|
||||
} else if (key == "show_dive_emerge_maps") {
|
||||
this->showDiveEmergeMaps = getConfigBool(key, value);
|
||||
} else if (key == "dive_emerge_map_opacity") {
|
||||
this->diveEmergeMapOpacity = getConfigInteger(key, value, 10, 90, 30);
|
||||
} else if (key == "dive_map_opacity") {
|
||||
this->diveMapOpacity = getConfigInteger(key, value, 10, 90, 15);
|
||||
} else if (key == "emerge_map_opacity") {
|
||||
this->emergeMapOpacity = getConfigInteger(key, value, 10, 90, 15);
|
||||
} else if (key == "collision_opacity") {
|
||||
this->collisionOpacity = getConfigInteger(key, value, 0, 100, 50);
|
||||
} else if (key == "tileset_editor_geometry") {
|
||||
|
@ -439,6 +449,11 @@ QMap<QString, QString> PorymapConfig::getKeyValueMap() {
|
|||
map.insert("project_settings_editor_state", stringFromByteArray(this->projectSettingsEditorState));
|
||||
map.insert("custom_scripts_editor_geometry", stringFromByteArray(this->customScriptsEditorGeometry));
|
||||
map.insert("custom_scripts_editor_state", stringFromByteArray(this->customScriptsEditorState));
|
||||
map.insert("mirror_connecting_maps", this->mirrorConnectingMaps ? "1" : "0");
|
||||
map.insert("show_dive_emerge_maps", this->showDiveEmergeMaps ? "1" : "0");
|
||||
map.insert("dive_emerge_map_opacity", QString::number(this->diveEmergeMapOpacity));
|
||||
map.insert("dive_map_opacity", QString::number(this->diveMapOpacity));
|
||||
map.insert("emerge_map_opacity", QString::number(this->emergeMapOpacity));
|
||||
map.insert("collision_opacity", QString::number(this->collisionOpacity));
|
||||
map.insert("collision_zoom", QString::number(this->collisionZoom));
|
||||
map.insert("metatiles_zoom", QString::number(this->metatilesZoom));
|
||||
|
|
|
@ -569,3 +569,205 @@ void ScriptEditMap::undo() {
|
|||
|
||||
QUndoCommand::undo();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
MapConnectionMove::MapConnectionMove(MapConnection *connection, int newOffset, unsigned actionId,
|
||||
QUndoCommand *parent) : QUndoCommand(parent) {
|
||||
setText("Move Map Connection");
|
||||
|
||||
this->connection = connection;
|
||||
this->oldOffset = connection->offset();
|
||||
this->newOffset = newOffset;
|
||||
|
||||
this->mirrored = porymapConfig.mirrorConnectingMaps;
|
||||
|
||||
this->actionId = actionId;
|
||||
}
|
||||
|
||||
void MapConnectionMove::redo() {
|
||||
QUndoCommand::redo();
|
||||
if (this->connection)
|
||||
this->connection->setOffset(this->newOffset, this->mirrored);
|
||||
}
|
||||
|
||||
void MapConnectionMove::undo() {
|
||||
if (this->connection)
|
||||
this->connection->setOffset(this->oldOffset, this->mirrored);
|
||||
QUndoCommand::undo();
|
||||
}
|
||||
|
||||
bool MapConnectionMove::mergeWith(const QUndoCommand *command) {
|
||||
if (this->id() != command->id())
|
||||
return false;
|
||||
|
||||
const MapConnectionMove *other = static_cast<const MapConnectionMove *>(command);
|
||||
if (this->connection != other->connection)
|
||||
return false;
|
||||
if (this->actionId != other->actionId)
|
||||
return false;
|
||||
|
||||
this->newOffset = other->newOffset;
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
MapConnectionChangeDirection::MapConnectionChangeDirection(MapConnection *connection, QString newDirection,
|
||||
QUndoCommand *parent) : QUndoCommand(parent) {
|
||||
setText("Change Map Connection Direction");
|
||||
|
||||
this->connection = connection;
|
||||
|
||||
this->oldDirection = connection->direction();
|
||||
this->newDirection = newDirection;
|
||||
|
||||
this->oldOffset = connection->offset();
|
||||
|
||||
// If the direction changes between vertical/horizontal then the old offset may not make sense, so we reset it.
|
||||
if (MapConnection::isHorizontal(this->oldDirection) != MapConnection::isHorizontal(this->newDirection)
|
||||
|| MapConnection::isVertical(this->oldDirection) != MapConnection::isVertical(this->newDirection)) {
|
||||
this->newOffset = 0;
|
||||
} else {
|
||||
this->newOffset = oldOffset;
|
||||
}
|
||||
|
||||
this->mirrored = porymapConfig.mirrorConnectingMaps;
|
||||
}
|
||||
|
||||
void MapConnectionChangeDirection::redo() {
|
||||
QUndoCommand::redo();
|
||||
if (this->connection) {
|
||||
this->connection->setDirection(this->newDirection, this->mirrored);
|
||||
this->connection->setOffset(this->newOffset, this->mirrored);
|
||||
}
|
||||
}
|
||||
|
||||
void MapConnectionChangeDirection::undo() {
|
||||
if (this->connection) {
|
||||
this->connection->setDirection(this->oldDirection, this->mirrored);
|
||||
this->connection->setOffset(this->oldOffset, this->mirrored);
|
||||
}
|
||||
QUndoCommand::undo();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
MapConnectionChangeMap::MapConnectionChangeMap(MapConnection *connection, QString newMapName,
|
||||
QUndoCommand *parent) : QUndoCommand(parent) {
|
||||
setText("Change Map Connection Map");
|
||||
|
||||
this->connection = connection;
|
||||
|
||||
this->oldMapName = connection->targetMapName();
|
||||
this->newMapName = newMapName;
|
||||
|
||||
this->oldOffset = connection->offset();
|
||||
this->newOffset = 0; // The old offset may not make sense, so we reset it
|
||||
|
||||
this->mirrored = porymapConfig.mirrorConnectingMaps;
|
||||
}
|
||||
|
||||
void MapConnectionChangeMap::redo() {
|
||||
QUndoCommand::redo();
|
||||
if (this->connection) {
|
||||
this->connection->setTargetMapName(this->newMapName, this->mirrored);
|
||||
this->connection->setOffset(this->newOffset, this->mirrored);
|
||||
}
|
||||
}
|
||||
|
||||
void MapConnectionChangeMap::undo() {
|
||||
if (this->connection) {
|
||||
this->connection->setTargetMapName(this->oldMapName, this->mirrored);
|
||||
this->connection->setOffset(this->oldOffset, this->mirrored);
|
||||
}
|
||||
QUndoCommand::undo();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
MapConnectionAdd::MapConnectionAdd(Map *map, MapConnection *connection,
|
||||
QUndoCommand *parent) : QUndoCommand(parent) {
|
||||
setText("Add Map Connection");
|
||||
|
||||
this->map = map;
|
||||
this->connection = connection;
|
||||
|
||||
// Set this now because it's needed to create a mirror below.
|
||||
// It would otherwise be set by Map::addConnection.
|
||||
this->connection->setParentMap(this->map, false);
|
||||
|
||||
if (porymapConfig.mirrorConnectingMaps) {
|
||||
this->mirror = this->connection->createMirror();
|
||||
this->mirrorMap = this->connection->targetMap();
|
||||
}
|
||||
}
|
||||
|
||||
void MapConnectionAdd::redo() {
|
||||
QUndoCommand::redo();
|
||||
|
||||
this->map->addConnection(this->connection);
|
||||
if (this->mirrorMap)
|
||||
this->mirrorMap->addConnection(this->mirror);
|
||||
}
|
||||
|
||||
void MapConnectionAdd::undo() {
|
||||
if (this->mirrorMap) {
|
||||
// We can't guarantee that the mirror we created earlier is still our connection's
|
||||
// mirror because there is no strict source->mirror pairing for map connections
|
||||
// (a different identical map connection can take its place during any mirrored change).
|
||||
if (!MapConnection::areMirrored(this->connection, this->mirror))
|
||||
this->mirror = this->connection->findMirror();
|
||||
|
||||
this->mirrorMap->removeConnection(this->mirror);
|
||||
}
|
||||
this->map->removeConnection(this->connection);
|
||||
|
||||
QUndoCommand::undo();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
MapConnectionRemove::MapConnectionRemove(Map *map, MapConnection *connection,
|
||||
QUndoCommand *parent) : QUndoCommand(parent) {
|
||||
setText("Remove Map Connection");
|
||||
|
||||
this->map = map;
|
||||
this->connection = connection;
|
||||
|
||||
if (porymapConfig.mirrorConnectingMaps) {
|
||||
this->mirror = this->connection->findMirror();
|
||||
this->mirrorMap = this->connection->targetMap();
|
||||
}
|
||||
}
|
||||
|
||||
void MapConnectionRemove::redo() {
|
||||
QUndoCommand::redo();
|
||||
|
||||
if (this->mirrorMap) {
|
||||
// See comment in MapConnectionAdd::undo
|
||||
if (!MapConnection::areMirrored(this->connection, this->mirror))
|
||||
this->mirror = this->connection->findMirror();
|
||||
|
||||
this->mirrorMap->removeConnection(this->mirror);
|
||||
}
|
||||
this->map->removeConnection(this->connection);
|
||||
}
|
||||
|
||||
void MapConnectionRemove::undo() {
|
||||
this->map->addConnection(this->connection);
|
||||
if (this->mirrorMap)
|
||||
this->mirrorMap->addConnection(this->mirror);
|
||||
|
||||
QUndoCommand::undo();
|
||||
}
|
||||
|
|
170
src/core/map.cpp
170
src/core/map.cpp
|
@ -17,11 +17,9 @@ Map::Map(QObject *parent) : QObject(parent)
|
|||
}
|
||||
|
||||
Map::~Map() {
|
||||
// delete all associated events
|
||||
while (!ownedEvents.isEmpty()) {
|
||||
Event *last = ownedEvents.takeLast();
|
||||
if (last) delete last;
|
||||
}
|
||||
qDeleteAll(ownedEvents);
|
||||
ownedEvents.clear();
|
||||
deleteConnections();
|
||||
}
|
||||
|
||||
void Map::setName(QString mapName) {
|
||||
|
@ -217,38 +215,47 @@ QPixmap Map::renderBorder(bool ignoreCache) {
|
|||
return layout->border_pixmap;
|
||||
}
|
||||
|
||||
QPixmap Map::renderConnection(MapConnection connection, MapLayout * fromLayout) {
|
||||
int x, y, w, h;
|
||||
if (connection.direction == "up") {
|
||||
x = 0;
|
||||
y = getHeight() - BORDER_DISTANCE;
|
||||
w = getWidth();
|
||||
h = BORDER_DISTANCE;
|
||||
} else if (connection.direction == "down") {
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = getWidth();
|
||||
h = BORDER_DISTANCE;
|
||||
} else if (connection.direction == "left") {
|
||||
x = getWidth() - BORDER_DISTANCE;
|
||||
y = 0;
|
||||
w = BORDER_DISTANCE;
|
||||
h = getHeight();
|
||||
} else if (connection.direction == "right") {
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = BORDER_DISTANCE;
|
||||
h = getHeight();
|
||||
} else {
|
||||
// this should not happen
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = getWidth();
|
||||
h = getHeight();
|
||||
}
|
||||
// Get the portion of the map that can be rendered when rendered as a map connection.
|
||||
// Cardinal connections render the nearest segment of their map and within the bounds of the border draw distance,
|
||||
// Dive/Emerge connections are rendered normally within the bounds of their parent map.
|
||||
QRect Map::getConnectionRect(const QString &direction, MapLayout * fromLayout) {
|
||||
int x = 0, y = 0;
|
||||
int w = getWidth(), h = getHeight();
|
||||
|
||||
render(true, fromLayout, QRect(x, y, w, h));
|
||||
QImage connection_image = image.copy(x * 16, y * 16, w * 16, h * 16);
|
||||
if (direction == "up") {
|
||||
h = qMin(h, BORDER_DISTANCE);
|
||||
y = getHeight() - h;
|
||||
} else if (direction == "down") {
|
||||
h = qMin(h, BORDER_DISTANCE);
|
||||
} else if (direction == "left") {
|
||||
w = qMin(w, BORDER_DISTANCE);
|
||||
x = getWidth() - w;
|
||||
} else if (direction == "right") {
|
||||
w = qMin(w, BORDER_DISTANCE);
|
||||
} else if (MapConnection::isDiving(direction)) {
|
||||
if (fromLayout) {
|
||||
w = qMin(w, fromLayout->getWidth());
|
||||
h = qMin(h, fromLayout->getHeight());
|
||||
}
|
||||
} else {
|
||||
// Unknown direction
|
||||
return QRect();
|
||||
}
|
||||
return QRect(x, y, w, h);
|
||||
}
|
||||
|
||||
QPixmap Map::renderConnection(const QString &direction, MapLayout * fromLayout) {
|
||||
QRect bounds = getConnectionRect(direction, fromLayout);
|
||||
if (!bounds.isValid())
|
||||
return QPixmap();
|
||||
|
||||
// 'fromLayout' will be used in 'render' to get the palettes from the parent map.
|
||||
// Dive/Emerge connections render normally with their own palettes, so we ignore this.
|
||||
if (MapConnection::isDiving(direction))
|
||||
fromLayout = nullptr;
|
||||
|
||||
render(true, fromLayout, bounds);
|
||||
QImage connection_image = image.copy(bounds.x() * 16, bounds.y() * 16, bounds.width() * 16, bounds.height() * 16);
|
||||
return QPixmap::fromImage(connection_image);
|
||||
}
|
||||
|
||||
|
@ -304,8 +311,8 @@ void Map::setDimensions(int newWidth, int newHeight, bool setNewBlockdata, bool
|
|||
Scripting::cb_MapResized(oldWidth, oldHeight, newWidth, newHeight);
|
||||
}
|
||||
|
||||
emit mapChanged(this);
|
||||
emit mapDimensionsChanged(QSize(getWidth(), getHeight()));
|
||||
modify();
|
||||
}
|
||||
|
||||
void Map::setBorderDimensions(int newWidth, int newHeight, bool setNewBlockdata, bool enableScriptCallback) {
|
||||
|
@ -322,7 +329,7 @@ void Map::setBorderDimensions(int newWidth, int newHeight, bool setNewBlockdata,
|
|||
Scripting::cb_BorderResized(oldWidth, oldHeight, newWidth, newHeight);
|
||||
}
|
||||
|
||||
emit mapChanged(this);
|
||||
modify();
|
||||
}
|
||||
|
||||
void Map::openScript(QString label) {
|
||||
|
@ -523,6 +530,72 @@ void Map::addEvent(Event *event) {
|
|||
if (!ownedEvents.contains(event)) ownedEvents.append(event);
|
||||
}
|
||||
|
||||
void Map::deleteConnections() {
|
||||
qDeleteAll(this->ownedConnections);
|
||||
this->ownedConnections.clear();
|
||||
this->connections.clear();
|
||||
}
|
||||
|
||||
QList<MapConnection*> Map::getConnections() const {
|
||||
return this->connections;
|
||||
}
|
||||
|
||||
void Map::addConnection(MapConnection *connection) {
|
||||
if (!connection || this->connections.contains(connection))
|
||||
return;
|
||||
|
||||
// Maps should only have one Dive/Emerge connection at a time.
|
||||
// (Users can technically have more by editing their data manually, but we will only display one at a time)
|
||||
// Any additional connections being added (this can happen via mirroring) are tracked for deleting but otherwise ignored.
|
||||
if (MapConnection::isDiving(connection->direction())) {
|
||||
for (auto i : this->connections) {
|
||||
if (i->direction() == connection->direction()) {
|
||||
trackConnection(connection);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loadConnection(connection);
|
||||
modify();
|
||||
emit connectionAdded(connection);
|
||||
return;
|
||||
}
|
||||
|
||||
void Map::loadConnection(MapConnection *connection) {
|
||||
if (!connection)
|
||||
return;
|
||||
|
||||
if (!this->connections.contains(connection))
|
||||
this->connections.append(connection);
|
||||
|
||||
trackConnection(connection);
|
||||
}
|
||||
|
||||
void Map::trackConnection(MapConnection *connection) {
|
||||
connection->setParentMap(this, false);
|
||||
|
||||
if (!this->ownedConnections.contains(connection)) {
|
||||
this->ownedConnections.insert(connection);
|
||||
connect(connection, &MapConnection::parentMapChanged, [=](Map *, Map *after) {
|
||||
if (after != this && after != nullptr) {
|
||||
// MapConnection's parent has been reassigned, it's no longer our responsibility
|
||||
this->ownedConnections.remove(connection);
|
||||
QObject::disconnect(connection, &MapConnection::parentMapChanged, this, nullptr);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// We retain ownership of this MapConnection until it's assigned to a new parent map.
|
||||
void Map::removeConnection(MapConnection *connection) {
|
||||
if (!this->connections.removeOne(connection))
|
||||
return;
|
||||
connection->setParentMap(nullptr, false);
|
||||
modify();
|
||||
emit connectionRemoved(connection);
|
||||
}
|
||||
|
||||
void Map::modify() {
|
||||
emit modified();
|
||||
}
|
||||
|
@ -535,6 +608,27 @@ bool Map::hasUnsavedChanges() {
|
|||
return !editHistory.isClean() || hasUnsavedDataChanges || !isPersistedToFile;
|
||||
}
|
||||
|
||||
void Map::pruneEditHistory() {
|
||||
// Edit history for map connections gets messy because edits on other maps can affect the current map.
|
||||
// To avoid complications we clear MapConnection edit history when the user opens a different map.
|
||||
// No other edits within a single map depend on MapConnections so they can be pruned safely.
|
||||
static const QSet<int> mapConnectionIds = {
|
||||
ID_MapConnectionMove,
|
||||
ID_MapConnectionChangeDirection,
|
||||
ID_MapConnectionChangeMap,
|
||||
ID_MapConnectionAdd,
|
||||
ID_MapConnectionRemove
|
||||
};
|
||||
for (int i = 0; i < this->editHistory.count(); i++) {
|
||||
// Qt really doesn't expect editing commands in the stack to be valid (fair).
|
||||
// A better future design might be to have separate edit histories per map tab,
|
||||
// and dumping the entire Connections tab history with QUndoStack::clear.
|
||||
auto command = const_cast<QUndoCommand*>(this->editHistory.command(i));
|
||||
if (mapConnectionIds.contains(command->id()))
|
||||
command->setObsolete(true);
|
||||
}
|
||||
}
|
||||
|
||||
bool Map::isWithinBounds(int x, int y) {
|
||||
return (x >= 0 && x < this->getWidth() && y >= 0 && y < this->getHeight());
|
||||
}
|
||||
|
|
163
src/core/mapconnection.cpp
Normal file
163
src/core/mapconnection.cpp
Normal file
|
@ -0,0 +1,163 @@
|
|||
#include "mapconnection.h"
|
||||
#include "project.h"
|
||||
|
||||
QPointer<Project> MapConnection::project = nullptr;
|
||||
|
||||
const QMap<QString, QString> MapConnection::oppositeDirections = {
|
||||
{"up", "down"}, {"down", "up"},
|
||||
{"right", "left"}, {"left", "right"},
|
||||
{"dive", "emerge"}, {"emerge", "dive"}
|
||||
};
|
||||
|
||||
MapConnection::MapConnection(const QString &targetMapName, const QString &direction, int offset) {
|
||||
m_parentMap = nullptr;
|
||||
m_targetMapName = targetMapName;
|
||||
m_direction = direction;
|
||||
m_offset = offset;
|
||||
}
|
||||
|
||||
bool MapConnection::areMirrored(const MapConnection* a, const MapConnection* b) {
|
||||
if (!a || !b || !a->m_parentMap || !b->m_parentMap)
|
||||
return false;
|
||||
|
||||
return a->parentMapName() == b->m_targetMapName
|
||||
&& a->m_targetMapName == b->parentMapName()
|
||||
&& a->m_offset == -b->m_offset
|
||||
&& a->m_direction == oppositeDirection(b->m_direction);
|
||||
}
|
||||
|
||||
MapConnection* MapConnection::findMirror() {
|
||||
auto map = targetMap();
|
||||
if (!map)
|
||||
return nullptr;
|
||||
|
||||
// Find the matching connection in the connected map.
|
||||
// Note: There is no strict source -> mirror pairing, i.e. we are not guaranteed
|
||||
// to always get the same MapConnection if there are multiple identical copies.
|
||||
for (auto connection : map->getConnections()) {
|
||||
if (this != connection && areMirrored(this, connection))
|
||||
return connection;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MapConnection * MapConnection::createMirror() {
|
||||
auto mirror = new MapConnection(parentMapName(), oppositeDirection(m_direction), -m_offset);
|
||||
mirror->setParentMap(targetMap(), false);
|
||||
return mirror;
|
||||
}
|
||||
|
||||
void MapConnection::markMapEdited() {
|
||||
if (m_parentMap)
|
||||
m_parentMap->modify();
|
||||
}
|
||||
|
||||
Map* MapConnection::getMap(const QString& mapName) const {
|
||||
return project ? project->getMap(mapName) : nullptr;
|
||||
}
|
||||
|
||||
Map* MapConnection::targetMap() const {
|
||||
return getMap(m_targetMapName);
|
||||
}
|
||||
|
||||
QPixmap MapConnection::getPixmap() {
|
||||
auto map = targetMap();
|
||||
if (!map)
|
||||
return QPixmap();
|
||||
|
||||
return map->renderConnection(m_direction, m_parentMap ? m_parentMap->layout : nullptr);
|
||||
}
|
||||
|
||||
void MapConnection::setParentMap(Map* map, bool mirror) {
|
||||
if (map == m_parentMap)
|
||||
return;
|
||||
|
||||
if (mirror) {
|
||||
auto connection = findMirror();
|
||||
if (connection)
|
||||
connection->setTargetMapName(map ? map->name : QString(), false);
|
||||
}
|
||||
|
||||
if (m_parentMap)
|
||||
m_parentMap->removeConnection(this);
|
||||
|
||||
auto before = m_parentMap;
|
||||
m_parentMap = map;
|
||||
|
||||
if (m_parentMap)
|
||||
m_parentMap->addConnection(this);
|
||||
|
||||
emit parentMapChanged(before, m_parentMap);
|
||||
}
|
||||
|
||||
QString MapConnection::parentMapName() const {
|
||||
return m_parentMap ? m_parentMap->name : QString();
|
||||
}
|
||||
|
||||
void MapConnection::setTargetMapName(const QString &targetMapName, bool mirror) {
|
||||
if (targetMapName == m_targetMapName)
|
||||
return;
|
||||
|
||||
if (mirror) {
|
||||
auto connection = findMirror();
|
||||
if (connection)
|
||||
connection->setParentMap(getMap(targetMapName), false);
|
||||
}
|
||||
|
||||
auto before = m_targetMapName;
|
||||
m_targetMapName = targetMapName;
|
||||
emit targetMapNameChanged(before, m_targetMapName);
|
||||
markMapEdited();
|
||||
}
|
||||
|
||||
void MapConnection::setDirection(const QString &direction, bool mirror) {
|
||||
if (direction == m_direction)
|
||||
return;
|
||||
|
||||
if (mirror) {
|
||||
auto connection = findMirror();
|
||||
if (connection)
|
||||
connection->setDirection(oppositeDirection(direction), false);
|
||||
}
|
||||
|
||||
auto before = m_direction;
|
||||
m_direction = direction;
|
||||
emit directionChanged(before, m_direction);
|
||||
markMapEdited();
|
||||
}
|
||||
|
||||
void MapConnection::setOffset(int offset, bool mirror) {
|
||||
if (offset == m_offset)
|
||||
return;
|
||||
|
||||
if (mirror) {
|
||||
auto connection = findMirror();
|
||||
if (connection)
|
||||
connection->setOffset(-offset, false);
|
||||
}
|
||||
|
||||
auto before = m_offset;
|
||||
m_offset = offset;
|
||||
emit offsetChanged(before, m_offset);
|
||||
markMapEdited();
|
||||
}
|
||||
|
||||
const QStringList MapConnection::cardinalDirections = {
|
||||
"up", "down", "left", "right"
|
||||
};
|
||||
|
||||
bool MapConnection::isCardinal(const QString &direction) {
|
||||
return cardinalDirections.contains(direction);
|
||||
}
|
||||
|
||||
bool MapConnection::isHorizontal(const QString &direction) {
|
||||
return direction == "left" || direction == "right";
|
||||
}
|
||||
|
||||
bool MapConnection::isVertical(const QString &direction) {
|
||||
return direction == "up" || direction == "down";
|
||||
}
|
||||
|
||||
bool MapConnection::isDiving(const QString &direction) {
|
||||
return direction == "dive" || direction == "emerge";
|
||||
}
|
795
src/editor.cpp
795
src/editor.cpp
|
@ -2,7 +2,7 @@
|
|||
#include "draggablepixmapitem.h"
|
||||
#include "imageproviders.h"
|
||||
#include "log.h"
|
||||
#include "mapconnection.h"
|
||||
#include "connectionslistitem.h"
|
||||
#include "currentselectedmetatilespixmapitem.h"
|
||||
#include "mapsceneeventfilter.h"
|
||||
#include "metatile.h"
|
||||
|
@ -78,6 +78,14 @@ void Editor::saveUiFields() {
|
|||
saveEncounterTabData();
|
||||
}
|
||||
|
||||
void Editor::setProject(Project * project) {
|
||||
if (this->project) {
|
||||
closeProject();
|
||||
}
|
||||
this->project = project;
|
||||
MapConnection::project = project;
|
||||
}
|
||||
|
||||
void Editor::closeProject() {
|
||||
if (!this->project)
|
||||
return;
|
||||
|
@ -92,7 +100,6 @@ void Editor::setEditingMap() {
|
|||
current_view = map_item;
|
||||
if (map_item) {
|
||||
map_item->paintingMode = MapPixmapItem::PaintMode::Metatiles;
|
||||
displayMapConnections();
|
||||
map_item->draw();
|
||||
map_item->setVisible(true);
|
||||
}
|
||||
|
@ -102,9 +109,7 @@ void Editor::setEditingMap() {
|
|||
if (events_group) {
|
||||
events_group->setVisible(false);
|
||||
}
|
||||
setBorderItemsVisible(ui->checkBox_ToggleBorder->isChecked());
|
||||
setConnectionItemsVisible(ui->checkBox_ToggleBorder->isChecked());
|
||||
setConnectionsEditable(false);
|
||||
updateBorderVisibility();
|
||||
this->cursorMapTileRect->stopSingleTileMode();
|
||||
this->cursorMapTileRect->setActive(true);
|
||||
|
||||
|
@ -114,7 +119,6 @@ void Editor::setEditingMap() {
|
|||
void Editor::setEditingCollision() {
|
||||
current_view = collision_item;
|
||||
if (collision_item) {
|
||||
displayMapConnections();
|
||||
collision_item->draw();
|
||||
collision_item->setVisible(true);
|
||||
}
|
||||
|
@ -126,9 +130,7 @@ void Editor::setEditingCollision() {
|
|||
if (events_group) {
|
||||
events_group->setVisible(false);
|
||||
}
|
||||
setBorderItemsVisible(ui->checkBox_ToggleBorder->isChecked());
|
||||
setConnectionItemsVisible(ui->checkBox_ToggleBorder->isChecked());
|
||||
setConnectionsEditable(false);
|
||||
updateBorderVisibility();
|
||||
this->cursorMapTileRect->setSingleTileMode();
|
||||
this->cursorMapTileRect->setActive(true);
|
||||
|
||||
|
@ -142,16 +144,13 @@ void Editor::setEditingObjects() {
|
|||
}
|
||||
if (map_item) {
|
||||
map_item->paintingMode = MapPixmapItem::PaintMode::EventObjects;
|
||||
displayMapConnections();
|
||||
map_item->draw();
|
||||
map_item->setVisible(true);
|
||||
}
|
||||
if (collision_item) {
|
||||
collision_item->setVisible(false);
|
||||
}
|
||||
setBorderItemsVisible(ui->checkBox_ToggleBorder->isChecked());
|
||||
setConnectionItemsVisible(ui->checkBox_ToggleBorder->isChecked());
|
||||
setConnectionsEditable(false);
|
||||
updateBorderVisibility();
|
||||
this->cursorMapTileRect->setSingleTileMode();
|
||||
this->cursorMapTileRect->setActive(false);
|
||||
updateWarpEventWarnings();
|
||||
|
@ -181,17 +180,6 @@ void Editor::setEditingConnections() {
|
|||
map_item->paintingMode = MapPixmapItem::PaintMode::Disabled;
|
||||
map_item->draw();
|
||||
map_item->setVisible(true);
|
||||
populateConnectionMapPickers();
|
||||
ui->label_NumConnections->setText(QString::number(map->connections.length()));
|
||||
setDiveEmergeControls();
|
||||
bool controlsEnabled = selected_connection_item != nullptr;
|
||||
setConnectionEditControlsEnabled(controlsEnabled);
|
||||
if (selected_connection_item) {
|
||||
onConnectionOffsetChanged(selected_connection_item->connection->offset);
|
||||
setConnectionMap(selected_connection_item->connection->map_name);
|
||||
setCurrentConnectionDirection(selected_connection_item->connection->direction);
|
||||
}
|
||||
maskNonVisibleConnectionTiles();
|
||||
}
|
||||
if (collision_item) {
|
||||
collision_item->setVisible(false);
|
||||
|
@ -199,9 +187,7 @@ void Editor::setEditingConnections() {
|
|||
if (events_group) {
|
||||
events_group->setVisible(false);
|
||||
}
|
||||
setBorderItemsVisible(true, 0.4);
|
||||
setConnectionItemsVisible(true);
|
||||
setConnectionsEditable(true);
|
||||
updateBorderVisibility();
|
||||
this->cursorMapTileRect->setSingleTileMode();
|
||||
this->cursorMapTileRect->setActive(false);
|
||||
}
|
||||
|
@ -747,193 +733,297 @@ void Editor::updateEncounterFields(EncounterFields newFields) {
|
|||
project->wildMonFields = newFields;
|
||||
}
|
||||
|
||||
void Editor::setDiveEmergeControls() {
|
||||
ui->comboBox_DiveMap->blockSignals(true);
|
||||
ui->comboBox_EmergeMap->blockSignals(true);
|
||||
ui->comboBox_DiveMap->setCurrentText("");
|
||||
ui->comboBox_EmergeMap->setCurrentText("");
|
||||
for (MapConnection* connection : map->connections) {
|
||||
if (connection->direction == "dive") {
|
||||
ui->comboBox_DiveMap->setCurrentText(connection->map_name);
|
||||
} else if (connection->direction == "emerge") {
|
||||
ui->comboBox_EmergeMap->setCurrentText(connection->map_name);
|
||||
void Editor::disconnectMapConnection(MapConnection *connection) {
|
||||
// Disconnect MapConnection's signals used by the display.
|
||||
// It'd be nice if we could just 'connection->disconnect(this)' but that doesn't account for lambda functions.
|
||||
QObject::disconnect(connection, &MapConnection::targetMapNameChanged, nullptr, nullptr);
|
||||
QObject::disconnect(connection, &MapConnection::directionChanged, nullptr, nullptr);
|
||||
QObject::disconnect(connection, &MapConnection::offsetChanged, nullptr, nullptr);
|
||||
}
|
||||
|
||||
void Editor::displayConnection(MapConnection *connection) {
|
||||
if (!connection)
|
||||
return;
|
||||
|
||||
if (MapConnection::isDiving(connection->direction())) {
|
||||
displayDivingConnection(connection);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create connection image
|
||||
ConnectionPixmapItem *pixmapItem = new ConnectionPixmapItem(connection, getConnectionOrigin(connection));
|
||||
pixmapItem->render();
|
||||
scene->addItem(pixmapItem);
|
||||
maskNonVisibleConnectionTiles();
|
||||
|
||||
// Create item for the list panel
|
||||
ConnectionsListItem *listItem = new ConnectionsListItem(ui->scrollAreaContents_ConnectionsList, pixmapItem->connection, project->mapNames);
|
||||
ui->layout_ConnectionsList->insertWidget(ui->layout_ConnectionsList->count() - 1, listItem); // Insert above the vertical spacer
|
||||
|
||||
// Double clicking the pixmap or clicking the list item's map button opens the connected map
|
||||
connect(listItem, &ConnectionsListItem::openMapClicked, this, &Editor::openConnectedMap);
|
||||
connect(pixmapItem, &ConnectionPixmapItem::connectionItemDoubleClicked, this, &Editor::openConnectedMap);
|
||||
|
||||
// Sync the selection highlight between the list UI and the pixmap
|
||||
connect(pixmapItem, &ConnectionPixmapItem::selectionChanged, [=](bool selected) {
|
||||
listItem->setSelected(selected);
|
||||
if (selected) setSelectedConnectionItem(pixmapItem);
|
||||
});
|
||||
connect(listItem, &ConnectionsListItem::selected, [=] {
|
||||
setSelectedConnectionItem(pixmapItem);
|
||||
});
|
||||
|
||||
// Sync edits to 'offset' between the list UI and the pixmap
|
||||
connect(connection, &MapConnection::offsetChanged, [=](int, int) {
|
||||
listItem->updateUI();
|
||||
pixmapItem->updatePos();
|
||||
maskNonVisibleConnectionTiles();
|
||||
});
|
||||
|
||||
// Sync edits to 'direction' between the list UI and the pixmap
|
||||
connect(connection, &MapConnection::directionChanged, [=](QString, QString) {
|
||||
listItem->updateUI();
|
||||
updateConnectionPixmap(pixmapItem);
|
||||
});
|
||||
|
||||
// Sync edits to 'map' between the list UI and the pixmap
|
||||
connect(connection, &MapConnection::targetMapNameChanged, [=](QString, QString) {
|
||||
listItem->updateUI();
|
||||
updateConnectionPixmap(pixmapItem);
|
||||
});
|
||||
|
||||
// When the pixmap is deleted, remove its associated list item
|
||||
connect(pixmapItem, &ConnectionPixmapItem::destroyed, listItem, &ConnectionsListItem::deleteLater);
|
||||
|
||||
connection_items.append(pixmapItem);
|
||||
|
||||
// If this was a recent addition from the user we should select it.
|
||||
// We intentionally exclude connections added programmatically, e.g. by mirroring.
|
||||
if (connection_to_select == connection) {
|
||||
connection_to_select = nullptr;
|
||||
setSelectedConnectionItem(pixmapItem);
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::addConnection(MapConnection *connection) {
|
||||
if (!connection)
|
||||
return;
|
||||
|
||||
// Mark this connection to be selected once its display elements have been created.
|
||||
// It's possible this is a Dive/Emerge connection, but that's ok (no selection will occur).
|
||||
connection_to_select = connection;
|
||||
|
||||
this->map->editHistory.push(new MapConnectionAdd(this->map, connection));
|
||||
}
|
||||
|
||||
void Editor::removeConnection(MapConnection *connection) {
|
||||
if (!connection)
|
||||
return;
|
||||
this->map->editHistory.push(new MapConnectionRemove(this->map, connection));
|
||||
}
|
||||
|
||||
void Editor::removeSelectedConnection() {
|
||||
if (selected_connection_item)
|
||||
removeConnection(selected_connection_item->connection);
|
||||
}
|
||||
|
||||
void Editor::removeConnectionPixmap(MapConnection *connection) {
|
||||
if (!connection)
|
||||
return;
|
||||
|
||||
disconnectMapConnection(connection);
|
||||
|
||||
if (MapConnection::isDiving(connection->direction())) {
|
||||
removeDivingMapPixmap(connection);
|
||||
return;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < connection_items.length(); i++) {
|
||||
if (connection_items.at(i)->connection == connection)
|
||||
break;
|
||||
}
|
||||
if (i == connection_items.length())
|
||||
return; // Connection is not displayed, nothing to do.
|
||||
|
||||
auto pixmapItem = connection_items.takeAt(i);
|
||||
if (pixmapItem == selected_connection_item) {
|
||||
// This was the selected connection, select the next one up in the list.
|
||||
selected_connection_item = nullptr;
|
||||
if (i != 0) i--;
|
||||
if (connection_items.length() > i)
|
||||
setSelectedConnectionItem(connection_items.at(i));
|
||||
}
|
||||
|
||||
if (pixmapItem->scene())
|
||||
pixmapItem->scene()->removeItem(pixmapItem);
|
||||
|
||||
delete pixmapItem;
|
||||
}
|
||||
|
||||
void Editor::displayDivingConnection(MapConnection *connection) {
|
||||
if (!connection)
|
||||
return;
|
||||
|
||||
const QString direction = connection->direction();
|
||||
if (!MapConnection::isDiving(direction))
|
||||
return;
|
||||
|
||||
// Note: We only support editing 1 Dive and Emerge connection per map.
|
||||
// In a vanilla game only the first Dive/Emerge connection is considered, so allowing
|
||||
// users to have multiple is likely to lead to confusion. In case users have changed
|
||||
// this we won't delete extra diving connections, but we'll only display the first one.
|
||||
if (diving_map_items.value(direction))
|
||||
return;
|
||||
|
||||
// Create map display
|
||||
auto comboBox = (direction == "dive") ? ui->comboBox_DiveMap : ui->comboBox_EmergeMap;
|
||||
auto item = new DivingMapPixmapItem(connection, comboBox);
|
||||
scene->addItem(item);
|
||||
diving_map_items.insert(direction, item);
|
||||
|
||||
updateDivingMapsVisibility();
|
||||
}
|
||||
|
||||
void Editor::renderDivingConnections() {
|
||||
for (auto item : diving_map_items.values())
|
||||
item->updatePixmap();
|
||||
}
|
||||
|
||||
void Editor::removeDivingMapPixmap(MapConnection *connection) {
|
||||
if (!connection)
|
||||
return;
|
||||
|
||||
const QString direction = connection->direction();
|
||||
if (!diving_map_items.contains(direction))
|
||||
return;
|
||||
|
||||
// If the diving map being removed is different than the one that's currently displayed we don't need to do anything.
|
||||
if (diving_map_items.value(direction)->connection() != connection)
|
||||
return;
|
||||
|
||||
// Delete map image
|
||||
auto pixmapItem = diving_map_items.take(direction);
|
||||
if (pixmapItem->scene())
|
||||
pixmapItem->scene()->removeItem(pixmapItem);
|
||||
delete pixmapItem;
|
||||
|
||||
// Reveal any previously-hidden connection (because we only ever display one diving map of each type).
|
||||
// Note: When this occurs as a result of the user clicking the 'X' clear button it seems the QComboBox
|
||||
// doesn't expect the line edit to be immediately repopulated, and the 'X' doesn't reappear.
|
||||
// As a workaround we wait before displaying the new text. The wait time is essentially arbitrary.
|
||||
for (auto i : map->getConnections()) {
|
||||
if (i->direction() == direction) {
|
||||
QTimer::singleShot(10, Qt::CoarseTimer, [this, i]() { displayDivingConnection(i); });
|
||||
break;
|
||||
}
|
||||
}
|
||||
ui->comboBox_DiveMap->blockSignals(false);
|
||||
ui->comboBox_EmergeMap->blockSignals(false);
|
||||
updateDivingMapsVisibility();
|
||||
}
|
||||
|
||||
void Editor::populateConnectionMapPickers() {
|
||||
ui->comboBox_ConnectedMap->blockSignals(true);
|
||||
ui->comboBox_DiveMap->blockSignals(true);
|
||||
ui->comboBox_EmergeMap->blockSignals(true);
|
||||
|
||||
ui->comboBox_ConnectedMap->clear();
|
||||
ui->comboBox_ConnectedMap->addItems(project->mapNames);
|
||||
ui->comboBox_DiveMap->clear();
|
||||
ui->comboBox_DiveMap->addItems(project->mapNames);
|
||||
ui->comboBox_EmergeMap->clear();
|
||||
ui->comboBox_EmergeMap->addItems(project->mapNames);
|
||||
|
||||
ui->comboBox_ConnectedMap->blockSignals(false);
|
||||
ui->comboBox_DiveMap->blockSignals(true);
|
||||
ui->comboBox_EmergeMap->blockSignals(true);
|
||||
void Editor::updateDiveMap(QString mapName) {
|
||||
setDivingMapName(mapName, "dive");
|
||||
}
|
||||
|
||||
void Editor::setConnectionItemsVisible(bool visible) {
|
||||
for (ConnectionPixmapItem* item : connection_items) {
|
||||
item->setVisible(visible);
|
||||
item->setEnabled(visible);
|
||||
void Editor::updateEmergeMap(QString mapName) {
|
||||
setDivingMapName(mapName, "emerge");
|
||||
}
|
||||
|
||||
void Editor::setDivingMapName(QString mapName, QString direction) {
|
||||
auto pixmapItem = diving_map_items.value(direction);
|
||||
MapConnection *connection = pixmapItem ? pixmapItem->connection() : nullptr;
|
||||
|
||||
if (connection) {
|
||||
if (mapName == connection->targetMapName())
|
||||
return; // No change
|
||||
|
||||
// Update existing connection
|
||||
if (mapName.isEmpty()) {
|
||||
removeConnection(connection);
|
||||
} else {
|
||||
map->editHistory.push(new MapConnectionChangeMap(connection, mapName));
|
||||
}
|
||||
} else if (!mapName.isEmpty()) {
|
||||
// Create new connection
|
||||
addConnection(new MapConnection(mapName, direction));
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::setBorderItemsVisible(bool visible, qreal opacity) {
|
||||
for (QGraphicsPixmapItem* item : borderItems) {
|
||||
item->setVisible(visible);
|
||||
item->setOpacity(opacity);
|
||||
void Editor::updateDivingMapsVisibility() {
|
||||
auto dive = diving_map_items.value("dive");
|
||||
auto emerge = diving_map_items.value("emerge");
|
||||
|
||||
if (dive && emerge) {
|
||||
// Both connections in use, use separate sliders
|
||||
ui->stackedWidget_DiveMapOpacity->setCurrentIndex(0);
|
||||
dive->setOpacity(!porymapConfig.showDiveEmergeMaps ? 0 : static_cast<qreal>(porymapConfig.diveMapOpacity) / 100);
|
||||
emerge->setOpacity(!porymapConfig.showDiveEmergeMaps ? 0 : static_cast<qreal>(porymapConfig.emergeMapOpacity) / 100);
|
||||
} else {
|
||||
// One connection in use (or none), use single slider
|
||||
ui->stackedWidget_DiveMapOpacity->setCurrentIndex(1);
|
||||
qreal opacity = !porymapConfig.showDiveEmergeMaps ? 0 : static_cast<qreal>(porymapConfig.diveEmergeMapOpacity) / 100;
|
||||
if (dive) dive->setOpacity(opacity);
|
||||
else if (emerge) emerge->setOpacity(opacity);
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::setCurrentConnectionDirection(QString curDirection) {
|
||||
if (!selected_connection_item)
|
||||
return;
|
||||
Map *connected_map = project->getMap(selected_connection_item->connection->map_name);
|
||||
if (!connected_map) {
|
||||
return;
|
||||
}
|
||||
// Get the 'origin' point for the connection's pixmap, i.e. where it should be positioned in the editor when connection->offset() == 0.
|
||||
// This differs depending on the connection's direction and the dimensions of its target map or parent map.
|
||||
QPoint Editor::getConnectionOrigin(MapConnection *connection) {
|
||||
if (!connection)
|
||||
return QPoint(0, 0);
|
||||
|
||||
selected_connection_item->connection->direction = curDirection;
|
||||
|
||||
QPixmap pixmap = connected_map->renderConnection(*selected_connection_item->connection, map->layout);
|
||||
int offset = selected_connection_item->connection->offset;
|
||||
selected_connection_item->initialOffset = offset;
|
||||
Map *parentMap = connection->parentMap();
|
||||
Map *targetMap = connection->targetMap();
|
||||
const QString direction = connection->direction();
|
||||
int x = 0, y = 0;
|
||||
if (selected_connection_item->connection->direction == "up") {
|
||||
x = offset * 16;
|
||||
y = -pixmap.height();
|
||||
} else if (selected_connection_item->connection->direction == "down") {
|
||||
x = offset * 16;
|
||||
y = map->getHeight() * 16;
|
||||
} else if (selected_connection_item->connection->direction == "left") {
|
||||
x = -pixmap.width();
|
||||
y = offset * 16;
|
||||
} else if (selected_connection_item->connection->direction == "right") {
|
||||
x = map->getWidth() * 16;
|
||||
y = offset * 16;
|
||||
|
||||
if (direction == "right") {
|
||||
if (parentMap) x = parentMap->getWidth();
|
||||
} else if (direction == "down") {
|
||||
if (parentMap) y = parentMap->getHeight();
|
||||
} else if (direction == "left") {
|
||||
if (targetMap) x = -targetMap->getConnectionRect(direction).width();
|
||||
} else if (direction == "up") {
|
||||
if (targetMap) y = -targetMap->getConnectionRect(direction).height();
|
||||
}
|
||||
|
||||
selected_connection_item->basePixmap = pixmap;
|
||||
QPainter painter(&pixmap);
|
||||
painter.setPen(QColor(255, 0, 255));
|
||||
painter.drawRect(0, 0, pixmap.width() - 1, pixmap.height() - 1);
|
||||
painter.end();
|
||||
selected_connection_item->setPixmap(pixmap);
|
||||
selected_connection_item->initialX = x;
|
||||
selected_connection_item->initialY = y;
|
||||
selected_connection_item->blockSignals(true);
|
||||
selected_connection_item->setX(x);
|
||||
selected_connection_item->setY(y);
|
||||
selected_connection_item->setZValue(-1);
|
||||
selected_connection_item->blockSignals(false);
|
||||
|
||||
setConnectionEditControlValues(selected_connection_item->connection);
|
||||
return QPoint(x * 16, y * 16);
|
||||
}
|
||||
|
||||
void Editor::updateCurrentConnectionDirection(QString curDirection) {
|
||||
if (!selected_connection_item)
|
||||
void Editor::updateConnectionPixmap(ConnectionPixmapItem *pixmapItem) {
|
||||
if (!pixmapItem)
|
||||
return;
|
||||
|
||||
QString originalDirection = selected_connection_item->connection->direction;
|
||||
setCurrentConnectionDirection(curDirection);
|
||||
updateMirroredConnectionDirection(selected_connection_item->connection, originalDirection);
|
||||
pixmapItem->setOrigin(getConnectionOrigin(pixmapItem->connection));
|
||||
pixmapItem->render(true); // Full render to reflect map changes
|
||||
|
||||
maskNonVisibleConnectionTiles();
|
||||
}
|
||||
|
||||
void Editor::onConnectionMoved(MapConnection* connection) {
|
||||
updateMirroredConnectionOffset(connection);
|
||||
onConnectionOffsetChanged(connection->offset);
|
||||
maskNonVisibleConnectionTiles();
|
||||
}
|
||||
|
||||
void Editor::onConnectionOffsetChanged(int newOffset) {
|
||||
ui->spinBox_ConnectionOffset->blockSignals(true);
|
||||
ui->spinBox_ConnectionOffset->setValue(newOffset);
|
||||
ui->spinBox_ConnectionOffset->blockSignals(false);
|
||||
|
||||
}
|
||||
|
||||
void Editor::setConnectionEditControlValues(MapConnection* connection) {
|
||||
QString mapName = connection ? connection->map_name : "";
|
||||
QString direction = connection ? connection->direction : "";
|
||||
int offset = connection ? connection->offset : 0;
|
||||
|
||||
ui->comboBox_ConnectedMap->blockSignals(true);
|
||||
ui->comboBox_ConnectionDirection->blockSignals(true);
|
||||
ui->spinBox_ConnectionOffset->blockSignals(true);
|
||||
|
||||
ui->comboBox_ConnectedMap->setCurrentText(mapName);
|
||||
ui->comboBox_ConnectionDirection->setCurrentText(direction);
|
||||
ui->spinBox_ConnectionOffset->setValue(offset);
|
||||
|
||||
ui->comboBox_ConnectedMap->blockSignals(false);
|
||||
ui->comboBox_ConnectionDirection->blockSignals(false);
|
||||
ui->spinBox_ConnectionOffset->blockSignals(false);
|
||||
}
|
||||
|
||||
void Editor::setConnectionEditControlsEnabled(bool enabled) {
|
||||
ui->comboBox_ConnectionDirection->setEnabled(enabled);
|
||||
ui->comboBox_ConnectedMap->setEnabled(enabled);
|
||||
ui->spinBox_ConnectionOffset->setEnabled(enabled);
|
||||
|
||||
if (!enabled) {
|
||||
setConnectionEditControlValues(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::setConnectionsEditable(bool editable) {
|
||||
for (ConnectionPixmapItem* item : connection_items) {
|
||||
item->setEditable(editable);
|
||||
item->updateHighlight(item == selected_connection_item);
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::onConnectionItemSelected(ConnectionPixmapItem* connectionItem) {
|
||||
if (!connectionItem)
|
||||
void Editor::setSelectedConnectionItem(ConnectionPixmapItem *pixmapItem) {
|
||||
if (!pixmapItem || pixmapItem == selected_connection_item)
|
||||
return;
|
||||
|
||||
selected_connection_item = connectionItem;
|
||||
for (ConnectionPixmapItem* item : connection_items)
|
||||
item->updateHighlight(item == selected_connection_item);
|
||||
setConnectionEditControlsEnabled(true);
|
||||
setConnectionEditControlValues(selected_connection_item->connection);
|
||||
ui->spinBox_ConnectionOffset->setMaximum(selected_connection_item->getMaxOffset());
|
||||
ui->spinBox_ConnectionOffset->setMinimum(selected_connection_item->getMinOffset());
|
||||
onConnectionOffsetChanged(selected_connection_item->connection->offset);
|
||||
if (selected_connection_item) selected_connection_item->setSelected(false);
|
||||
selected_connection_item = pixmapItem;
|
||||
selected_connection_item->setSelected(true);
|
||||
}
|
||||
|
||||
void Editor::setSelectedConnectionFromMap(QString mapName) {
|
||||
// Search for the first connection that connects to the given map map.
|
||||
for (ConnectionPixmapItem* item : connection_items) {
|
||||
if (item->connection->map_name == mapName) {
|
||||
onConnectionItemSelected(item);
|
||||
void Editor::setSelectedConnection(MapConnection *connection) {
|
||||
if (!connection)
|
||||
return;
|
||||
|
||||
for (auto item : connection_items) {
|
||||
if (item->connection == connection) {
|
||||
setSelectedConnectionItem(item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::onConnectionItemDoubleClicked(ConnectionPixmapItem* connectionItem) {
|
||||
emit loadMapRequested(connectionItem->connection->map_name, map->name);
|
||||
}
|
||||
|
||||
void Editor::onConnectionDirectionChanged(QString newDirection) {
|
||||
ui->comboBox_ConnectionDirection->blockSignals(true);
|
||||
ui->comboBox_ConnectionDirection->setCurrentText(newDirection);
|
||||
ui->comboBox_ConnectionDirection->blockSignals(false);
|
||||
}
|
||||
|
||||
void Editor::onBorderMetatilesChanged() {
|
||||
displayMapBorder();
|
||||
setBorderItemsVisible(ui->checkBox_ToggleBorder->isChecked());
|
||||
updateBorderVisibility();
|
||||
}
|
||||
|
||||
void Editor::onHoveredMovementPermissionChanged(uint16_t collision, uint16_t elevation) {
|
||||
|
@ -1113,7 +1203,10 @@ bool Editor::setMap(QString map_name) {
|
|||
// disconnect previous map's signals so they are not firing
|
||||
// multiple times if set again in the future
|
||||
if (map) {
|
||||
map->pruneEditHistory();
|
||||
map->disconnect(this);
|
||||
for (auto connection : map->getConnections())
|
||||
disconnectMapConnection(connection);
|
||||
}
|
||||
|
||||
if (project) {
|
||||
|
@ -1133,6 +1226,8 @@ bool Editor::setMap(QString map_name) {
|
|||
map_ruler->setMapDimensions(QSize(map->getWidth(), map->getHeight()));
|
||||
connect(map, &Map::mapDimensionsChanged, map_ruler, &MapRuler::setMapDimensions);
|
||||
connect(map, &Map::openScriptRequested, this, &Editor::openScript);
|
||||
connect(map, &Map::connectionAdded, this, &Editor::displayConnection);
|
||||
connect(map, &Map::connectionRemoved, this, &Editor::removeConnectionPixmap);
|
||||
updateSelectedEvents();
|
||||
}
|
||||
|
||||
|
@ -1354,16 +1449,13 @@ void Editor::clearMap() {
|
|||
clearBorderMetatiles();
|
||||
clearCurrentMetatilesSelection();
|
||||
clearMapEvents();
|
||||
//clearMapConnections();
|
||||
clearMapConnections();
|
||||
clearMapBorder();
|
||||
clearMapGrid();
|
||||
clearWildMonTables();
|
||||
clearConnectionMask();
|
||||
|
||||
// TODO: Handle connections after redesign PR.
|
||||
selected_connection_item = nullptr;
|
||||
connection_items.clear();
|
||||
connection_mask = nullptr;
|
||||
|
||||
// Clear pointers to objects deleted elsewhere
|
||||
current_view = nullptr;
|
||||
map = nullptr;
|
||||
|
||||
|
@ -1393,6 +1485,7 @@ bool Editor::displayMap() {
|
|||
displayMapBorder();
|
||||
displayMapGrid();
|
||||
displayWildMonTables();
|
||||
maskNonVisibleConnectionTiles();
|
||||
|
||||
this->map_ruler->setZValue(1000);
|
||||
scene->addItem(this->map_ruler);
|
||||
|
@ -1611,66 +1704,43 @@ DraggablePixmapItem *Editor::addMapEvent(Event *event) {
|
|||
return object;
|
||||
}
|
||||
|
||||
void Editor::displayMapConnections() {
|
||||
for (ConnectionPixmapItem* item : connection_items) {
|
||||
if (item->scene()) {
|
||||
void Editor::clearMapConnections() {
|
||||
for (auto item : connection_items) {
|
||||
if (item->scene())
|
||||
item->scene()->removeItem(item);
|
||||
}
|
||||
delete item;
|
||||
}
|
||||
selected_connection_item = nullptr;
|
||||
connection_items.clear();
|
||||
|
||||
for (MapConnection *connection : map->connections) {
|
||||
if (connection->direction == "dive" || connection->direction == "emerge") {
|
||||
continue;
|
||||
}
|
||||
createConnectionItem(connection);
|
||||
}
|
||||
const QSignalBlocker blocker1(ui->comboBox_DiveMap);
|
||||
const QSignalBlocker blocker2(ui->comboBox_EmergeMap);
|
||||
ui->comboBox_DiveMap->setCurrentText("");
|
||||
ui->comboBox_EmergeMap->setCurrentText("");
|
||||
|
||||
if (!connection_items.empty()) {
|
||||
onConnectionItemSelected(connection_items.first());
|
||||
for (auto item : diving_map_items.values()) {
|
||||
if (item->scene())
|
||||
item->scene()->removeItem(item);
|
||||
delete item;
|
||||
}
|
||||
diving_map_items.clear();
|
||||
|
||||
maskNonVisibleConnectionTiles();
|
||||
// Reset to single opacity slider
|
||||
ui->stackedWidget_DiveMapOpacity->setCurrentIndex(1);
|
||||
|
||||
selected_connection_item = nullptr;
|
||||
}
|
||||
|
||||
void Editor::createConnectionItem(MapConnection* connection) {
|
||||
Map *connected_map = project->getMap(connection->map_name);
|
||||
if (!connected_map) {
|
||||
return;
|
||||
}
|
||||
void Editor::displayMapConnections() {
|
||||
clearMapConnections();
|
||||
|
||||
QPixmap pixmap = connected_map->renderConnection(*connection, map->layout);
|
||||
int offset = connection->offset;
|
||||
int x = 0, y = 0;
|
||||
if (connection->direction == "up") {
|
||||
x = offset * 16;
|
||||
y = -pixmap.height();
|
||||
} else if (connection->direction == "down") {
|
||||
x = offset * 16;
|
||||
y = map->getHeight() * 16;
|
||||
} else if (connection->direction == "left") {
|
||||
x = -pixmap.width();
|
||||
y = offset * 16;
|
||||
} else if (connection->direction == "right") {
|
||||
x = map->getWidth() * 16;
|
||||
y = offset * 16;
|
||||
}
|
||||
for (auto connection : map->getConnections())
|
||||
displayConnection(connection);
|
||||
|
||||
ConnectionPixmapItem *item = new ConnectionPixmapItem(pixmap, connection, x, y, map->getWidth(), map->getHeight());
|
||||
item->setX(x);
|
||||
item->setY(y);
|
||||
item->setZValue(-1);
|
||||
scene->addItem(item);
|
||||
connect(item, &ConnectionPixmapItem::connectionMoved, this, &Editor::onConnectionMoved);
|
||||
connect(item, &ConnectionPixmapItem::connectionItemSelected, this, &Editor::onConnectionItemSelected);
|
||||
connect(item, &ConnectionPixmapItem::connectionItemDoubleClicked, this, &Editor::onConnectionItemDoubleClicked);
|
||||
connection_items.append(item);
|
||||
if (!connection_items.isEmpty())
|
||||
setSelectedConnectionItem(connection_items.first());
|
||||
}
|
||||
|
||||
// Hides connected map tiles that cannot be seen from the current map (beyond BORDER_DISTANCE).
|
||||
void Editor::maskNonVisibleConnectionTiles() {
|
||||
void Editor::clearConnectionMask() {
|
||||
if (connection_mask) {
|
||||
if (connection_mask->scene()) {
|
||||
connection_mask->scene()->removeItem(connection_mask);
|
||||
|
@ -1678,6 +1748,11 @@ void Editor::maskNonVisibleConnectionTiles() {
|
|||
delete connection_mask;
|
||||
connection_mask = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Hides connected map tiles that cannot be seen from the current map (beyond BORDER_DISTANCE).
|
||||
void Editor::maskNonVisibleConnectionTiles() {
|
||||
clearConnectionMask();
|
||||
|
||||
QPainterPath mask;
|
||||
mask.addRect(scene->itemsBoundingRect().toRect());
|
||||
|
@ -1719,7 +1794,7 @@ void Editor::displayMapBorder() {
|
|||
item->setX(x * 16);
|
||||
item->setY(y * 16);
|
||||
item->setZValue(-3);
|
||||
scene->addItem(item); // TODO: If the scene is taking ownership here is a double-free possible?
|
||||
scene->addItem(item);
|
||||
borderItems.append(item);
|
||||
}
|
||||
}
|
||||
|
@ -1732,17 +1807,8 @@ void Editor::updateMapBorder() {
|
|||
}
|
||||
|
||||
void Editor::updateMapConnections() {
|
||||
for (int i = 0; i < connection_items.size(); i++) {
|
||||
Map *connected_map = project->getMap(connection_items[i]->connection->map_name);
|
||||
if (!connected_map)
|
||||
continue;
|
||||
|
||||
QPixmap pixmap = connected_map->renderConnection(*(connection_items[i]->connection), map->layout);
|
||||
connection_items[i]->basePixmap = pixmap;
|
||||
connection_items[i]->setPixmap(pixmap);
|
||||
}
|
||||
|
||||
maskNonVisibleConnectionTiles();
|
||||
for (auto item : connection_items)
|
||||
item->render(true);
|
||||
}
|
||||
|
||||
int Editor::getBorderDrawDistance(int dimension) {
|
||||
|
@ -1792,214 +1858,6 @@ void Editor::displayMapGrid() {
|
|||
connect(ui->checkBox_ToggleGrid, &QCheckBox::toggled, this, &Editor::onToggleGridClicked);
|
||||
}
|
||||
|
||||
void Editor::updateConnectionOffset(int offset) {
|
||||
if (!selected_connection_item)
|
||||
return;
|
||||
|
||||
selected_connection_item->blockSignals(true);
|
||||
offset = qMin(offset, selected_connection_item->getMaxOffset());
|
||||
offset = qMax(offset, selected_connection_item->getMinOffset());
|
||||
selected_connection_item->connection->offset = offset;
|
||||
if (selected_connection_item->connection->direction == "up" || selected_connection_item->connection->direction == "down") {
|
||||
selected_connection_item->setX(selected_connection_item->initialX + (offset - selected_connection_item->initialOffset) * 16);
|
||||
} else if (selected_connection_item->connection->direction == "left" || selected_connection_item->connection->direction == "right") {
|
||||
selected_connection_item->setY(selected_connection_item->initialY + (offset - selected_connection_item->initialOffset) * 16);
|
||||
}
|
||||
selected_connection_item->blockSignals(false);
|
||||
updateMirroredConnectionOffset(selected_connection_item->connection);
|
||||
maskNonVisibleConnectionTiles();
|
||||
}
|
||||
|
||||
void Editor::setConnectionMap(QString mapName) {
|
||||
if (!mapName.isEmpty() && !project->mapNames.contains(mapName)) {
|
||||
logError(QString("Invalid map name '%1' specified for connection.").arg(mapName));
|
||||
return;
|
||||
}
|
||||
if (!selected_connection_item)
|
||||
return;
|
||||
|
||||
if (mapName.isEmpty() || mapName == DYNAMIC_MAP_NAME) {
|
||||
removeCurrentConnection();
|
||||
return;
|
||||
}
|
||||
|
||||
QString originalMapName = selected_connection_item->connection->map_name;
|
||||
setConnectionEditControlsEnabled(true);
|
||||
selected_connection_item->connection->map_name = mapName;
|
||||
setCurrentConnectionDirection(selected_connection_item->connection->direction);
|
||||
|
||||
// New map may have a different minimum offset than the last one. The maximum will be the same.
|
||||
int min = selected_connection_item->getMinOffset();
|
||||
ui->spinBox_ConnectionOffset->setMinimum(min);
|
||||
onConnectionOffsetChanged(qMax(min, selected_connection_item->connection->offset));
|
||||
|
||||
updateMirroredConnectionMap(selected_connection_item->connection, originalMapName);
|
||||
maskNonVisibleConnectionTiles();
|
||||
}
|
||||
|
||||
void Editor::addNewConnection() {
|
||||
// Find direction with least number of connections.
|
||||
QMap<QString, int> directionCounts = QMap<QString, int>({{"up", 0}, {"right", 0}, {"down", 0}, {"left", 0}});
|
||||
for (MapConnection* connection : map->connections) {
|
||||
directionCounts[connection->direction]++;
|
||||
}
|
||||
QString minDirection = "up";
|
||||
int minCount = INT_MAX;
|
||||
for (QString direction : directionCounts.keys()) {
|
||||
if (directionCounts[direction] < minCount) {
|
||||
minDirection = direction;
|
||||
minCount = directionCounts[direction];
|
||||
}
|
||||
}
|
||||
|
||||
// Don't connect the map to itself.
|
||||
QString defaultMapName = project->mapNames.first();
|
||||
if (defaultMapName == map->name) {
|
||||
defaultMapName = project->mapNames.value(1);
|
||||
}
|
||||
|
||||
MapConnection* newConnection = new MapConnection;
|
||||
newConnection->direction = minDirection;
|
||||
newConnection->offset = 0;
|
||||
newConnection->map_name = defaultMapName;
|
||||
map->connections.append(newConnection);
|
||||
createConnectionItem(newConnection);
|
||||
onConnectionItemSelected(connection_items.last());
|
||||
ui->label_NumConnections->setText(QString::number(map->connections.length()));
|
||||
|
||||
updateMirroredConnection(newConnection, newConnection->direction, newConnection->map_name);
|
||||
}
|
||||
|
||||
void Editor::updateMirroredConnectionOffset(MapConnection* connection) {
|
||||
updateMirroredConnection(connection, connection->direction, connection->map_name);
|
||||
}
|
||||
void Editor::updateMirroredConnectionDirection(MapConnection* connection, QString originalDirection) {
|
||||
updateMirroredConnection(connection, originalDirection, connection->map_name);
|
||||
}
|
||||
void Editor::updateMirroredConnectionMap(MapConnection* connection, QString originalMapName) {
|
||||
updateMirroredConnection(connection, connection->direction, originalMapName);
|
||||
}
|
||||
void Editor::removeMirroredConnection(MapConnection* connection) {
|
||||
updateMirroredConnection(connection, connection->direction, connection->map_name, true);
|
||||
}
|
||||
void Editor::updateMirroredConnection(MapConnection* connection, QString originalDirection, QString originalMapName, bool isDelete) {
|
||||
if (!ui->checkBox_MirrorConnections->isChecked())
|
||||
return;
|
||||
Map* otherMap = project->getMap(originalMapName);
|
||||
if (!otherMap)
|
||||
return;
|
||||
|
||||
static QMap<QString, QString> oppositeDirections = QMap<QString, QString>({
|
||||
{"up", "down"}, {"right", "left"},
|
||||
{"down", "up"}, {"left", "right"},
|
||||
{"dive", "emerge"},{"emerge", "dive"}});
|
||||
QString oppositeDirection = oppositeDirections.value(originalDirection);
|
||||
|
||||
// Find the matching connection in the connected map.
|
||||
MapConnection* mirrorConnection = nullptr;
|
||||
for (MapConnection* conn : otherMap->connections) {
|
||||
if (conn->direction == oppositeDirection && conn->map_name == map->name) {
|
||||
mirrorConnection = conn;
|
||||
}
|
||||
}
|
||||
|
||||
if (isDelete) {
|
||||
if (mirrorConnection) {
|
||||
otherMap->connections.removeOne(mirrorConnection);
|
||||
delete mirrorConnection;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (connection->direction != originalDirection || connection->map_name != originalMapName) {
|
||||
if (mirrorConnection) {
|
||||
otherMap->connections.removeOne(mirrorConnection);
|
||||
delete mirrorConnection;
|
||||
mirrorConnection = nullptr;
|
||||
otherMap = project->getMap(connection->map_name);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new mirrored connection, if a matching one doesn't already exist.
|
||||
if (!mirrorConnection) {
|
||||
mirrorConnection = new MapConnection;
|
||||
mirrorConnection->direction = oppositeDirections.value(connection->direction);
|
||||
mirrorConnection->map_name = map->name;
|
||||
otherMap->connections.append(mirrorConnection);
|
||||
}
|
||||
|
||||
mirrorConnection->offset = -connection->offset;
|
||||
}
|
||||
|
||||
void Editor::removeCurrentConnection() {
|
||||
if (!selected_connection_item)
|
||||
return;
|
||||
|
||||
map->connections.removeOne(selected_connection_item->connection);
|
||||
connection_items.removeOne(selected_connection_item);
|
||||
removeMirroredConnection(selected_connection_item->connection);
|
||||
|
||||
if (selected_connection_item && selected_connection_item->scene()) {
|
||||
selected_connection_item->scene()->removeItem(selected_connection_item);
|
||||
delete selected_connection_item;
|
||||
}
|
||||
|
||||
selected_connection_item = nullptr;
|
||||
setConnectionEditControlsEnabled(false);
|
||||
ui->spinBox_ConnectionOffset->setValue(0);
|
||||
ui->label_NumConnections->setText(QString::number(map->connections.length()));
|
||||
|
||||
if (connection_items.length() > 0) {
|
||||
onConnectionItemSelected(connection_items.last());
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::updateDiveMap(QString mapName) {
|
||||
updateDiveEmergeMap(mapName, "dive");
|
||||
}
|
||||
|
||||
void Editor::updateEmergeMap(QString mapName) {
|
||||
updateDiveEmergeMap(mapName, "emerge");
|
||||
}
|
||||
|
||||
void Editor::updateDiveEmergeMap(QString mapName, QString direction) {
|
||||
if (!mapName.isEmpty() && !project->mapNamesToMapConstants.contains(mapName)) {
|
||||
logError(QString("Invalid %1 connection map name: '%2'").arg(direction).arg(mapName));
|
||||
return;
|
||||
}
|
||||
|
||||
MapConnection* connection = nullptr;
|
||||
for (MapConnection* conn : map->connections) {
|
||||
if (conn->direction == direction) {
|
||||
connection = conn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mapName.isEmpty() || mapName == DYNAMIC_MAP_NAME) {
|
||||
// Remove dive/emerge connection
|
||||
if (connection) {
|
||||
map->connections.removeOne(connection);
|
||||
removeMirroredConnection(connection);
|
||||
}
|
||||
} else {
|
||||
if (!connection) {
|
||||
connection = new MapConnection;
|
||||
connection->direction = direction;
|
||||
connection->offset = 0;
|
||||
connection->map_name = mapName;
|
||||
map->connections.append(connection);
|
||||
updateMirroredConnection(connection, connection->direction, connection->map_name);
|
||||
} else {
|
||||
QString originalMapName = connection->map_name;
|
||||
connection->map_name = mapName;
|
||||
updateMirroredConnectionMap(connection, originalMapName);
|
||||
}
|
||||
}
|
||||
|
||||
ui->label_NumConnections->setText(QString::number(map->connections.length()));
|
||||
}
|
||||
|
||||
void Editor::updatePrimaryTileset(QString tilesetLabel, bool forceLoad)
|
||||
{
|
||||
if (map->layout->tileset_primary_label != tilesetLabel || forceLoad)
|
||||
|
@ -2022,17 +1880,42 @@ void Editor::updateSecondaryTileset(QString tilesetLabel, bool forceLoad)
|
|||
|
||||
void Editor::toggleBorderVisibility(bool visible, bool enableScriptCallback)
|
||||
{
|
||||
this->setBorderItemsVisible(visible);
|
||||
this->setConnectionItemsVisible(visible);
|
||||
porymapConfig.showBorder = visible;
|
||||
updateBorderVisibility();
|
||||
if (enableScriptCallback)
|
||||
Scripting::cb_BorderVisibilityToggled(visible);
|
||||
}
|
||||
|
||||
void Editor::updateBorderVisibility() {
|
||||
// On the connections tab the border is always visible, and the connections can be edited.
|
||||
bool editingConnections = (ui->mainTabBar->currentIndex() == MainTab::Connections);
|
||||
bool visible = (editingConnections || ui->checkBox_ToggleBorder->isChecked());
|
||||
|
||||
// Update border
|
||||
const qreal borderOpacity = editingConnections ? 0.4 : 1;
|
||||
for (QGraphicsPixmapItem* item : borderItems) {
|
||||
item->setVisible(visible);
|
||||
item->setOpacity(borderOpacity);
|
||||
}
|
||||
|
||||
// Update map connections
|
||||
for (ConnectionPixmapItem* item : connection_items) {
|
||||
item->setVisible(visible);
|
||||
item->setEditable(editingConnections);
|
||||
item->setEnabled(visible);
|
||||
|
||||
// When connecting a map to itself we don't bother to re-render the map connections in real-time,
|
||||
// i.e. if the user paints a new metatile on the map this isn't immediately reflected in the connection.
|
||||
// We're rendering them now, so we take the opportunity to do a full re-render for self-connections.
|
||||
bool fullRender = (this->map && item->connection && this->map->name == item->connection->targetMapName());
|
||||
item->render(fullRender);
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::updateCustomMapHeaderValues(QTableWidget *table)
|
||||
{
|
||||
map->customHeaders = CustomAttributesTable::getAttributes(table);
|
||||
emit editedMapData();
|
||||
map->modify();
|
||||
}
|
||||
|
||||
Tileset* Editor::getCurrentMapPrimaryTileset()
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "prefab.h"
|
||||
#include "montabwidget.h"
|
||||
#include "imageexport.h"
|
||||
#include "newmapconnectiondialog.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QClipboard>
|
||||
|
@ -150,9 +151,9 @@ void MainWindow::initExtraShortcuts() {
|
|||
shortcutDuplicate_Events->setWhatsThis("Duplicate Selected Event(s)");
|
||||
|
||||
auto *shortcutDelete_Object = new Shortcut(
|
||||
{QKeySequence("Del"), QKeySequence("Backspace")}, this, SLOT(on_toolButton_deleteObject_clicked()));
|
||||
{QKeySequence("Del"), QKeySequence("Backspace")}, this, SLOT(onDeleteKeyPressed()));
|
||||
shortcutDelete_Object->setObjectName("shortcutDelete_Object");
|
||||
shortcutDelete_Object->setWhatsThis("Delete Selected Event(s)");
|
||||
shortcutDelete_Object->setWhatsThis("Delete Selected Item(s)");
|
||||
|
||||
auto *shortcutToggle_Border = new Shortcut(QKeySequence(), ui->checkBox_ToggleBorder, SLOT(toggle()));
|
||||
shortcutToggle_Border->setObjectName("shortcutToggle_Border");
|
||||
|
@ -208,16 +209,23 @@ void MainWindow::applyUserShortcuts() {
|
|||
shortcut->setKeys(shortcutsConfig.userShortcuts(shortcut));
|
||||
}
|
||||
|
||||
static const QMap<int, QString> mainTabNames = {
|
||||
{MainTab::Map, "Map"},
|
||||
{MainTab::Events, "Events"},
|
||||
{MainTab::Header, "Header"},
|
||||
{MainTab::Connections, "Connections"},
|
||||
{MainTab::WildPokemon, "Wild Pokemon"},
|
||||
};
|
||||
|
||||
void MainWindow::initCustomUI() {
|
||||
// Set up the tab bar
|
||||
while (ui->mainTabBar->count()) ui->mainTabBar->removeTab(0);
|
||||
ui->mainTabBar->addTab("Map");
|
||||
ui->mainTabBar->setTabIcon(0, QIcon(QStringLiteral(":/icons/map.ico")));
|
||||
ui->mainTabBar->addTab("Events");
|
||||
ui->mainTabBar->addTab("Header");
|
||||
ui->mainTabBar->addTab("Connections");
|
||||
ui->mainTabBar->addTab("Wild Pokemon");
|
||||
ui->mainTabBar->setTabIcon(4, QIcon(QStringLiteral(":/icons/tall_grass.ico")));
|
||||
|
||||
for (int i = 0; i < mainTabNames.count(); i++)
|
||||
ui->mainTabBar->addTab(mainTabNames.value(i));
|
||||
|
||||
ui->mainTabBar->setTabIcon(MainTab::Map, QIcon(QStringLiteral(":/icons/map.ico")));
|
||||
ui->mainTabBar->setTabIcon(MainTab::WildPokemon, QIcon(QStringLiteral(":/icons/tall_grass.ico")));
|
||||
}
|
||||
|
||||
void MainWindow::initExtraSignals() {
|
||||
|
@ -298,12 +306,11 @@ void MainWindow::checkForUpdates(bool) {}
|
|||
void MainWindow::initEditor() {
|
||||
this->editor = new Editor(ui);
|
||||
connect(this->editor, &Editor::objectsChanged, this, &MainWindow::updateObjects);
|
||||
connect(this->editor, &Editor::loadMapRequested, this, &MainWindow::onLoadMapRequested);
|
||||
connect(this->editor, &Editor::openConnectedMap, this, &MainWindow::onOpenConnectedMap);
|
||||
connect(this->editor, &Editor::warpEventDoubleClicked, this, &MainWindow::openWarpMap);
|
||||
connect(this->editor, &Editor::currentMetatilesSelectionChanged, this, &MainWindow::currentMetatilesSelectionChanged);
|
||||
connect(this->editor, &Editor::wildMonDataChanged, this, &MainWindow::onWildMonDataChanged);
|
||||
connect(this->editor, &Editor::mapRulerStatusChanged, this, &MainWindow::onMapRulerStatusChanged);
|
||||
connect(this->editor, &Editor::editedMapData, this, &MainWindow::markMapEdited);
|
||||
connect(this->editor, &Editor::tilesetUpdated, this, &Scripting::cb_TilesetUpdated);
|
||||
connect(ui->toolButton_Open_Scripts, &QToolButton::pressed, this->editor, &Editor::openMapScripts);
|
||||
connect(ui->actionOpen_Project_in_Text_Editor, &QAction::triggered, this->editor, &Editor::openProjectInTextEditor);
|
||||
|
@ -355,9 +362,7 @@ void MainWindow::initEditor() {
|
|||
}
|
||||
|
||||
void MainWindow::initMiscHeapObjects() {
|
||||
mapIcon = new QIcon(QStringLiteral(":/icons/map.ico"));
|
||||
mapEditedIcon = new QIcon(QStringLiteral(":/icons/map_edited.ico"));
|
||||
mapOpenedIcon = new QIcon(QStringLiteral(":/icons/map_opened.ico"));
|
||||
mapIcon = QIcon(QStringLiteral(":/icons/map.ico"));
|
||||
|
||||
mapListModel = new QStandardItemModel;
|
||||
mapGroupItemsList = new QList<QStandardItem*>;
|
||||
|
@ -400,10 +405,17 @@ void MainWindow::showWindowTitle() {
|
|||
}
|
||||
|
||||
void MainWindow::markMapEdited() {
|
||||
if (editor && editor->map) {
|
||||
editor->map->hasUnsavedDataChanges = true;
|
||||
if (editor) markMapEdited(editor->map);
|
||||
}
|
||||
|
||||
void MainWindow::markMapEdited(Map* map) {
|
||||
if (!map)
|
||||
return;
|
||||
map->hasUnsavedDataChanges = true;
|
||||
|
||||
updateMapListIcon(map->name);
|
||||
if (editor && editor->map == map)
|
||||
showWindowTitle();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::mapSortOrder_changed(QAction *action)
|
||||
|
@ -448,6 +460,13 @@ void MainWindow::applyMapListFilter(QString filterText)
|
|||
}
|
||||
|
||||
void MainWindow::loadUserSettings() {
|
||||
const QSignalBlocker blocker1(ui->horizontalSlider_CollisionTransparency);
|
||||
const QSignalBlocker blocker2(ui->slider_DiveEmergeMapOpacity);
|
||||
const QSignalBlocker blocker3(ui->slider_DiveMapOpacity);
|
||||
const QSignalBlocker blocker4(ui->slider_EmergeMapOpacity);
|
||||
const QSignalBlocker blocker5(ui->horizontalSlider_MetatileZoom);
|
||||
const QSignalBlocker blocker6(ui->horizontalSlider_CollisionZoom);
|
||||
|
||||
ui->actionBetter_Cursors->setChecked(porymapConfig.prettyCursors);
|
||||
this->editor->settings->betterCursors = porymapConfig.prettyCursors;
|
||||
ui->actionPlayer_View_Rectangle->setChecked(porymapConfig.showPlayerView);
|
||||
|
@ -456,17 +475,17 @@ void MainWindow::loadUserSettings() {
|
|||
this->editor->settings->cursorTileRectEnabled = porymapConfig.showCursorTile;
|
||||
ui->checkBox_ToggleBorder->setChecked(porymapConfig.showBorder);
|
||||
ui->checkBox_ToggleGrid->setChecked(porymapConfig.showGrid);
|
||||
ui->horizontalSlider_CollisionTransparency->blockSignals(true);
|
||||
ui->checkBox_MirrorConnections->setChecked(porymapConfig.mirrorConnectingMaps);
|
||||
this->editor->collisionOpacity = static_cast<qreal>(porymapConfig.collisionOpacity) / 100;
|
||||
ui->horizontalSlider_CollisionTransparency->setValue(porymapConfig.collisionOpacity);
|
||||
ui->horizontalSlider_CollisionTransparency->blockSignals(false);
|
||||
ui->horizontalSlider_MetatileZoom->blockSignals(true);
|
||||
ui->slider_DiveEmergeMapOpacity->setValue(porymapConfig.diveEmergeMapOpacity);
|
||||
ui->slider_DiveMapOpacity->setValue(porymapConfig.diveMapOpacity);
|
||||
ui->slider_EmergeMapOpacity->setValue(porymapConfig.emergeMapOpacity);
|
||||
ui->horizontalSlider_MetatileZoom->setValue(porymapConfig.metatilesZoom);
|
||||
ui->horizontalSlider_MetatileZoom->blockSignals(false);
|
||||
ui->horizontalSlider_CollisionZoom->blockSignals(true);
|
||||
ui->horizontalSlider_CollisionZoom->setValue(porymapConfig.collisionZoom);
|
||||
ui->horizontalSlider_CollisionZoom->blockSignals(false);
|
||||
|
||||
setTheme(porymapConfig.theme);
|
||||
setDivingMapsVisible(porymapConfig.showDiveEmergeMaps);
|
||||
}
|
||||
|
||||
void MainWindow::restoreWindowState() {
|
||||
|
@ -537,15 +556,17 @@ bool MainWindow::openProject(QString dir, bool initial) {
|
|||
Scripting::init(this);
|
||||
|
||||
// Create the project
|
||||
this->editor->project = new Project(this);
|
||||
QObject::connect(this->editor->project, &Project::reloadProject, this, &MainWindow::on_action_Reload_Project_triggered);
|
||||
QObject::connect(this->editor->project, &Project::mapCacheCleared, this, &MainWindow::onMapCacheCleared);
|
||||
QObject::connect(this->editor->project, &Project::uncheckMonitorFilesAction, [this]() {
|
||||
auto project = new Project(this);
|
||||
project->set_root(dir);
|
||||
QObject::connect(project, &Project::reloadProject, this, &MainWindow::on_action_Reload_Project_triggered);
|
||||
QObject::connect(project, &Project::mapCacheCleared, this, &MainWindow::onMapCacheCleared);
|
||||
QObject::connect(project, &Project::mapLoaded, this, &MainWindow::onMapLoaded);
|
||||
QObject::connect(project, &Project::uncheckMonitorFilesAction, [this]() {
|
||||
porymapConfig.monitorFiles = false;
|
||||
if (this->preferenceEditor)
|
||||
this->preferenceEditor->updateFields();
|
||||
});
|
||||
this->editor->project->set_root(dir);
|
||||
this->editor->setProject(project);
|
||||
|
||||
// Make sure project looks reasonable before attempting to load it
|
||||
if (!checkProjectSanity()) {
|
||||
|
@ -720,9 +741,34 @@ void MainWindow::on_action_Close_Project_triggered() {
|
|||
porymapConfig.projectManuallyClosed = true;
|
||||
}
|
||||
|
||||
// setMap, but with a visible error message in case of failure.
|
||||
// Use when the user is specifically requesting a map to open.
|
||||
bool MainWindow::userSetMap(QString map_name, bool scrollTreeView) {
|
||||
if (editor->map && editor->map->name == map_name)
|
||||
return true; // Already set
|
||||
|
||||
if (map_name == DYNAMIC_MAP_NAME) {
|
||||
QMessageBox msgBox(this);
|
||||
QString errorMsg = QString("The map '%1' can't be opened, it's a placeholder to indicate the specified map will be set programmatically.").arg(map_name);
|
||||
msgBox.critical(nullptr, "Error Opening Map", errorMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!setMap(map_name, scrollTreeView)) {
|
||||
QMessageBox msgBox(this);
|
||||
QString errorMsg = QString("There was an error opening map %1. Please see %2 for full error details.\n\n%3")
|
||||
.arg(map_name)
|
||||
.arg(getLogPath())
|
||||
.arg(getMostRecentError());
|
||||
msgBox.critical(nullptr, "Error Opening Map", errorMsg);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MainWindow::setMap(QString map_name, bool scrollTreeView) {
|
||||
logInfo(QString("Setting map to '%1'").arg(map_name));
|
||||
if (map_name.isEmpty()) {
|
||||
if (map_name.isEmpty() || map_name == DYNAMIC_MAP_NAME) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -750,12 +796,13 @@ bool MainWindow::setMap(QString map_name, bool scrollTreeView) {
|
|||
|
||||
showWindowTitle();
|
||||
|
||||
connect(editor->map, &Map::mapChanged, this, &MainWindow::onMapChanged);
|
||||
connect(editor->map, &Map::mapNeedsRedrawing, this, &MainWindow::onMapNeedsRedrawing);
|
||||
connect(editor->map, &Map::modified, [this](){ this->markMapEdited(); });
|
||||
|
||||
// Swap the "currently-open" icon from the old map to the new map
|
||||
if (!userConfig.recentMap.isEmpty() && userConfig.recentMap != map_name)
|
||||
updateMapListIcon(userConfig.recentMap);
|
||||
userConfig.recentMap = map_name;
|
||||
updateMapList();
|
||||
updateMapListIcon(userConfig.recentMap);
|
||||
|
||||
Scripting::cb_MapOpened(map_name);
|
||||
prefab.updatePrefabUi(editor->map);
|
||||
|
@ -801,10 +848,6 @@ void MainWindow::refreshMapScene()
|
|||
}
|
||||
|
||||
void MainWindow::openWarpMap(QString map_name, int event_id, Event::Group event_group) {
|
||||
// Can't warp to dynamic maps
|
||||
if (map_name == DYNAMIC_MAP_NAME)
|
||||
return;
|
||||
|
||||
// Ensure valid destination map name.
|
||||
if (!editor->project->mapNames.contains(map_name)) {
|
||||
logError(QString("Invalid map name '%1'").arg(map_name));
|
||||
|
@ -812,15 +855,8 @@ void MainWindow::openWarpMap(QString map_name, int event_id, Event::Group event_
|
|||
}
|
||||
|
||||
// Open the destination map.
|
||||
if (!setMap(map_name, true)) {
|
||||
QMessageBox msgBox(this);
|
||||
QString errorMsg = QString("There was an error opening map %1. Please see %2 for full error details.\n\n%3")
|
||||
.arg(map_name)
|
||||
.arg(getLogPath())
|
||||
.arg(getMostRecentError());
|
||||
msgBox.critical(nullptr, "Error Opening Map", errorMsg);
|
||||
if (!userSetMap(map_name, true))
|
||||
return;
|
||||
}
|
||||
|
||||
// Select the target event.
|
||||
int index = event_id - Event::getIndexOffset(event_group);
|
||||
|
@ -869,12 +905,8 @@ void MainWindow::displayMapProperties() {
|
|||
ui->frame_3->setEnabled(true);
|
||||
Map *map = editor->map;
|
||||
|
||||
ui->comboBox_PrimaryTileset->blockSignals(true);
|
||||
ui->comboBox_SecondaryTileset->blockSignals(true);
|
||||
ui->comboBox_PrimaryTileset->setCurrentText(map->layout->tileset_primary_label);
|
||||
ui->comboBox_SecondaryTileset->setCurrentText(map->layout->tileset_secondary_label);
|
||||
ui->comboBox_PrimaryTileset->blockSignals(false);
|
||||
ui->comboBox_SecondaryTileset->blockSignals(false);
|
||||
|
||||
ui->comboBox_Song->setCurrentText(map->song);
|
||||
ui->comboBox_Location->setCurrentText(map->location);
|
||||
|
@ -997,6 +1029,8 @@ bool MainWindow::setProjectUI() {
|
|||
const QSignalBlocker blocker5(ui->comboBox_Weather);
|
||||
const QSignalBlocker blocker6(ui->comboBox_BattleScene);
|
||||
const QSignalBlocker blocker7(ui->comboBox_Type);
|
||||
const QSignalBlocker blocker8(ui->comboBox_DiveMap);
|
||||
const QSignalBlocker blocker9(ui->comboBox_EmergeMap);
|
||||
|
||||
// Set up project comboboxes
|
||||
ui->comboBox_Song->clear();
|
||||
|
@ -1013,14 +1047,21 @@ bool MainWindow::setProjectUI() {
|
|||
ui->comboBox_BattleScene->addItems(project->mapBattleScenes);
|
||||
ui->comboBox_Type->clear();
|
||||
ui->comboBox_Type->addItems(project->mapTypes);
|
||||
ui->comboBox_DiveMap->clear();
|
||||
ui->comboBox_DiveMap->addItems(project->mapNames);
|
||||
ui->comboBox_DiveMap->setClearButtonEnabled(true);
|
||||
ui->comboBox_DiveMap->setFocusedScrollingEnabled(false);
|
||||
ui->comboBox_EmergeMap->clear();
|
||||
ui->comboBox_EmergeMap->addItems(project->mapNames);
|
||||
ui->comboBox_EmergeMap->setClearButtonEnabled(true);
|
||||
ui->comboBox_EmergeMap->setFocusedScrollingEnabled(false);
|
||||
|
||||
sortMapList();
|
||||
|
||||
// Show/hide parts of the UI that are dependent on the user's project settings
|
||||
|
||||
// Wild Encounters tab
|
||||
// TODO: This index should come from an enum
|
||||
ui->mainTabBar->setTabEnabled(4, editor->project->wildEncountersLoaded);
|
||||
ui->mainTabBar->setTabEnabled(MainTab::WildPokemon, editor->project->wildEncountersLoaded);
|
||||
|
||||
bool hasFlags = projectConfig.mapAllowFlagsEnabled;
|
||||
ui->checkBox_AllowRunning->setVisible(hasFlags);
|
||||
|
@ -1055,6 +1096,8 @@ void MainWindow::clearProjectUI() {
|
|||
const QSignalBlocker blocker5(ui->comboBox_Weather);
|
||||
const QSignalBlocker blocker6(ui->comboBox_BattleScene);
|
||||
const QSignalBlocker blocker7(ui->comboBox_Type);
|
||||
const QSignalBlocker blocker8(ui->comboBox_DiveMap);
|
||||
const QSignalBlocker blocker9(ui->comboBox_EmergeMap);
|
||||
|
||||
ui->comboBox_Song->clear();
|
||||
ui->comboBox_Location->clear();
|
||||
|
@ -1063,6 +1106,8 @@ void MainWindow::clearProjectUI() {
|
|||
ui->comboBox_Weather->clear();
|
||||
ui->comboBox_BattleScene->clear();
|
||||
ui->comboBox_Type->clear();
|
||||
ui->comboBox_DiveMap->clear();
|
||||
ui->comboBox_EmergeMap->clear();
|
||||
|
||||
// Clear map list
|
||||
mapListModel->clear();
|
||||
|
@ -1180,7 +1225,7 @@ void MainWindow::sortMapList() {
|
|||
QStandardItem* MainWindow::createMapItem(QString mapName, int groupNum, int inGroupNum) {
|
||||
QStandardItem *map = new QStandardItem;
|
||||
map->setText(QString("[%1.%2] ").arg(groupNum).arg(inGroupNum, 2, 10, QLatin1Char('0')) + mapName);
|
||||
map->setIcon(*mapIcon);
|
||||
map->setIcon(mapIcon);
|
||||
map->setEditable(false);
|
||||
map->setData(mapName, Qt::UserRole);
|
||||
map->setData("map_name", MapListUserRoles::TypeRole);
|
||||
|
@ -1268,6 +1313,16 @@ void MainWindow::onNewMapCreated() {
|
|||
sortMapList();
|
||||
setMap(newMapName, true);
|
||||
|
||||
// Refresh any combo box that displays map names and persists between maps
|
||||
// (other combo boxes like for warp destinations are repopulated when the map changes).
|
||||
int index = this->editor->project->mapNames.indexOf(newMapName);
|
||||
if (index >= 0) {
|
||||
const QSignalBlocker blocker1(ui->comboBox_DiveMap);
|
||||
const QSignalBlocker blocker2(ui->comboBox_EmergeMap);
|
||||
ui->comboBox_DiveMap->insertItem(index, newMapName);
|
||||
ui->comboBox_EmergeMap->insertItem(index, newMapName);
|
||||
}
|
||||
|
||||
if (newMap->needsHealLocation) {
|
||||
addNewEvent(Event::Type::HealLocation);
|
||||
editor->project->saveHealLocations(newMap);
|
||||
|
@ -1472,51 +1527,46 @@ void MainWindow::currentMetatilesSelectionChanged() {
|
|||
void MainWindow::on_mapList_activated(const QModelIndex &index)
|
||||
{
|
||||
QVariant data = index.data(Qt::UserRole);
|
||||
if (index.data(MapListUserRoles::TypeRole) == "map_name" && !data.isNull()) {
|
||||
QString mapName = data.toString();
|
||||
if (!setMap(mapName)) {
|
||||
QMessageBox msgBox(this);
|
||||
QString errorMsg = QString("There was an error opening map %1. Please see %2 for full error details.\n\n%3")
|
||||
.arg(mapName)
|
||||
.arg(getLogPath())
|
||||
.arg(getMostRecentError());
|
||||
msgBox.critical(nullptr, "Error Opening Map", errorMsg);
|
||||
}
|
||||
}
|
||||
if (index.data(MapListUserRoles::TypeRole) == "map_name" && !data.isNull())
|
||||
userSetMap(data.toString());
|
||||
}
|
||||
|
||||
void MainWindow::drawMapListIcons(QAbstractItemModel *model) {
|
||||
projectHasUnsavedChanges = false;
|
||||
QList<QModelIndex> list;
|
||||
list.append(QModelIndex());
|
||||
while (list.length()) {
|
||||
QModelIndex parent = list.takeFirst();
|
||||
for (int i = 0; i < model->rowCount(parent); i++) {
|
||||
QModelIndex index = model->index(i, 0, parent);
|
||||
if (model->hasChildren(index)) {
|
||||
list.append(index);
|
||||
}
|
||||
QVariant data = index.data(Qt::UserRole);
|
||||
if (!data.isNull()) {
|
||||
QString map_name = data.toString();
|
||||
if (editor->project && editor->project->mapCache.contains(map_name)) {
|
||||
QStandardItem *map = mapListModel->itemFromIndex(mapListIndexes.value(map_name));
|
||||
map->setIcon(*mapIcon);
|
||||
if (editor->project->mapCache.value(map_name)->hasUnsavedChanges()) {
|
||||
map->setIcon(*mapEditedIcon);
|
||||
projectHasUnsavedChanges = true;
|
||||
}
|
||||
if (editor->map->name == map_name) {
|
||||
map->setIcon(*mapOpenedIcon);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void MainWindow::updateMapListIcon(const QString &mapName) {
|
||||
if (!editor->project || !editor->project->mapCache.contains(mapName))
|
||||
return;
|
||||
|
||||
QStandardItem *item = mapListModel->itemFromIndex(mapListIndexes.value(mapName));
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
static const QIcon mapEditedIcon = QIcon(QStringLiteral(":/icons/map_edited.ico"));
|
||||
static const QIcon mapOpenedIcon = QIcon(QStringLiteral(":/icons/map_opened.ico"));
|
||||
|
||||
if (editor->map && editor->map->name == mapName) {
|
||||
item->setIcon(mapOpenedIcon);
|
||||
} else if (editor->project->mapCache.value(mapName)->hasUnsavedChanges()) {
|
||||
item->setIcon(mapEditedIcon);
|
||||
} else {
|
||||
item->setIcon(mapIcon);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::updateMapList() {
|
||||
drawMapListIcons(mapListModel);
|
||||
QList<QModelIndex> list;
|
||||
list.append(QModelIndex());
|
||||
while (list.length()) {
|
||||
QModelIndex parent = list.takeFirst();
|
||||
for (int i = 0; i < mapListModel->rowCount(parent); i++) {
|
||||
QModelIndex index = mapListModel->index(i, 0, parent);
|
||||
if (mapListModel->hasChildren(index)) {
|
||||
list.append(index);
|
||||
}
|
||||
QVariant data = index.data(Qt::UserRole);
|
||||
if (!data.isNull()) {
|
||||
updateMapListIcon(data.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_action_Save_Project_triggered() {
|
||||
|
@ -1525,6 +1575,13 @@ void MainWindow::on_action_Save_Project_triggered() {
|
|||
showWindowTitle();
|
||||
}
|
||||
|
||||
void MainWindow::on_action_Save_triggered() {
|
||||
editor->save();
|
||||
if (editor->map)
|
||||
updateMapListIcon(editor->map->name);
|
||||
showWindowTitle();
|
||||
}
|
||||
|
||||
void MainWindow::duplicate() {
|
||||
editor->duplicateSelectedEvents();
|
||||
}
|
||||
|
@ -1574,7 +1631,7 @@ void MainWindow::copy() {
|
|||
{
|
||||
default:
|
||||
break;
|
||||
case 0:
|
||||
case MainTab::Map:
|
||||
{
|
||||
// copy the map image
|
||||
QPixmap pixmap = editor->map ? editor->map->render(true) : QPixmap();
|
||||
|
@ -1582,7 +1639,7 @@ void MainWindow::copy() {
|
|||
logInfo("Copied current map image to clipboard");
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
case MainTab::Events:
|
||||
{
|
||||
if (!editor || !editor->project) break;
|
||||
|
||||
|
@ -1622,7 +1679,7 @@ void MainWindow::copy() {
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (this->ui->mainTabBar->currentIndex() == 4) {
|
||||
else if (this->ui->mainTabBar->currentIndex() == MainTab::WildPokemon) {
|
||||
QWidget *w = this->ui->stackedWidget_WildMons->currentWidget();
|
||||
if (w) {
|
||||
MonTabWidget *mtw = static_cast<MonTabWidget *>(w);
|
||||
|
@ -1653,7 +1710,7 @@ void MainWindow::paste() {
|
|||
QClipboard *clipboard = QGuiApplication::clipboard();
|
||||
QString clipboardText(clipboard->text());
|
||||
|
||||
if (ui->mainTabBar->currentIndex() == 4) {
|
||||
if (ui->mainTabBar->currentIndex() == MainTab::WildPokemon) {
|
||||
QWidget *w = this->ui->stackedWidget_WildMons->currentWidget();
|
||||
if (w) {
|
||||
w->setFocus();
|
||||
|
@ -1681,7 +1738,7 @@ void MainWindow::paste() {
|
|||
{
|
||||
default:
|
||||
break;
|
||||
case 0:
|
||||
case MainTab::Map:
|
||||
{
|
||||
// can only paste currently selected metatiles on this tab
|
||||
if (pasteObject["object"].toString() != "metatile_selection") {
|
||||
|
@ -1777,12 +1834,6 @@ void MainWindow::paste() {
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_action_Save_triggered() {
|
||||
editor->save();
|
||||
updateMapList();
|
||||
showWindowTitle();
|
||||
}
|
||||
|
||||
void MainWindow::on_mapViewTab_tabBarClicked(int index)
|
||||
{
|
||||
int oldIndex = ui->mapViewTab->currentIndex();
|
||||
|
@ -1790,11 +1841,11 @@ void MainWindow::on_mapViewTab_tabBarClicked(int index)
|
|||
if (index != oldIndex)
|
||||
Scripting::cb_MapViewTabChanged(oldIndex, index);
|
||||
|
||||
if (index == 0) {
|
||||
if (index == MapViewTab::Metatiles) {
|
||||
editor->setEditingMap();
|
||||
} else if (index == 1) {
|
||||
} else if (index == MapViewTab::Collision) {
|
||||
editor->setEditingCollision();
|
||||
} else if (index == 2) {
|
||||
} else if (index == MapViewTab::Prefabs) {
|
||||
editor->setEditingMap();
|
||||
if (projectConfig.prefabFilepath.isEmpty() && !projectConfig.prefabImportPrompted) {
|
||||
// User hasn't set up prefabs and hasn't been prompted before.
|
||||
|
@ -1813,25 +1864,33 @@ void MainWindow::on_mainTabBar_tabBarClicked(int index)
|
|||
if (index != oldIndex)
|
||||
Scripting::cb_MainTabChanged(oldIndex, index);
|
||||
|
||||
int tabIndexToStackIndex[5] = {0, 0, 1, 2, 3};
|
||||
ui->mainStackedWidget->setCurrentIndex(tabIndexToStackIndex[index]);
|
||||
static const QMap<int, int> tabIndexToStackIndex = {
|
||||
{MainTab::Map, 0},
|
||||
{MainTab::Events, 0},
|
||||
{MainTab::Header, 1},
|
||||
{MainTab::Connections, 2},
|
||||
{MainTab::WildPokemon, 3},
|
||||
};
|
||||
ui->mainStackedWidget->setCurrentIndex(tabIndexToStackIndex.value(index));
|
||||
|
||||
if (index == 0) {
|
||||
if (index == MainTab::Map) {
|
||||
ui->stackedWidget_MapEvents->setCurrentIndex(0);
|
||||
on_mapViewTab_tabBarClicked(ui->mapViewTab->currentIndex());
|
||||
clickToolButtonFromEditMode(editor->map_edit_mode);
|
||||
} else if (index == 1) {
|
||||
} else if (index == MainTab::Events) {
|
||||
ui->stackedWidget_MapEvents->setCurrentIndex(1);
|
||||
editor->setEditingObjects();
|
||||
clickToolButtonFromEditMode(editor->obj_edit_mode);
|
||||
} else if (index == 3) {
|
||||
} else if (index == MainTab::Connections) {
|
||||
editor->setEditingConnections();
|
||||
// Stop the Dive/Emerge combo boxes from getting the initial focus
|
||||
ui->graphicsView_Connections->setFocus();
|
||||
}
|
||||
if (index != 4) {
|
||||
if (index != MainTab::WildPokemon) {
|
||||
if (editor->project && editor->project->wildEncountersLoaded)
|
||||
editor->saveEncounterTabData();
|
||||
}
|
||||
if (index != 1) {
|
||||
if (index != MainTab::Events) {
|
||||
editor->map_ruler->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
@ -2197,17 +2256,73 @@ void MainWindow::eventTabChanged(int index) {
|
|||
isProgrammaticEventTabChange = false;
|
||||
}
|
||||
|
||||
void MainWindow::on_actionDive_Emerge_Map_triggered() {
|
||||
setDivingMapsVisible(ui->actionDive_Emerge_Map->isChecked());
|
||||
}
|
||||
|
||||
void MainWindow::on_groupBox_DiveMapOpacity_toggled(bool on) {
|
||||
setDivingMapsVisible(on);
|
||||
}
|
||||
|
||||
void MainWindow::setDivingMapsVisible(bool visible) {
|
||||
// Qt doesn't change the style of disabled sliders, so we do it ourselves
|
||||
QString stylesheet = visible ? "" : "QSlider::groove:horizontal {border: 1px solid #999999; border-radius: 3px; height: 2px; background: #B1B1B1;}"
|
||||
"QSlider::handle:horizontal {border: 1px solid #444444; border-radius: 3px; width: 10px; height: 9px; margin: -5px -1px; background: #5C5C5C; }";
|
||||
ui->slider_DiveEmergeMapOpacity->setStyleSheet(stylesheet);
|
||||
ui->slider_DiveMapOpacity->setStyleSheet(stylesheet);
|
||||
ui->slider_EmergeMapOpacity->setStyleSheet(stylesheet);
|
||||
|
||||
// Sync UI toggle elements
|
||||
const QSignalBlocker blocker1(ui->groupBox_DiveMapOpacity);
|
||||
const QSignalBlocker blocker2(ui->actionDive_Emerge_Map);
|
||||
ui->groupBox_DiveMapOpacity->setChecked(visible);
|
||||
ui->actionDive_Emerge_Map->setChecked(visible);
|
||||
|
||||
porymapConfig.showDiveEmergeMaps = visible;
|
||||
|
||||
if (visible) {
|
||||
// We skip rendering diving maps if this setting is not enabled,
|
||||
// so when we enable it we need to make sure they've rendered.
|
||||
this->editor->renderDivingConnections();
|
||||
}
|
||||
this->editor->updateDivingMapsVisibility();
|
||||
}
|
||||
|
||||
// Normally a map only has either a Dive map connection or an Emerge map connection,
|
||||
// in which case we only show a single opacity slider to modify the one in use.
|
||||
// If a user has both connections we show two separate opacity sliders so they can
|
||||
// modify them independently.
|
||||
void MainWindow::on_slider_DiveEmergeMapOpacity_valueChanged(int value) {
|
||||
porymapConfig.diveEmergeMapOpacity = value;
|
||||
this->editor->updateDivingMapsVisibility();
|
||||
}
|
||||
|
||||
void MainWindow::on_slider_DiveMapOpacity_valueChanged(int value) {
|
||||
porymapConfig.diveMapOpacity = value;
|
||||
this->editor->updateDivingMapsVisibility();
|
||||
}
|
||||
|
||||
void MainWindow::on_slider_EmergeMapOpacity_valueChanged(int value) {
|
||||
porymapConfig.emergeMapOpacity = value;
|
||||
this->editor->updateDivingMapsVisibility();
|
||||
}
|
||||
|
||||
void MainWindow::on_horizontalSlider_CollisionTransparency_valueChanged(int value) {
|
||||
this->editor->collisionOpacity = static_cast<qreal>(value) / 100;
|
||||
porymapConfig.collisionOpacity = value;
|
||||
this->editor->collision_item->draw(true);
|
||||
}
|
||||
|
||||
void MainWindow::on_toolButton_deleteObject_clicked() {
|
||||
if (ui->mainTabBar->currentIndex() != 1) {
|
||||
// do not delete an event when not on event tab
|
||||
return;
|
||||
void MainWindow::onDeleteKeyPressed() {
|
||||
auto tab = ui->mainTabBar->currentIndex();
|
||||
if (tab == MainTab::Events) {
|
||||
on_toolButton_deleteObject_clicked();
|
||||
} else if (tab == MainTab::Connections) {
|
||||
if (editor) editor->removeSelectedConnection();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_toolButton_deleteObject_clicked() {
|
||||
if (editor && editor->selected_events) {
|
||||
if (editor->selected_events->length()) {
|
||||
DraggablePixmapItem *nextSelectedEvent = nullptr;
|
||||
|
@ -2254,15 +2369,14 @@ void MainWindow::on_toolButton_deleteObject_clicked() {
|
|||
|
||||
void MainWindow::on_toolButton_Paint_clicked()
|
||||
{
|
||||
if (ui->mainTabBar->currentIndex() == 0)
|
||||
if (ui->mainTabBar->currentIndex() == MainTab::Map)
|
||||
editor->map_edit_mode = "paint";
|
||||
else
|
||||
editor->obj_edit_mode = "paint";
|
||||
|
||||
editor->settings->mapCursor = QCursor(QPixmap(":/icons/pencil_cursor.ico"), 10, 10);
|
||||
|
||||
// do not stop single tile mode when editing collision
|
||||
if (ui->mapViewTab->currentIndex() != 1)
|
||||
if (ui->mapViewTab->currentIndex() != MapViewTab::Collision)
|
||||
editor->cursorMapTileRect->stopSingleTileMode();
|
||||
|
||||
ui->graphicsView_Map->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
|
@ -2276,7 +2390,7 @@ void MainWindow::on_toolButton_Paint_clicked()
|
|||
|
||||
void MainWindow::on_toolButton_Select_clicked()
|
||||
{
|
||||
if (ui->mainTabBar->currentIndex() == 0)
|
||||
if (ui->mainTabBar->currentIndex() == MainTab::Map)
|
||||
editor->map_edit_mode = "select";
|
||||
else
|
||||
editor->obj_edit_mode = "select";
|
||||
|
@ -2295,7 +2409,7 @@ void MainWindow::on_toolButton_Select_clicked()
|
|||
|
||||
void MainWindow::on_toolButton_Fill_clicked()
|
||||
{
|
||||
if (ui->mainTabBar->currentIndex() == 0)
|
||||
if (ui->mainTabBar->currentIndex() == MainTab::Map)
|
||||
editor->map_edit_mode = "fill";
|
||||
else
|
||||
editor->obj_edit_mode = "fill";
|
||||
|
@ -2314,7 +2428,7 @@ void MainWindow::on_toolButton_Fill_clicked()
|
|||
|
||||
void MainWindow::on_toolButton_Dropper_clicked()
|
||||
{
|
||||
if (ui->mainTabBar->currentIndex() == 0)
|
||||
if (ui->mainTabBar->currentIndex() == MainTab::Map)
|
||||
editor->map_edit_mode = "pick";
|
||||
else
|
||||
editor->obj_edit_mode = "pick";
|
||||
|
@ -2333,7 +2447,7 @@ void MainWindow::on_toolButton_Dropper_clicked()
|
|||
|
||||
void MainWindow::on_toolButton_Move_clicked()
|
||||
{
|
||||
if (ui->mainTabBar->currentIndex() == 0)
|
||||
if (ui->mainTabBar->currentIndex() == MainTab::Map)
|
||||
editor->map_edit_mode = "move";
|
||||
else
|
||||
editor->obj_edit_mode = "move";
|
||||
|
@ -2352,7 +2466,7 @@ void MainWindow::on_toolButton_Move_clicked()
|
|||
|
||||
void MainWindow::on_toolButton_Shift_clicked()
|
||||
{
|
||||
if (ui->mainTabBar->currentIndex() == 0)
|
||||
if (ui->mainTabBar->currentIndex() == MainTab::Map)
|
||||
editor->map_edit_mode = "shift";
|
||||
else
|
||||
editor->obj_edit_mode = "shift";
|
||||
|
@ -2371,7 +2485,7 @@ void MainWindow::on_toolButton_Shift_clicked()
|
|||
|
||||
void MainWindow::checkToolButtons() {
|
||||
QString edit_mode;
|
||||
if (ui->mainTabBar->currentIndex() == 0) {
|
||||
if (ui->mainTabBar->currentIndex() == MainTab::Map) {
|
||||
edit_mode = editor->map_edit_mode;
|
||||
} else {
|
||||
edit_mode = editor->obj_edit_mode;
|
||||
|
@ -2405,21 +2519,11 @@ void MainWindow::clickToolButtonFromEditMode(QString editMode) {
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::onLoadMapRequested(QString mapName, QString fromMapName) {
|
||||
if (!setMap(mapName, true)) {
|
||||
QMessageBox msgBox(this);
|
||||
QString errorMsg = QString("There was an error opening map %1. Please see %2 for full error details.\n\n%3")
|
||||
.arg(mapName)
|
||||
.arg(getLogPath())
|
||||
.arg(getMostRecentError());
|
||||
msgBox.critical(nullptr, "Error Opening Map", errorMsg);
|
||||
void MainWindow::onOpenConnectedMap(MapConnection *connection) {
|
||||
if (!connection)
|
||||
return;
|
||||
}
|
||||
editor->setSelectedConnectionFromMap(fromMapName);
|
||||
}
|
||||
|
||||
void MainWindow::onMapChanged(Map *) {
|
||||
updateMapList();
|
||||
if (userSetMap(connection->targetMapName(), true))
|
||||
editor->setSelectedConnection(connection->findMirror());
|
||||
}
|
||||
|
||||
void MainWindow::onMapNeedsRedrawing() {
|
||||
|
@ -2430,6 +2534,10 @@ void MainWindow::onMapCacheCleared() {
|
|||
editor->map = nullptr;
|
||||
}
|
||||
|
||||
void MainWindow::onMapLoaded(Map *map) {
|
||||
connect(map, &Map::modified, [this, map] { this->markMapEdited(map); });
|
||||
}
|
||||
|
||||
void MainWindow::onTilesetsSaved(QString primaryTilesetLabel, QString secondaryTilesetLabel) {
|
||||
// If saved tilesets are currently in-use, update them and redraw
|
||||
// Otherwise overwrite the cache for the saved tileset
|
||||
|
@ -2532,36 +2640,13 @@ void MainWindow::showExportMapImageWindow(ImageExporterMode mode) {
|
|||
openSubWindow(this->mapImageExporter);
|
||||
}
|
||||
|
||||
void MainWindow::on_comboBox_ConnectionDirection_currentTextChanged(const QString &direction)
|
||||
{
|
||||
editor->updateCurrentConnectionDirection(direction);
|
||||
markMapEdited();
|
||||
}
|
||||
void MainWindow::on_pushButton_AddConnection_clicked() {
|
||||
if (!this->editor || !this->editor->map || !this->editor->project)
|
||||
return;
|
||||
|
||||
void MainWindow::on_spinBox_ConnectionOffset_valueChanged(int offset)
|
||||
{
|
||||
editor->updateConnectionOffset(offset);
|
||||
markMapEdited();
|
||||
}
|
||||
|
||||
void MainWindow::on_comboBox_ConnectedMap_currentTextChanged(const QString &mapName)
|
||||
{
|
||||
if (mapName.isEmpty() || editor->project->mapNames.contains(mapName)) {
|
||||
editor->setConnectionMap(mapName);
|
||||
markMapEdited();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_pushButton_AddConnection_clicked()
|
||||
{
|
||||
editor->addNewConnection();
|
||||
markMapEdited();
|
||||
}
|
||||
|
||||
void MainWindow::on_pushButton_RemoveConnection_clicked()
|
||||
{
|
||||
editor->removeCurrentConnection();
|
||||
markMapEdited();
|
||||
auto dialog = new NewMapConnectionDialog(this, this->editor->map, this->editor->project->mapNames);
|
||||
connect(dialog, &NewMapConnectionDialog::accepted, this->editor, &Editor::addConnection);
|
||||
dialog->exec();
|
||||
}
|
||||
|
||||
void MainWindow::on_pushButton_NewWildMonGroup_clicked() {
|
||||
|
@ -2576,20 +2661,27 @@ void MainWindow::on_pushButton_ConfigureEncountersJSON_clicked() {
|
|||
editor->configureEncounterJSON(this);
|
||||
}
|
||||
|
||||
void MainWindow::on_comboBox_DiveMap_currentTextChanged(const QString &mapName)
|
||||
{
|
||||
if (mapName.isEmpty() || editor->project->mapNames.contains(mapName)) {
|
||||
editor->updateDiveMap(mapName);
|
||||
markMapEdited();
|
||||
}
|
||||
void MainWindow::on_button_OpenDiveMap_clicked() {
|
||||
const QString mapName = ui->comboBox_DiveMap->currentText();
|
||||
if (editor->project->mapNames.contains(mapName))
|
||||
userSetMap(mapName, true);
|
||||
}
|
||||
|
||||
void MainWindow::on_comboBox_EmergeMap_currentTextChanged(const QString &mapName)
|
||||
{
|
||||
if (mapName.isEmpty() || editor->project->mapNames.contains(mapName)) {
|
||||
void MainWindow::on_button_OpenEmergeMap_clicked() {
|
||||
const QString mapName = ui->comboBox_EmergeMap->currentText();
|
||||
if (editor->project->mapNames.contains(mapName))
|
||||
userSetMap(mapName, true);
|
||||
}
|
||||
|
||||
void MainWindow::on_comboBox_DiveMap_currentTextChanged(const QString &mapName) {
|
||||
// Include empty names as an update (user is deleting the connection)
|
||||
if (mapName.isEmpty() || editor->project->mapNames.contains(mapName))
|
||||
editor->updateDiveMap(mapName);
|
||||
}
|
||||
|
||||
void MainWindow::on_comboBox_EmergeMap_currentTextChanged(const QString &mapName) {
|
||||
if (mapName.isEmpty() || editor->project->mapNames.contains(mapName))
|
||||
editor->updateEmergeMap(mapName);
|
||||
markMapEdited();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_comboBox_PrimaryTileset_currentTextChanged(const QString &tilesetLabel)
|
||||
|
@ -2715,8 +2807,12 @@ void MainWindow::on_checkBox_smartPaths_stateChanged(int selected)
|
|||
|
||||
void MainWindow::on_checkBox_ToggleBorder_stateChanged(int selected)
|
||||
{
|
||||
bool visible = selected != 0;
|
||||
editor->toggleBorderVisibility(visible);
|
||||
editor->toggleBorderVisibility(selected != 0);
|
||||
}
|
||||
|
||||
void MainWindow::on_checkBox_MirrorConnections_stateChanged(int selected)
|
||||
{
|
||||
porymapConfig.mirrorConnectingMaps = (selected == Qt::Checked);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionTileset_Editor_triggered()
|
||||
|
@ -3030,7 +3126,16 @@ bool MainWindow::closeProject() {
|
|||
if (!isProjectOpen())
|
||||
return true;
|
||||
|
||||
if (projectHasUnsavedChanges || (editor->map && editor->map->hasUnsavedChanges())) {
|
||||
// Check loaded maps for unsaved changes
|
||||
bool unsavedChanges = false;
|
||||
for (auto map : editor->project->mapCache.values()) {
|
||||
if (map && map->hasUnsavedChanges()) {
|
||||
unsavedChanges = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (unsavedChanges) {
|
||||
QMessageBox::StandardButton result = QMessageBox::question(
|
||||
this, "porymap", "The project has been modified, save changes?",
|
||||
QMessageBox::No | QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes);
|
||||
|
|
|
@ -171,6 +171,9 @@ void Project::clearTilesetCache() {
|
|||
}
|
||||
|
||||
Map* Project::loadMap(QString map_name) {
|
||||
if (map_name == DYNAMIC_MAP_NAME)
|
||||
return nullptr;
|
||||
|
||||
Map *map;
|
||||
if (mapCache.contains(map_name)) {
|
||||
map = mapCache.value(map_name);
|
||||
|
@ -183,17 +186,16 @@ Map* Project::loadMap(QString map_name) {
|
|||
map->setName(map_name);
|
||||
}
|
||||
|
||||
if (!(loadMapData(map) && loadMapLayout(map)))
|
||||
if (!(loadMapData(map) && loadMapLayout(map))){
|
||||
delete map;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mapCache.insert(map_name, map);
|
||||
emit mapLoaded(map);
|
||||
return map;
|
||||
}
|
||||
|
||||
void Project::setNewMapConnections(Map *map) {
|
||||
map->connections.clear();
|
||||
}
|
||||
|
||||
const QSet<QString> defaultTopLevelMapFields = {
|
||||
"id",
|
||||
"name",
|
||||
|
@ -362,18 +364,17 @@ bool Project::loadMapData(Map* map) {
|
|||
}
|
||||
}
|
||||
|
||||
map->connections.clear();
|
||||
map->deleteConnections();
|
||||
QJsonArray connectionsArr = mapObj["connections"].toArray();
|
||||
if (!connectionsArr.isEmpty()) {
|
||||
for (int i = 0; i < connectionsArr.size(); i++) {
|
||||
QJsonObject connectionObj = connectionsArr[i].toObject();
|
||||
MapConnection *connection = new MapConnection;
|
||||
connection->direction = ParseUtil::jsonToQString(connectionObj["direction"]);
|
||||
connection->offset = ParseUtil::jsonToInt(connectionObj["offset"]);
|
||||
QString mapConstant = ParseUtil::jsonToQString(connectionObj["map"]);
|
||||
const QString direction = ParseUtil::jsonToQString(connectionObj["direction"]);
|
||||
int offset = ParseUtil::jsonToInt(connectionObj["offset"]);
|
||||
const QString mapConstant = ParseUtil::jsonToQString(connectionObj["map"]);
|
||||
if (mapConstantsToMapNames.contains(mapConstant)) {
|
||||
connection->map_name = mapConstantsToMapNames.value(mapConstant);
|
||||
map->connections.append(connection);
|
||||
// Successully read map connection
|
||||
map->loadConnection(new MapConnection(mapConstantsToMapNames.value(mapConstant), direction, offset));
|
||||
} else {
|
||||
logError(QString("Failed to find connected map for map constant '%1'").arg(mapConstant));
|
||||
}
|
||||
|
@ -1274,17 +1275,18 @@ void Project::saveMap(Map *map) {
|
|||
mapObj["battle_scene"] = map->battle_scene;
|
||||
|
||||
// Connections
|
||||
if (map->connections.length() > 0) {
|
||||
auto connections = map->getConnections();
|
||||
if (connections.length() > 0) {
|
||||
OrderedJson::array connectionsArr;
|
||||
for (MapConnection* connection : map->connections) {
|
||||
if (mapNamesToMapConstants.contains(connection->map_name)) {
|
||||
for (auto connection : connections) {
|
||||
if (mapNamesToMapConstants.contains(connection->targetMapName())) {
|
||||
OrderedJson::object connectionObj;
|
||||
connectionObj["map"] = this->mapNamesToMapConstants.value(connection->map_name);
|
||||
connectionObj["offset"] = connection->offset;
|
||||
connectionObj["direction"] = connection->direction;
|
||||
connectionObj["map"] = this->mapNamesToMapConstants.value(connection->targetMapName());
|
||||
connectionObj["offset"] = connection->offset();
|
||||
connectionObj["direction"] = connection->direction();
|
||||
connectionsArr.append(connectionObj);
|
||||
} else {
|
||||
logError(QString("Failed to write map connection. '%1' is not a valid map name").arg(connection->map_name));
|
||||
logError(QString("Failed to write map connection. '%1' is not a valid map name").arg(connection->targetMapName()));
|
||||
}
|
||||
}
|
||||
mapObj["connections"] = connectionsArr;
|
||||
|
@ -1816,18 +1818,22 @@ bool Project::readMapGroups() {
|
|||
}
|
||||
|
||||
Map* Project::addNewMapToGroup(QString mapName, int groupNum, Map *newMap, bool existingLayout, bool importedMap) {
|
||||
mapNames.append(mapName);
|
||||
mapGroups.insert(mapName, groupNum);
|
||||
groupedMapNames[groupNum].append(mapName);
|
||||
int mapNamePos = 0;
|
||||
for (int i = 0; i <= groupNum; i++)
|
||||
mapNamePos += this->groupedMapNames.value(i).length();
|
||||
|
||||
this->mapNames.insert(mapNamePos, mapName);
|
||||
this->mapGroups.insert(mapName, groupNum);
|
||||
this->groupedMapNames[groupNum].append(mapName);
|
||||
|
||||
newMap->isPersistedToFile = false;
|
||||
newMap->setName(mapName);
|
||||
|
||||
mapConstantsToMapNames.insert(newMap->constantName, newMap->name);
|
||||
mapNamesToMapConstants.insert(newMap->name, newMap->constantName);
|
||||
this->mapConstantsToMapNames.insert(newMap->constantName, newMap->name);
|
||||
this->mapNamesToMapConstants.insert(newMap->name, newMap->constantName);
|
||||
if (!existingLayout) {
|
||||
mapLayouts.insert(newMap->layoutId, newMap->layout);
|
||||
mapLayoutsTable.append(newMap->layoutId);
|
||||
this->mapLayouts.insert(newMap->layoutId, newMap->layout);
|
||||
this->mapLayoutsTable.append(newMap->layoutId);
|
||||
if (!importedMap) {
|
||||
setNewMapBlockdata(newMap);
|
||||
}
|
||||
|
@ -1838,7 +1844,6 @@ Map* Project::addNewMapToGroup(QString mapName, int groupNum, Map *newMap, bool
|
|||
|
||||
loadLayoutTilesets(newMap->layout);
|
||||
setNewMapEvents(newMap);
|
||||
setNewMapConnections(newMap);
|
||||
|
||||
return newMap;
|
||||
}
|
||||
|
|
|
@ -164,7 +164,10 @@ int ScriptUtility::getMapViewTab() {
|
|||
}
|
||||
|
||||
void ScriptUtility::setMapViewTab(int index) {
|
||||
if (this->getMainTab() != 0 || !window->ui->mapViewTab || index < 0 || index >= window->ui->mapViewTab->count())
|
||||
if (this->getMainTab() != MainTab::Map || !window->ui->mapViewTab || index < 0 || index >= window->ui->mapViewTab->count())
|
||||
return;
|
||||
// Can't select tab if it's disabled
|
||||
if (!window->ui->mapViewTab->isTabEnabled(index))
|
||||
return;
|
||||
window->on_mapViewTab_tabBarClicked(index);
|
||||
}
|
||||
|
@ -178,7 +181,7 @@ bool ScriptUtility::getGridVisibility() {
|
|||
}
|
||||
|
||||
void ScriptUtility::setBorderVisibility(bool visible) {
|
||||
window->editor->toggleBorderVisibility(visible, false);
|
||||
window->ui->checkBox_ToggleBorder->setChecked(visible);
|
||||
}
|
||||
|
||||
bool ScriptUtility::getBorderVisibility() {
|
||||
|
|
|
@ -1,30 +1,48 @@
|
|||
#include "connectionpixmapitem.h"
|
||||
#include "editcommands.h"
|
||||
#include "map.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
void ConnectionPixmapItem::render(qreal opacity) {
|
||||
QPixmap newPixmap = this->basePixmap.copy(0, 0, this->basePixmap.width(), this->basePixmap.height());
|
||||
if (opacity < 1) {
|
||||
QPainter painter(&newPixmap);
|
||||
int alpha = static_cast<int>(255 * (1 - opacity));
|
||||
painter.fillRect(0, 0, newPixmap.width(), newPixmap.height(), QColor(0, 0, 0, alpha));
|
||||
painter.end();
|
||||
ConnectionPixmapItem::ConnectionPixmapItem(MapConnection* connection, int x, int y)
|
||||
: QGraphicsPixmapItem(connection->getPixmap()),
|
||||
connection(connection)
|
||||
{
|
||||
this->setEditable(true);
|
||||
this->basePixmap = pixmap();
|
||||
this->setOrigin(x, y);
|
||||
}
|
||||
|
||||
ConnectionPixmapItem::ConnectionPixmapItem(MapConnection* connection, QPoint pos)
|
||||
: ConnectionPixmapItem(connection, pos.x(), pos.y())
|
||||
{}
|
||||
|
||||
// Render additional visual effects on top of the base map image.
|
||||
void ConnectionPixmapItem::render(bool ignoreCache) {
|
||||
if (ignoreCache)
|
||||
this->basePixmap = this->connection->getPixmap();
|
||||
|
||||
QPixmap pixmap = this->basePixmap.copy(0, 0, this->basePixmap.width(), this->basePixmap.height());
|
||||
this->setZValue(-1);
|
||||
|
||||
// When editing is inactive the current selection is ignored, all connections should appear normal.
|
||||
if (this->getEditable()) {
|
||||
if (this->selected) {
|
||||
// Draw highlight
|
||||
QPainter painter(&pixmap);
|
||||
painter.setPen(QColor(255, 0, 255));
|
||||
painter.drawRect(0, 0, pixmap.width() - 1, pixmap.height() - 1);
|
||||
painter.end();
|
||||
} else {
|
||||
// Darken the image
|
||||
this->setZValue(-2);
|
||||
QPainter painter(&pixmap);
|
||||
int alpha = static_cast<int>(255 * 0.25);
|
||||
painter.fillRect(0, 0, pixmap.width(), pixmap.height(), QColor(0, 0, 0, alpha));
|
||||
painter.end();
|
||||
}
|
||||
}
|
||||
this->setPixmap(newPixmap);
|
||||
}
|
||||
|
||||
int ConnectionPixmapItem::getMinOffset() {
|
||||
if (this->connection->direction == "up" || this->connection->direction == "down")
|
||||
return -(this->pixmap().width() / 16) - 6;
|
||||
else
|
||||
return -(this->pixmap().height() / 16) - 6;
|
||||
}
|
||||
|
||||
int ConnectionPixmapItem::getMaxOffset() {
|
||||
if (this->connection->direction == "up" || this->connection->direction == "down")
|
||||
return this->baseMapWidth + 6;
|
||||
else
|
||||
return this->baseMapHeight + 6;
|
||||
this->setPixmap(pixmap);
|
||||
}
|
||||
|
||||
QVariant ConnectionPixmapItem::itemChange(GraphicsItemChange change, const QVariant &value)
|
||||
|
@ -32,32 +50,23 @@ QVariant ConnectionPixmapItem::itemChange(GraphicsItemChange change, const QVari
|
|||
if (change == ItemPositionChange) {
|
||||
QPointF newPos = value.toPointF();
|
||||
|
||||
qreal x, y;
|
||||
int newOffset = this->initialOffset;
|
||||
if (this->connection->direction == "up" || this->connection->direction == "down") {
|
||||
x = round(newPos.x() / 16) * 16;
|
||||
newOffset += (x - initialX) / 16;
|
||||
newOffset = qMin(newOffset, this->getMaxOffset());
|
||||
newOffset = qMax(newOffset, this->getMinOffset());
|
||||
x = newOffset * 16;
|
||||
}
|
||||
else {
|
||||
x = this->initialX;
|
||||
qreal x = this->originX;
|
||||
qreal y = this->originY;
|
||||
int newOffset = this->connection->offset();
|
||||
|
||||
// Restrict movement to the metatile grid and perpendicular to the connection direction.
|
||||
if (MapConnection::isVertical(this->connection->direction())) {
|
||||
x = (round(newPos.x() / this->mWidth) * this->mWidth) - this->originX;
|
||||
newOffset = x / this->mWidth;
|
||||
} else if (MapConnection::isHorizontal(this->connection->direction())) {
|
||||
y = (round(newPos.y() / this->mHeight) * this->mHeight) - this->originY;
|
||||
newOffset = y / this->mHeight;
|
||||
}
|
||||
|
||||
if (this->connection->direction == "right" || this->connection->direction == "left") {
|
||||
y = round(newPos.y() / 16) * 16;
|
||||
newOffset += (y - this->initialY) / 16;
|
||||
newOffset = qMin(newOffset, this->getMaxOffset());
|
||||
newOffset = qMax(newOffset, this->getMinOffset());
|
||||
y = newOffset * 16;
|
||||
}
|
||||
else {
|
||||
y = this->initialY;
|
||||
}
|
||||
// This is convoluted because of how our edit history works; this would otherwise just be 'this->connection->setOffset(newOffset);'
|
||||
if (this->connection->parentMap() && newOffset != this->connection->offset())
|
||||
this->connection->parentMap()->editHistory.push(new MapConnectionMove(this->connection, newOffset, this->actionId));
|
||||
|
||||
this->connection->offset = newOffset;
|
||||
emit connectionMoved(this->connection);
|
||||
return QPointF(x, y);
|
||||
}
|
||||
else {
|
||||
|
@ -65,6 +74,32 @@ QVariant ConnectionPixmapItem::itemChange(GraphicsItemChange change, const QVari
|
|||
}
|
||||
}
|
||||
|
||||
// If connection->offset changed externally we call this to correct our position.
|
||||
void ConnectionPixmapItem::updatePos() {
|
||||
const QSignalBlocker blocker(this);
|
||||
|
||||
qreal x = this->originX;
|
||||
qreal y = this->originY;
|
||||
|
||||
if (MapConnection::isVertical(this->connection->direction())) {
|
||||
x += this->connection->offset() * this->mWidth;
|
||||
} else if (MapConnection::isHorizontal(this->connection->direction())) {
|
||||
y += this->connection->offset() * this->mHeight;
|
||||
}
|
||||
|
||||
this->setPos(x, y);
|
||||
}
|
||||
|
||||
// Set the pixmap's external origin point, i.e. the pixmap's position when connection->offset == 0
|
||||
void ConnectionPixmapItem::setOrigin(int x, int y) {
|
||||
this->originX = x;
|
||||
this->originY = y;
|
||||
updatePos();
|
||||
}
|
||||
void ConnectionPixmapItem::setOrigin(QPoint pos) {
|
||||
this->setOrigin(pos.x(), pos.y());
|
||||
}
|
||||
|
||||
void ConnectionPixmapItem::setEditable(bool editable) {
|
||||
setFlag(ItemIsMovable, editable);
|
||||
setFlag(ItemSendsGeometryChanges, editable);
|
||||
|
@ -74,28 +109,25 @@ bool ConnectionPixmapItem::getEditable() {
|
|||
return (this->flags() & ItemIsMovable) != 0;
|
||||
}
|
||||
|
||||
void ConnectionPixmapItem::updateHighlight(bool selected) {
|
||||
bool editable = this->getEditable();
|
||||
int zValue = (selected || !editable) ? -1 : -2;
|
||||
qreal opacity = (selected || !editable) ? 1 : 0.75;
|
||||
this->setZValue(zValue);
|
||||
this->render(opacity);
|
||||
if (editable && selected) {
|
||||
QPixmap pixmap = this->pixmap();
|
||||
QPainter painter(&pixmap);
|
||||
painter.setPen(QColor(255, 0, 255));
|
||||
painter.drawRect(0, 0, pixmap.width() - 1, pixmap.height() - 1);
|
||||
painter.end();
|
||||
this->setPixmap(pixmap);
|
||||
}
|
||||
void ConnectionPixmapItem::setSelected(bool selected) {
|
||||
if (this->selected == selected)
|
||||
return;
|
||||
this->selected = selected;
|
||||
this->render();
|
||||
emit selectionChanged(selected);
|
||||
}
|
||||
|
||||
void ConnectionPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *) {
|
||||
if (!this->getEditable())
|
||||
return;
|
||||
emit connectionItemSelected(this);
|
||||
this->setSelected(true);
|
||||
}
|
||||
|
||||
void ConnectionPixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
|
||||
this->actionId++; // Distinguish between move actions for the edit history
|
||||
QGraphicsPixmapItem::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
void ConnectionPixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) {
|
||||
emit connectionItemDoubleClicked(this);
|
||||
emit connectionItemDoubleClicked(this->connection);
|
||||
}
|
||||
|
|
103
src/ui/connectionslistitem.cpp
Normal file
103
src/ui/connectionslistitem.cpp
Normal file
|
@ -0,0 +1,103 @@
|
|||
#include "connectionslistitem.h"
|
||||
#include "ui_connectionslistitem.h"
|
||||
#include "editcommands.h"
|
||||
#include "map.h"
|
||||
|
||||
#include <QLineEdit>
|
||||
|
||||
ConnectionsListItem::ConnectionsListItem(QWidget *parent, MapConnection * connection, const QStringList &mapNames) :
|
||||
QFrame(parent),
|
||||
ui(new Ui::ConnectionsListItem)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
const QSignalBlocker blocker1(ui->comboBox_Direction);
|
||||
const QSignalBlocker blocker2(ui->comboBox_Map);
|
||||
const QSignalBlocker blocker3(ui->spinBox_Offset);
|
||||
|
||||
ui->comboBox_Direction->setEditable(false);
|
||||
ui->comboBox_Direction->setMinimumContentsLength(0);
|
||||
ui->comboBox_Direction->addItems(MapConnection::cardinalDirections);
|
||||
|
||||
ui->comboBox_Map->setMinimumContentsLength(6);
|
||||
ui->comboBox_Map->addItems(mapNames);
|
||||
ui->comboBox_Map->setFocusedScrollingEnabled(false); // Scrolling could cause rapid changes to many different maps
|
||||
ui->comboBox_Map->setInsertPolicy(QComboBox::NoInsert);
|
||||
|
||||
ui->spinBox_Offset->setMinimum(INT_MIN);
|
||||
ui->spinBox_Offset->setMaximum(INT_MAX);
|
||||
|
||||
// Invalid map names are not considered a change. If editing finishes with an invalid name, restore the previous name.
|
||||
connect(ui->comboBox_Map->lineEdit(), &QLineEdit::editingFinished, [this] {
|
||||
const QSignalBlocker blocker(ui->comboBox_Map);
|
||||
if (ui->comboBox_Map->findText(ui->comboBox_Map->currentText()) < 0)
|
||||
ui->comboBox_Map->setTextItem(this->connection->targetMapName());
|
||||
});
|
||||
|
||||
// Distinguish between move actions for the edit history
|
||||
connect(ui->spinBox_Offset, &QSpinBox::editingFinished, [this] { this->actionId++; });
|
||||
|
||||
this->connection = connection;
|
||||
this->map = connection->parentMap();
|
||||
this->updateUI();
|
||||
}
|
||||
|
||||
ConnectionsListItem::~ConnectionsListItem()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ConnectionsListItem::updateUI() {
|
||||
if (!this->connection)
|
||||
return;
|
||||
|
||||
const QSignalBlocker blocker1(ui->comboBox_Direction);
|
||||
const QSignalBlocker blocker2(ui->comboBox_Map);
|
||||
const QSignalBlocker blocker3(ui->spinBox_Offset);
|
||||
|
||||
ui->comboBox_Direction->setTextItem(this->connection->direction());
|
||||
ui->comboBox_Map->setTextItem(this->connection->targetMapName());
|
||||
ui->spinBox_Offset->setValue(this->connection->offset());
|
||||
}
|
||||
|
||||
void ConnectionsListItem::setSelected(bool selected) {
|
||||
if (selected == this->isSelected)
|
||||
return;
|
||||
this->isSelected = selected;
|
||||
|
||||
this->setStyleSheet(selected ? ".ConnectionsListItem { border: 1px solid rgb(255, 0, 255); }"
|
||||
: ".ConnectionsListItem { border-width: 1px; }");
|
||||
if (selected)
|
||||
emit this->selected();
|
||||
}
|
||||
|
||||
void ConnectionsListItem::mousePressEvent(QMouseEvent *) {
|
||||
this->setSelected(true);
|
||||
}
|
||||
|
||||
void ConnectionsListItem::on_comboBox_Direction_currentTextChanged(QString direction) {
|
||||
this->setSelected(true);
|
||||
if (this->map)
|
||||
this->map->editHistory.push(new MapConnectionChangeDirection(this->connection, direction));
|
||||
}
|
||||
|
||||
void ConnectionsListItem::on_comboBox_Map_currentTextChanged(QString mapName) {
|
||||
this->setSelected(true);
|
||||
if (this->map && ui->comboBox_Map->findText(mapName) >= 0)
|
||||
this->map->editHistory.push(new MapConnectionChangeMap(this->connection, mapName));
|
||||
}
|
||||
|
||||
void ConnectionsListItem::on_spinBox_Offset_valueChanged(int offset) {
|
||||
this->setSelected(true);
|
||||
if (this->map)
|
||||
this->map->editHistory.push(new MapConnectionMove(this->connection, offset, this->actionId));
|
||||
}
|
||||
|
||||
void ConnectionsListItem::on_button_Delete_clicked() {
|
||||
if (this->map)
|
||||
this->map->editHistory.push(new MapConnectionRemove(this->map, this->connection));
|
||||
}
|
||||
|
||||
void ConnectionsListItem::on_button_OpenMap_clicked() {
|
||||
emit openMapClicked(this->connection);
|
||||
}
|
46
src/ui/divingmappixmapitem.cpp
Normal file
46
src/ui/divingmappixmapitem.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
#include "divingmappixmapitem.h"
|
||||
#include "config.h"
|
||||
|
||||
DivingMapPixmapItem::DivingMapPixmapItem(MapConnection *connection, QComboBox *combo)
|
||||
: QGraphicsPixmapItem(getBasePixmap(connection))
|
||||
{
|
||||
m_connection = connection;
|
||||
m_combo = combo;
|
||||
|
||||
setComboText(connection->targetMapName());
|
||||
|
||||
// Update display if the connected map is swapped.
|
||||
connect(m_connection, &MapConnection::targetMapNameChanged, this, &DivingMapPixmapItem::onTargetMapChanged);
|
||||
}
|
||||
|
||||
DivingMapPixmapItem::~DivingMapPixmapItem() {
|
||||
// Clear map name from combo box
|
||||
setComboText("");
|
||||
}
|
||||
|
||||
QPixmap DivingMapPixmapItem::getBasePixmap(MapConnection* connection) {
|
||||
if (!connection)
|
||||
return QPixmap();
|
||||
if (!porymapConfig.showDiveEmergeMaps)
|
||||
return QPixmap(); // Save some rendering time if it won't be displayed
|
||||
if (connection->targetMapName() == connection->parentMapName())
|
||||
return QPixmap(); // If the map is connected to itself then rendering is pointless.
|
||||
return connection->getPixmap();
|
||||
}
|
||||
|
||||
void DivingMapPixmapItem::updatePixmap() {
|
||||
setPixmap(getBasePixmap(m_connection));
|
||||
}
|
||||
|
||||
void DivingMapPixmapItem::onTargetMapChanged() {
|
||||
updatePixmap();
|
||||
setComboText(m_connection->targetMapName());
|
||||
}
|
||||
|
||||
void DivingMapPixmapItem::setComboText(const QString &text) {
|
||||
if (!m_combo)
|
||||
return;
|
||||
|
||||
const QSignalBlocker blocker(m_combo);
|
||||
m_combo->setCurrentText(text);
|
||||
}
|
|
@ -33,7 +33,7 @@ MapImageExporter::MapImageExporter(QWidget *parent_, Editor *editor_, ImageExpor
|
|||
this->editor = editor_;
|
||||
this->mode = mode;
|
||||
this->setWindowTitle(getTitle(this->mode));
|
||||
this->ui->groupBox_Connections->setVisible(this->mode == ImageExporterMode::Normal);
|
||||
this->ui->groupBox_Connections->setVisible(this->mode != ImageExporterMode::Stitch);
|
||||
this->ui->groupBox_Timelapse->setVisible(this->mode == ImageExporterMode::Timelapse);
|
||||
|
||||
this->ui->comboBox_MapSelection->addItems(editor->project->mapNames);
|
||||
|
@ -144,7 +144,7 @@ void MapImageExporter::saveImage() {
|
|||
this->map->editHistory.redo();
|
||||
}
|
||||
progress.setValue(progress.maximum() - i);
|
||||
QPixmap pixmap = this->getFormattedMapPixmap(this->map, !this->showBorder);
|
||||
QPixmap pixmap = this->getFormattedMapPixmap(this->map);
|
||||
if (pixmap.width() < maxWidth || pixmap.height() < maxHeight) {
|
||||
QPixmap pixmap2 = QPixmap(maxWidth, maxHeight);
|
||||
QPainter painter(&pixmap2);
|
||||
|
@ -167,7 +167,7 @@ void MapImageExporter::saveImage() {
|
|||
}
|
||||
}
|
||||
// The latest map state is the last animated frame.
|
||||
QPixmap pixmap = this->getFormattedMapPixmap(this->map, !this->showBorder);
|
||||
QPixmap pixmap = this->getFormattedMapPixmap(this->map);
|
||||
timelapseImg.addFrame(pixmap.toImage());
|
||||
timelapseImg.save(filepath);
|
||||
progress.close();
|
||||
|
@ -178,6 +178,9 @@ void MapImageExporter::saveImage() {
|
|||
}
|
||||
|
||||
bool MapImageExporter::historyItemAppliesToFrame(const QUndoCommand *command) {
|
||||
if (command->isObsolete())
|
||||
return false;
|
||||
|
||||
switch (command->id() & 0xFF) {
|
||||
case CommandId::ID_PaintMetatile:
|
||||
case CommandId::ID_BucketFillMetatile:
|
||||
|
@ -192,6 +195,12 @@ bool MapImageExporter::historyItemAppliesToFrame(const QUndoCommand *command) {
|
|||
return this->showCollision;
|
||||
case CommandId::ID_PaintBorder:
|
||||
return this->showBorder;
|
||||
case CommandId::ID_MapConnectionMove:
|
||||
case CommandId::ID_MapConnectionChangeDirection:
|
||||
case CommandId::ID_MapConnectionChangeMap:
|
||||
case CommandId::ID_MapConnectionAdd:
|
||||
case CommandId::ID_MapConnectionRemove:
|
||||
return this->showUpConnections || this->showDownConnections || this->showLeftConnections || this->showRightConnections;
|
||||
case CommandId::ID_EventMove:
|
||||
case CommandId::ID_EventShift:
|
||||
case CommandId::ID_EventCreate:
|
||||
|
@ -238,25 +247,29 @@ QPixmap MapImageExporter::getStitchedImage(QProgressDialog *progress, bool inclu
|
|||
visited.insert(cur.map->name);
|
||||
stitchedMaps.append(cur);
|
||||
|
||||
for (MapConnection *connection : cur.map->connections) {
|
||||
if (connection->direction == "dive" || connection->direction == "emerge")
|
||||
continue;
|
||||
for (MapConnection *connection : cur.map->getConnections()) {
|
||||
const QString direction = connection->direction();
|
||||
int x = cur.x;
|
||||
int y = cur.y;
|
||||
int offset = connection->offset;
|
||||
Map *connectionMap = this->editor->project->loadMap(connection->map_name);
|
||||
if (connection->direction == "up") {
|
||||
int offset = connection->offset();
|
||||
Map *connectionMap = connection->targetMap();
|
||||
if (!connectionMap)
|
||||
continue;
|
||||
if (direction == "up") {
|
||||
x += offset;
|
||||
y -= connectionMap->getHeight();
|
||||
} else if (connection->direction == "down") {
|
||||
} else if (direction == "down") {
|
||||
x += offset;
|
||||
y += cur.map->getHeight();
|
||||
} else if (connection->direction == "left") {
|
||||
} else if (direction == "left") {
|
||||
x -= connectionMap->getWidth();
|
||||
y += offset;
|
||||
} else if (connection->direction == "right") {
|
||||
} else if (direction == "right") {
|
||||
x += cur.map->getWidth();
|
||||
y += offset;
|
||||
} else {
|
||||
// Ignore Dive/Emerge connections and unrecognized directions
|
||||
continue;
|
||||
}
|
||||
unvisited.append(StitchedMap{x, y, connectionMap});
|
||||
}
|
||||
|
@ -310,7 +323,7 @@ QPixmap MapImageExporter::getStitchedImage(QProgressDialog *progress, bool inclu
|
|||
pixelX -= STITCH_MODE_BORDER_DISTANCE * 16;
|
||||
pixelY -= STITCH_MODE_BORDER_DISTANCE * 16;
|
||||
}
|
||||
QPixmap pixmap = this->getFormattedMapPixmap(map.map, false);
|
||||
QPixmap pixmap = this->getFormattedMapPixmap(map.map);
|
||||
painter.drawPixmap(pixelX, pixelY, pixmap);
|
||||
}
|
||||
|
||||
|
@ -345,7 +358,7 @@ void MapImageExporter::updatePreview() {
|
|||
scene = nullptr;
|
||||
}
|
||||
|
||||
preview = getFormattedMapPixmap(this->map, false);
|
||||
preview = getFormattedMapPixmap(this->map);
|
||||
scene = new QGraphicsScene;
|
||||
scene->addPixmap(preview);
|
||||
this->scene->setSceneRect(this->scene->itemsBoundingRect());
|
||||
|
@ -373,8 +386,7 @@ QPixmap MapImageExporter::getFormattedMapPixmap(Map *map, bool ignoreBorder) {
|
|||
// draw map border
|
||||
// note: this will break when allowing map to be selected from drop down maybe
|
||||
int borderHeight = 0, borderWidth = 0;
|
||||
bool forceDrawBorder = showUpConnections || showDownConnections || showLeftConnections || showRightConnections;
|
||||
if (!ignoreBorder && (showBorder || forceDrawBorder)) {
|
||||
if (!ignoreBorder && this->showBorder) {
|
||||
int borderDistance = this->mode ? STITCH_MODE_BORDER_DISTANCE : BORDER_DISTANCE;
|
||||
map->renderBorder();
|
||||
int borderHorzDist = editor->getBorderDrawDistance(map->getBorderWidth());
|
||||
|
@ -393,17 +405,17 @@ QPixmap MapImageExporter::getFormattedMapPixmap(Map *map, bool ignoreBorder) {
|
|||
pixmap = newPixmap;
|
||||
}
|
||||
|
||||
if (!this->mode) {
|
||||
if (!ignoreBorder && (this->showUpConnections || this->showDownConnections || this->showLeftConnections || this->showRightConnections)) {
|
||||
// if showing connections, draw on outside of image
|
||||
QPainter connectionPainter(&pixmap);
|
||||
for (auto connectionItem : editor->connection_items) {
|
||||
QString direction = connectionItem->connection->direction;
|
||||
const QString direction = connectionItem->connection->direction();
|
||||
if ((showUpConnections && direction == "up")
|
||||
|| (showDownConnections && direction == "down")
|
||||
|| (showLeftConnections && direction == "left")
|
||||
|| (showRightConnections && direction == "right"))
|
||||
connectionPainter.drawImage(connectionItem->initialX + borderWidth, connectionItem->initialY + borderHeight,
|
||||
connectionItem->basePixmap.toImage());
|
||||
connectionPainter.drawImage(connectionItem->x() + borderWidth, connectionItem->y() + borderHeight,
|
||||
connectionItem->connection->getPixmap().toImage());
|
||||
}
|
||||
connectionPainter.end();
|
||||
}
|
||||
|
@ -412,7 +424,7 @@ QPixmap MapImageExporter::getFormattedMapPixmap(Map *map, bool ignoreBorder) {
|
|||
QPainter eventPainter(&pixmap);
|
||||
QList<Event *> events = map->getAllEvents();
|
||||
int pixelOffset = 0;
|
||||
if (!ignoreBorder && showBorder) {
|
||||
if (!ignoreBorder && this->showBorder) {
|
||||
pixelOffset = this->mode == ImageExporterMode::Normal ? BORDER_DISTANCE * 16 : STITCH_MODE_BORDER_DISTANCE * 16;
|
||||
}
|
||||
for (Event *event : events) {
|
||||
|
@ -450,6 +462,18 @@ QPixmap MapImageExporter::getFormattedMapPixmap(Map *map, bool ignoreBorder) {
|
|||
return pixmap;
|
||||
}
|
||||
|
||||
void MapImageExporter::updateShowBorderState() {
|
||||
// If any of the Connections settings are enabled then this setting is locked (it's implicitly enabled)
|
||||
const QSignalBlocker blocker(ui->checkBox_Border);
|
||||
if (showUpConnections || showDownConnections || showLeftConnections || showRightConnections) {
|
||||
ui->checkBox_Border->setChecked(true);
|
||||
ui->checkBox_Border->setDisabled(true);
|
||||
showBorder = true;
|
||||
} else {
|
||||
ui->checkBox_Border->setDisabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void MapImageExporter::on_checkBox_Elevation_stateChanged(int state) {
|
||||
showCollision = (state == Qt::Checked);
|
||||
updatePreview();
|
||||
|
@ -492,21 +516,25 @@ void MapImageExporter::on_checkBox_HealSpots_stateChanged(int state) {
|
|||
|
||||
void MapImageExporter::on_checkBox_ConnectionUp_stateChanged(int state) {
|
||||
showUpConnections = (state == Qt::Checked);
|
||||
updateShowBorderState();
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
void MapImageExporter::on_checkBox_ConnectionDown_stateChanged(int state) {
|
||||
showDownConnections = (state == Qt::Checked);
|
||||
updateShowBorderState();
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
void MapImageExporter::on_checkBox_ConnectionLeft_stateChanged(int state) {
|
||||
showLeftConnections = (state == Qt::Checked);
|
||||
updateShowBorderState();
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
void MapImageExporter::on_checkBox_ConnectionRight_stateChanged(int state) {
|
||||
showRightConnections = (state == Qt::Checked);
|
||||
updateShowBorderState();
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
|
|
72
src/ui/newmapconnectiondialog.cpp
Normal file
72
src/ui/newmapconnectiondialog.cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
#include "newmapconnectiondialog.h"
|
||||
#include "ui_newmapconnectiondialog.h"
|
||||
|
||||
NewMapConnectionDialog::NewMapConnectionDialog(QWidget *parent, Map* map, const QStringList &mapNames) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::NewMapConnectionDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
ui->comboBox_Direction->setEditable(false);
|
||||
ui->comboBox_Direction->addItems(MapConnection::cardinalDirections);
|
||||
|
||||
ui->comboBox_Map->addItems(mapNames);
|
||||
ui->comboBox_Map->setInsertPolicy(QComboBox::NoInsert);
|
||||
|
||||
// Choose default direction
|
||||
QMap<QString, int> directionCounts;
|
||||
for (auto connection : map->getConnections()) {
|
||||
directionCounts[connection->direction()]++;
|
||||
}
|
||||
QString defaultDirection;
|
||||
int minCount = INT_MAX;
|
||||
for (auto direction : MapConnection::cardinalDirections) {
|
||||
if (directionCounts[direction] < minCount) {
|
||||
defaultDirection = direction;
|
||||
minCount = directionCounts[direction];
|
||||
}
|
||||
}
|
||||
ui->comboBox_Direction->setTextItem(defaultDirection);
|
||||
|
||||
// Choose default map
|
||||
QString defaultMapName;
|
||||
if (mapNames.isEmpty()) {
|
||||
defaultMapName = QString();
|
||||
} else if (mapNames.first() == map->name && mapNames.length() > 1) {
|
||||
// Prefer not to connect the map to itself
|
||||
defaultMapName = mapNames.at(1);
|
||||
} else {
|
||||
defaultMapName = mapNames.first();
|
||||
}
|
||||
ui->comboBox_Map->setTextItem(defaultMapName);
|
||||
|
||||
connect(ui->comboBox_Map, &QComboBox::currentTextChanged, [this] {
|
||||
if (ui->label_Warning->isVisible() && mapNameIsValid())
|
||||
setWarningVisible(false);
|
||||
});
|
||||
setWarningVisible(false);
|
||||
}
|
||||
|
||||
NewMapConnectionDialog::~NewMapConnectionDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
bool NewMapConnectionDialog::mapNameIsValid() {
|
||||
return ui->comboBox_Map->findText(ui->comboBox_Map->currentText()) >= 0;
|
||||
}
|
||||
|
||||
void NewMapConnectionDialog::setWarningVisible(bool visible) {
|
||||
ui->label_Warning->setVisible(visible);
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
void NewMapConnectionDialog::accept() {
|
||||
if (!mapNameIsValid()) {
|
||||
setWarningVisible(true);
|
||||
return;
|
||||
}
|
||||
emit accepted(new MapConnection(ui->comboBox_Map->currentText(), ui->comboBox_Direction->currentText()));
|
||||
QDialog::accept();
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
#include "noscrollcombobox.h"
|
||||
|
||||
#include <QCompleter>
|
||||
#include <QLineEdit>
|
||||
|
||||
NoScrollComboBox::NoScrollComboBox(QWidget *parent)
|
||||
: QComboBox(parent)
|
||||
|
@ -36,11 +37,17 @@ void NoScrollComboBox::setLineEdit(QLineEdit *edit) {
|
|||
|
||||
void NoScrollComboBox::wheelEvent(QWheelEvent *event)
|
||||
{
|
||||
// Only allow scrolling to modify contents when it explicitly has focus.
|
||||
if (hasFocus())
|
||||
// By default NoScrollComboBoxes will allow scrolling to modify its contents only when it explicitly has focus.
|
||||
// If focusedScrollingEnabled is false it won't allow scrolling even with focus.
|
||||
if (this->focusedScrollingEnabled && hasFocus())
|
||||
QComboBox::wheelEvent(event);
|
||||
}
|
||||
|
||||
void NoScrollComboBox::setFocusedScrollingEnabled(bool enabled)
|
||||
{
|
||||
this->focusedScrollingEnabled = enabled;
|
||||
}
|
||||
|
||||
void NoScrollComboBox::setItem(int index, const QString &text)
|
||||
{
|
||||
if (index >= 0) {
|
||||
|
@ -73,3 +80,8 @@ void NoScrollComboBox::setHexItem(uint32_t value)
|
|||
{
|
||||
this->setItem(this->findData(value), "0x" + QString::number(value, 16).toUpper());
|
||||
}
|
||||
|
||||
void NoScrollComboBox::setClearButtonEnabled(bool enabled) {
|
||||
if (this->lineEdit())
|
||||
this->lineEdit()->setClearButtonEnabled(enabled);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue