diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui index 057df05d..7c2d45ba 100644 --- a/forms/mainwindow.ui +++ b/forms/mainwindow.ui @@ -2882,6 +2882,7 @@ + @@ -3236,6 +3237,17 @@ Show Dive/Emerge Map + + + true + + + false + + + Show Events in Map View + + true diff --git a/include/config.h b/include/config.h index 6eb84470..7f263da0 100644 --- a/include/config.h +++ b/include/config.h @@ -81,6 +81,7 @@ public: this->projectSettingsTab = 0; this->warpBehaviorWarningDisabled = false; this->eventDeleteWarningDisabled = false; + this->eventOverlayEnabled = false; this->checkForUpdates = true; this->lastUpdateCheckTime = QDateTime(); this->lastUpdateCheckVersion = porymapVersion; @@ -136,6 +137,7 @@ public: int projectSettingsTab; bool warpBehaviorWarningDisabled; bool eventDeleteWarningDisabled; + bool eventOverlayEnabled; bool checkForUpdates; QDateTime lastUpdateCheckTime; QVersionNumber lastUpdateCheckVersion; diff --git a/include/editor.h b/include/editor.h index 0c11a1e8..689d2f4f 100644 --- a/include/editor.h +++ b/include/editor.h @@ -119,6 +119,7 @@ public: void redrawEvents(const QList &events); void redrawEventPixmapItem(DraggablePixmapItem *item); QList getEventPixmapItems(); + qreal getEventOpacity(const Event *event) const; void updateCursorRectPos(int x, int y); void setCursorRectVisible(bool visible); @@ -161,21 +162,11 @@ public: EditAction eventEditAction = EditAction::Select; enum class EditMode { None, Disabled, Metatiles, Collision, Header, Events, Connections, Encounters }; - EditMode editMode = EditMode::None; - void setEditMode(EditMode mode) { this->editMode = mode; } - EditMode getEditMode() { return this->editMode; } + void setEditMode(EditMode editMode); + EditMode getEditMode() const { return this->editMode; } bool getEditingLayout(); - void setEditorView(); - - void setEditingMetatiles(); - void setEditingCollision(); - void setEditingHeader(); - void setEditingEvents(); - void setEditingConnections(); - void setEditingEncounters(); - void setMapEditingButtonsEnabled(bool enabled); int scaleIndex = 2; @@ -211,6 +202,8 @@ private: const QImage collisionPlaceholder = QImage(":/images/collisions_unknown.png"); QPixmap collisionSheetPixmap; + EditMode editMode = EditMode::None; + void clearMap(); void clearMetatileSelector(); void clearMovementPermissionSelector(); diff --git a/include/mainwindow.h b/include/mainwindow.h index 2d065b37..805899a1 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -261,6 +261,7 @@ private slots: void on_checkBox_MirrorConnections_stateChanged(int selected); void on_actionDive_Emerge_Map_triggered(); + void on_actionShow_Events_In_Map_View_triggered(); void on_groupBox_DiveMapOpacity_toggled(bool on); void on_slider_DiveEmergeMapOpacity_valueChanged(int value); void on_slider_DiveMapOpacity_valueChanged(int value); diff --git a/src/config.cpp b/src/config.cpp index a61393ab..b22972a4 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -394,6 +394,8 @@ void PorymapConfig::parseConfigKeyValue(QString key, QString value) { this->warpBehaviorWarningDisabled = getConfigBool(key, value); } else if (key == "event_delete_warning_disabled") { this->eventDeleteWarningDisabled = getConfigBool(key, value); + } else if (key == "event_overlay_enabled") { + this->eventOverlayEnabled = getConfigBool(key, value); } else if (key == "check_for_updates") { this->checkForUpdates = getConfigBool(key, value); } else if (key == "last_update_check_time") { @@ -479,6 +481,7 @@ QMap PorymapConfig::getKeyValueMap() { map.insert("project_settings_tab", QString::number(this->projectSettingsTab)); map.insert("warp_behavior_warning_disabled", QString::number(this->warpBehaviorWarningDisabled)); map.insert("event_delete_warning_disabled", QString::number(this->eventDeleteWarningDisabled)); + map.insert("event_overlay_enabled", QString::number(this->eventOverlayEnabled)); map.insert("check_for_updates", QString::number(this->checkForUpdates)); map.insert("last_update_check_time", this->lastUpdateCheckTime.toUTC().toString()); map.insert("last_update_check_version", this->lastUpdateCheckVersion.toString()); diff --git a/src/editor.cpp b/src/editor.cpp index a160f462..6a2e0c20 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -113,8 +113,12 @@ bool Editor::getEditingLayout() { return this->editMode == EditMode::Metatiles || this->editMode == EditMode::Collision; } -void Editor::setEditorView() { - // based on editMode +void Editor::setEditMode(EditMode editMode) { + // At the moment we can't early return if editMode == this->editMode, because this function also takes care of refreshing the map view. + // The main window relies on this when switching projects (the edit mode will remain the same, but it needs a refresh). + auto oldEditMode = this->editMode; + this->editMode = editMode; + if (!map_item || !collision_item) return; if (!this->layout) return; @@ -132,70 +136,34 @@ void Editor::setEditorView() { break; default: current_view = nullptr; - return; + break; } map_item->setEditsEnabled(this->editMode != EditMode::Connections); map_item->draw(); collision_item->draw(); - current_view->setVisible(true); + if (current_view) current_view->setVisible(true); updateBorderVisibility(); QUndoStack *editStack = this->map ? this->map->editHistory() : nullptr; - bool usesCursor = false; - if (this->editMode == EditMode::Metatiles || this->editMode == EditMode::Collision) { - if (this->layout) editStack = &this->layout->editHistory; - usesCursor = true; + bool editingLayout = getEditingLayout(); + if (editingLayout && this->layout) { + editStack = &this->layout->editHistory; } - this->cursorMapTileRect->setSingleTileMode(); - this->cursorMapTileRect->setActive(usesCursor); + this->cursorMapTileRect->setActive(editingLayout); this->editGroup.setActiveStack(editStack); + setMapEditingButtonsEnabled(editingLayout); - - if (this->events_group) { - this->events_group->setVisible(this->editMode == EditMode::Events); + if (this->editMode == EditMode::Events || oldEditMode == EditMode::Events) { + // When switching to or from the Events tab the opacity of the events changes. Redraw the events to reflect that change. + redrawAllEvents(); + } + if (this->editMode == EditMode::Events){ + updateWarpEventWarnings(); } - setMapEditingButtonsEnabled(this->editMode != EditMode::Events); -} - -void Editor::setEditingMetatiles() { - this->editMode = EditMode::Metatiles; - - setEditorView(); -} - -void Editor::setEditingCollision() { - this->editMode = EditMode::Collision; - - setEditorView(); -} - -void Editor::setEditingHeader() { - this->editMode = EditMode::Header; - - setEditorView(); -} - -void Editor::setEditingEvents() { - this->editMode = EditMode::Events; - - setEditorView(); - updateWarpEventWarnings(); -} - -void Editor::setEditingConnections() { - this->editMode = EditMode::Connections; - - setEditorView(); -} - -void Editor::setEditingEncounters() { - this->editMode = EditMode::Encounters; - - setEditorView(); } void Editor::setMapEditingButtonsEnabled(bool enabled) { @@ -1486,10 +1454,6 @@ bool Editor::displayMap() { displayMapEvents(); displayMapConnections(); maskNonVisibleConnectionTiles(); - - if (events_group) { - events_group->setVisible(false); - } return true; } @@ -2003,20 +1967,40 @@ QList Editor::getEventPixmapItems() { return list; } +qreal Editor::getEventOpacity(const Event *event) const { + // There are 4 possible opacities for an event's sprite: + // - Off the Events tab, and the event overlay is off (0.0) + // - Off the Events tab, and the event overlay is on (0.5) + // - On the Events tab, and the event has a default sprite (0.7) + // - On the Events tab, and the event has a custom sprite (1.0) + if (this->editMode != EditMode::Events) + return porymapConfig.eventOverlayEnabled ? 0.5 : 0.0; + return event->getUsingSprite() ? 1.0 : 0.7; +} + void Editor::redrawEventPixmapItem(DraggablePixmapItem *item) { if (item && item->event && !item->event->getPixmap().isNull()) { - qreal opacity = item->event->getUsingSprite() ? 1.0 : 0.7; - item->setOpacity(opacity); + item->setOpacity(getEventOpacity(item->event)); project->setEventPixmap(item->event, true); item->setPixmap(item->event->getPixmap()); item->setShapeMode(porymapConfig.eventSelectionShapeMode); - if (selected_events && selected_events->contains(item)) { - QImage image = item->pixmap().toImage(); - QPainter painter(&image); - painter.setPen(QColor(255, 0, 255)); - painter.drawRect(0, 0, image.width() - 1, image.height() - 1); - painter.end(); - item->setPixmap(QPixmap::fromImage(image)); + + if (this->editMode == EditMode::Events) { + if (selected_events && selected_events->contains(item)) { + // Draw the selection rectangle + QImage image = item->pixmap().toImage(); + QPainter painter(&image); + painter.setPen(QColor(255, 0, 255)); + painter.drawRect(0, 0, image.width() - 1, image.height() - 1); + painter.end(); + item->setPixmap(QPixmap::fromImage(image)); + } + item->setAcceptedMouseButtons(Qt::AllButtons); + } else { + // Can't interact with event pixmaps outside of event editing mode. + // We could do setEnabled(false), but rather than ignoring the mouse events this + // would reject them, which would prevent painting on the map behind the events. + item->setAcceptedMouseButtons(Qt::NoButton); } item->updatePosition(); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 3f359d0e..a38b3bd0 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -525,17 +525,11 @@ void MainWindow::loadUserSettings() { ui->actionCursor_Tile_Outline->setChecked(porymapConfig.showCursorTile); this->editor->settings->cursorTileRectEnabled = porymapConfig.showCursorTile; - // Border - ui->checkBox_ToggleBorder->setChecked(porymapConfig.showBorder); - // Grid const QSignalBlocker b_Grid(ui->checkBox_ToggleGrid); ui->actionShow_Grid->setChecked(porymapConfig.showGrid); ui->checkBox_ToggleGrid->setChecked(porymapConfig.showGrid); - // Mirror connections - ui->checkBox_MirrorConnections->setChecked(porymapConfig.mirrorConnectingMaps); - // Collision opacity/transparency const QSignalBlocker b_CollisionTransparency(ui->horizontalSlider_CollisionTransparency); this->editor->collisionOpacity = static_cast(porymapConfig.collisionOpacity) / 100; @@ -555,6 +549,10 @@ void MainWindow::loadUserSettings() { ui->horizontalSlider_MetatileZoom->setValue(porymapConfig.metatilesZoom); ui->horizontalSlider_CollisionZoom->setValue(porymapConfig.collisionZoom); + ui->checkBox_MirrorConnections->setChecked(porymapConfig.mirrorConnectingMaps); + ui->checkBox_ToggleBorder->setChecked(porymapConfig.showBorder); + ui->actionShow_Events_In_Map_View->setChecked(porymapConfig.eventOverlayEnabled); + setTheme(porymapConfig.theme); setDivingMapsVisible(porymapConfig.showDiveEmergeMaps); } @@ -1787,14 +1785,20 @@ void MainWindow::on_mapViewTab_tabBarClicked(int index) if (index != oldIndex) Scripting::cb_MapViewTabChanged(oldIndex, index); + static const QMap tabIndexToEditMode = { + {MapViewTab::Metatiles, Editor::EditMode::Metatiles}, + {MapViewTab::Collision, Editor::EditMode::Collision}, + {MapViewTab::Prefabs, Editor::EditMode::Metatiles}, + }; + if (tabIndexToEditMode.contains(index)) { + editor->setEditMode(tabIndexToEditMode.value(index)); + } + if (index == MapViewTab::Metatiles) { - editor->setEditingMetatiles(); refreshMetatileViews(); } else if (index == MapViewTab::Collision) { - editor->setEditingCollision(); refreshCollisionSelector(); } else if (index == MapViewTab::Prefabs) { - editor->setEditingMetatiles(); if (projectConfig.prefabFilepath.isEmpty() && !projectConfig.prefabImportPrompted) { // User hasn't set up prefabs and hasn't been prompted before. // Ask if they'd like to import the default prefabs file. @@ -1821,19 +1825,26 @@ void MainWindow::on_mainTabBar_tabBarClicked(int index) }; ui->mainStackedWidget->setCurrentIndex(tabIndexToStackIndex.value(index)); + static const QMap tabIndexToEditMode = { + // MainTab::Map itself has no edit mode, depends on mapViewTab. + {MainTab::Events, Editor::EditMode::Events}, + {MainTab::Header, Editor::EditMode::Header}, + {MainTab::Connections, Editor::EditMode::Connections}, + {MainTab::WildPokemon, Editor::EditMode::Encounters}, + }; + if (tabIndexToEditMode.contains(index)) { + editor->setEditMode(tabIndexToEditMode.value(index)); + } + if (index == MainTab::Map) { ui->stackedWidget_MapEvents->setCurrentIndex(0); on_mapViewTab_tabBarClicked(ui->mapViewTab->currentIndex()); clickToolButtonFromEditAction(editor->mapEditAction); } else if (index == MainTab::Events) { ui->stackedWidget_MapEvents->setCurrentIndex(1); - editor->setEditingEvents(); clickToolButtonFromEditAction(editor->eventEditAction); } else if (index == MainTab::Connections) { - editor->setEditingConnections(); ui->graphicsView_Connections->setFocus(); // Avoid opening tab with focus on something editable - } else if (index == MainTab::WildPokemon) { - editor->setEditingEncounters(); } if (!editor->map) return; @@ -1883,6 +1894,11 @@ void MainWindow::on_actionCursor_Tile_Outline_triggered() } } +void MainWindow::on_actionShow_Events_In_Map_View_triggered() { + porymapConfig.eventOverlayEnabled = ui->actionShow_Events_In_Map_View->isChecked(); + this->editor->redrawAllEvents(); +} + void MainWindow::on_actionShow_Grid_triggered() { this->editor->toggleGrid(ui->actionShow_Grid->isChecked()); }