Add events overlay to map view (#678)

This commit is contained in:
GriffinR 2025-02-19 10:16:53 -05:00 committed by GitHub
parent 8668504949
commit 007d11a337
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 100 additions and 89 deletions

View File

@ -2882,6 +2882,7 @@
<addaction name="actionPlayer_View_Rectangle"/>
<addaction name="actionBetter_Cursors"/>
<addaction name="actionDive_Emerge_Map"/>
<addaction name="actionShow_Events_In_Map_View"/>
<addaction name="actionShow_Grid"/>
<addaction name="actionGrid_Settings"/>
</widget>
@ -3236,6 +3237,17 @@
<string>Show Dive/Emerge Map</string>
</property>
</action>
<action name="actionShow_Events_In_Map_View">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="text">
<string>Show Events in Map View</string>
</property>
</action>
<action name="actionShow_Grid">
<property name="checkable">
<bool>true</bool>

View File

@ -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;

View File

@ -119,6 +119,7 @@ public:
void redrawEvents(const QList<Event*> &events);
void redrawEventPixmapItem(DraggablePixmapItem *item);
QList<DraggablePixmapItem *> 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();

View File

@ -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);

View File

@ -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<QString, QString> 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());

View File

@ -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<DraggablePixmapItem *> 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();
}

View File

@ -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<qreal>(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<int, Editor::EditMode> 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<int, Editor::EditMode> 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());
}