From d014eef9e8f6d4bbddc0eb4734a06e5bfec66e3e Mon Sep 17 00:00:00 2001 From: GriffinR Date: Mon, 14 Apr 2025 13:41:57 -0400 Subject: [PATCH] Add NoScrollComboBox::editingFinished, disable diving map buttons with no map --- forms/mainwindow.ui | 6 +++++ include/editor.h | 7 ++--- include/mainwindow.h | 2 -- include/ui/noscrollcombobox.h | 3 +++ src/editor.cpp | 47 ++++++++++++++++++++++++++-------- src/mainwindow.cpp | 16 ------------ src/ui/connectionslistitem.cpp | 5 +--- src/ui/divingmappixmapitem.cpp | 6 +---- src/ui/mapimageexporter.cpp | 5 +--- src/ui/newlayoutform.cpp | 4 +-- src/ui/noscrollcombobox.cpp | 5 ++++ src/ui/tileseteditor.cpp | 14 +++------- 12 files changed, 63 insertions(+), 57 deletions(-) diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui index 99e7d4b2..8a8757a0 100644 --- a/forms/mainwindow.ui +++ b/forms/mainwindow.ui @@ -2429,6 +2429,9 @@ + + false + Open the selected Dive Map @@ -2563,6 +2566,9 @@ + + false + Open the selected Emerge Map diff --git a/include/editor.h b/include/editor.h index 48fdfc0d..8b8a18b0 100644 --- a/include/editor.h +++ b/include/editor.h @@ -98,8 +98,8 @@ public: void deleteWildMonGroup(); void configureEncounterJSON(QWidget *); EncounterTableModel* getCurrentWildMonTable(); - void updateDiveMap(QString mapName); - void updateEmergeMap(QString mapName); + bool setDivingMapName(const QString &mapName, const QString &direction); + QString getDivingMapName(const QString &direction) const; void setSelectedConnection(MapConnection *connection); void updatePrimaryTileset(QString tilesetLabel, bool forceLoad = false); @@ -218,8 +218,9 @@ private: void removeConnectionPixmap(MapConnection *connection); void displayConnection(MapConnection *connection); void displayDivingConnection(MapConnection *connection); - void setDivingMapName(QString mapName, QString direction); void removeDivingMapPixmap(MapConnection *connection); + void onDivingMapEditingFinished(NoScrollComboBox* combo, const QString &direction); + void updateDivingMapButton(QToolButton* button, const QString &mapName); void updateEncounterFields(EncounterFields newFields); QString getMovementPermissionText(uint16_t collision, uint16_t elevation); QString getMetatileDisplayMessage(uint16_t metatileId); diff --git a/include/mainwindow.h b/include/mainwindow.h index 410bd6e3..abda3116 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -243,8 +243,6 @@ private slots: void on_pushButton_AddConnection_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); void on_comboBox_SecondaryTileset_currentTextChanged(const QString &arg1); void on_pushButton_ChangeDimensions_clicked(); diff --git a/include/ui/noscrollcombobox.h b/include/ui/noscrollcombobox.h index 32966b3a..0ae2487c 100644 --- a/include/ui/noscrollcombobox.h +++ b/include/ui/noscrollcombobox.h @@ -18,6 +18,9 @@ public: void setLineEdit(QLineEdit *edit); void setFocusedScrollingEnabled(bool enabled); +signals: + void editingFinished(); + private: void setItem(int index, const QString &text); diff --git a/src/editor.cpp b/src/editor.cpp index 1cb3a304..78cab8bb 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -54,6 +54,19 @@ Editor::Editor(Ui::MainWindow* ui) connect(ui->actionOpen_Project_in_Text_Editor, &QAction::triggered, this, &Editor::openProjectInTextEditor); connect(ui->checkBox_ToggleGrid, &QCheckBox::toggled, this, &Editor::toggleGrid); connect(ui->mapCustomAttributesFrame->table(), &CustomAttributesTable::edited, this, &Editor::updateCustomMapAttributes); + + connect(ui->comboBox_DiveMap, &NoScrollComboBox::editingFinished, [this] { + onDivingMapEditingFinished(this->ui->comboBox_DiveMap, "dive"); + }); + connect(ui->comboBox_EmergeMap, &NoScrollComboBox::editingFinished, [this] { + onDivingMapEditingFinished(this->ui->comboBox_EmergeMap, "emerge"); + }); + connect(ui->comboBox_DiveMap, &NoScrollComboBox::currentTextChanged, [this] { + updateDivingMapButton(this->ui->button_OpenDiveMap, this->ui->comboBox_DiveMap->currentText()); + }); + connect(ui->comboBox_EmergeMap, &NoScrollComboBox::currentTextChanged, [this] { + updateDivingMapButton(this->ui->button_OpenEmergeMap, this->ui->comboBox_EmergeMap->currentText()); + }); } Editor::~Editor() @@ -914,21 +927,18 @@ void Editor::removeDivingMapPixmap(MapConnection *connection) { updateDivingMapsVisibility(); } -void Editor::updateDiveMap(QString mapName) { - setDivingMapName(mapName, "dive"); -} +bool Editor::setDivingMapName(const QString &mapName, const QString &direction) { + if (!mapName.isEmpty() && !this->project->mapNames.contains(mapName)) + return false; + if (!MapConnection::isDiving(direction)) + return false; -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 + return true; // No change // Update existing connection if (mapName.isEmpty()) { @@ -940,6 +950,23 @@ void Editor::setDivingMapName(QString mapName, QString direction) { // Create new connection addConnection(new MapConnection(mapName, direction)); } + return true; +} + +QString Editor::getDivingMapName(const QString &direction) const { + auto pixmapItem = diving_map_items.value(direction); + return (pixmapItem && pixmapItem->connection()) ? pixmapItem->connection()->targetMapName() : QString(); +} + +void Editor::onDivingMapEditingFinished(NoScrollComboBox *combo, const QString &direction) { + if (!setDivingMapName(combo->currentText(), direction)) { + // If user input was invalid, restore the combo to the previously-valid text. + combo->setCurrentText(getDivingMapName(direction)); + } +} + +void Editor::updateDivingMapButton(QToolButton* button, const QString &mapName) { + if (this->project) button->setDisabled(!this->project->mapNames.contains(mapName)); } void Editor::updateDivingMapsVisibility() { @@ -1722,8 +1749,6 @@ void Editor::clearMapConnections() { } connection_items.clear(); - const QSignalBlocker blocker1(ui->comboBox_DiveMap); - const QSignalBlocker blocker2(ui->comboBox_EmergeMap); ui->comboBox_DiveMap->setCurrentText(""); ui->comboBox_EmergeMap->setCurrentText(""); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 006546e5..c539b654 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1217,10 +1217,7 @@ void MainWindow::clearProjectUI() { const QSignalBlocker b_SecondaryTileset(ui->comboBox_SecondaryTileset); ui->comboBox_SecondaryTileset->clear(); - const QSignalBlocker b_DiveMap(ui->comboBox_DiveMap); ui->comboBox_DiveMap->clear(); - - const QSignalBlocker b_EmergeMap(ui->comboBox_EmergeMap); ui->comboBox_EmergeMap->clear(); const QSignalBlocker b_LayoutSelector(ui->comboBox_LayoutSelector); @@ -1381,8 +1378,6 @@ void MainWindow::onNewMapCreated(Map *newMap, const QString &groupName) { // (other combo boxes like for warp destinations are repopulated when the map changes). int mapIndex = this->editor->project->mapNames.indexOf(newMap->name()); if (mapIndex >= 0) { - const QSignalBlocker b_DiveMap(ui->comboBox_DiveMap); - const QSignalBlocker b_EmergeMap(ui->comboBox_EmergeMap); ui->comboBox_DiveMap->insertItem(mapIndex, newMap->name()); ui->comboBox_EmergeMap->insertItem(mapIndex, newMap->name()); } @@ -2646,17 +2641,6 @@ void MainWindow::on_button_OpenEmergeMap_clicked() { userSetMap(ui->comboBox_EmergeMap->currentText()); } -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); -} - void MainWindow::on_comboBox_PrimaryTileset_currentTextChanged(const QString &tilesetLabel) { if (editor->project->primaryTilesetLabels.contains(tilesetLabel) && editor->layout) { diff --git a/src/ui/connectionslistitem.cpp b/src/ui/connectionslistitem.cpp index f761ba12..b0fdf581 100644 --- a/src/ui/connectionslistitem.cpp +++ b/src/ui/connectionslistitem.cpp @@ -20,9 +20,7 @@ ConnectionsListItem::ConnectionsListItem(QWidget *parent, MapConnection * connec ui->comboBox_Direction->addItems(MapConnection::cardinalDirections); ui->comboBox_Direction->installEventFilter(this); - // We don't use QComboBox::currentTextChanged here to avoid unnecessary commits while typing. - connect(ui->comboBox_Direction, QOverload::of(&QComboBox::currentIndexChanged), this, &ConnectionsListItem::commitDirection); - connect(ui->comboBox_Direction->lineEdit(), &QLineEdit::editingFinished, this, &ConnectionsListItem::commitDirection); + connect(ui->comboBox_Direction, &NoScrollComboBox::editingFinished, this, &ConnectionsListItem::commitDirection); // Map const QSignalBlocker b_Map(ui->comboBox_Map); @@ -32,7 +30,6 @@ ConnectionsListItem::ConnectionsListItem(QWidget *parent, MapConnection * connec ui->comboBox_Map->setInsertPolicy(QComboBox::NoInsert); ui->comboBox_Map->installEventFilter(this); - // The map combo box only commits the change if it's a valid map name, so unlike Direction we can use QComboBox::currentTextChanged. connect(ui->comboBox_Map, &QComboBox::currentTextChanged, this, &ConnectionsListItem::commitMap); // Invalid map names are not considered a change. If editing finishes with an invalid name, restore the previous name. diff --git a/src/ui/divingmappixmapitem.cpp b/src/ui/divingmappixmapitem.cpp index e20b8f25..b774b1e9 100644 --- a/src/ui/divingmappixmapitem.cpp +++ b/src/ui/divingmappixmapitem.cpp @@ -38,9 +38,5 @@ void DivingMapPixmapItem::onTargetMapChanged() { } void DivingMapPixmapItem::setComboText(const QString &text) { - if (!m_combo) - return; - - const QSignalBlocker blocker(m_combo); - m_combo->setCurrentText(text); + if (m_combo) m_combo->setCurrentText(text); } diff --git a/src/ui/mapimageexporter.cpp b/src/ui/mapimageexporter.cpp index 58b63cbd..8d415819 100644 --- a/src/ui/mapimageexporter.cpp +++ b/src/ui/mapimageexporter.cpp @@ -55,10 +55,7 @@ MapImageExporter::MapImageExporter(QWidget *parent, Project *project, Map *map, connect(ui->pushButton_Save, &QPushButton::pressed, this, &MapImageExporter::saveImage); connect(ui->pushButton_Cancel, &QPushButton::pressed, this, &MapImageExporter::close); - // Update the map selector when the text changes. - // We don't use QComboBox::currentTextChanged to avoid unnecessary re-rendering. - connect(ui->comboBox_MapSelection, QOverload::of(&QComboBox::currentIndexChanged), this, &MapImageExporter::updateMapSelection); - connect(ui->comboBox_MapSelection->lineEdit(), &QLineEdit::editingFinished, this, &MapImageExporter::updateMapSelection); + connect(ui->comboBox_MapSelection, &NoScrollComboBox::editingFinished, this, &MapImageExporter::updateMapSelection); connect(ui->checkBox_Objects, &QCheckBox::toggled, this, &MapImageExporter::setShowObjects); connect(ui->checkBox_Warps, &QCheckBox::toggled, this, &MapImageExporter::setShowWarps); diff --git a/src/ui/newlayoutform.cpp b/src/ui/newlayoutform.cpp index aa8178ce..2bf4621f 100644 --- a/src/ui/newlayoutform.cpp +++ b/src/ui/newlayoutform.cpp @@ -18,8 +18,8 @@ NewLayoutForm::NewLayoutForm(QWidget *parent) connect(ui->spinBox_MapWidth, QOverload::of(&QSpinBox::valueChanged), [=](int){ validateMapDimensions(); }); connect(ui->spinBox_MapHeight, QOverload::of(&QSpinBox::valueChanged), [=](int){ validateMapDimensions(); }); - connect(ui->comboBox_PrimaryTileset->lineEdit(), &QLineEdit::editingFinished, [this]{ validatePrimaryTileset(true); }); - connect(ui->comboBox_SecondaryTileset->lineEdit(), &QLineEdit::editingFinished, [this]{ validateSecondaryTileset(true); }); + connect(ui->comboBox_PrimaryTileset, &NoScrollComboBox::editingFinished, [this]{ validatePrimaryTileset(true); }); + connect(ui->comboBox_SecondaryTileset, &NoScrollComboBox::editingFinished, [this]{ validateSecondaryTileset(true); }); } NewLayoutForm::~NewLayoutForm() diff --git a/src/ui/noscrollcombobox.cpp b/src/ui/noscrollcombobox.cpp index 21de55a8..bd6b438b 100644 --- a/src/ui/noscrollcombobox.cpp +++ b/src/ui/noscrollcombobox.cpp @@ -23,6 +23,11 @@ NoScrollComboBox::NoScrollComboBox(QWidget *parent) static const QRegularExpression re("[^\\s]*"); QValidator *validator = new QRegularExpressionValidator(re, this); this->setValidator(validator); + + // QComboBox (as of writing) has no 'editing finished' signal to capture + // changes made either through the text edit or the drop-down. + connect(this, &QComboBox::activated, this, &NoScrollComboBox::editingFinished); + connect(this->lineEdit(), &QLineEdit::editingFinished, this, &NoScrollComboBox::editingFinished); } // On macOS QComboBox::setEditable and QComboBox::setLineEdit will override our changes to the focus policy, so we enforce it here. diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp index 3d610fb9..2671f445 100644 --- a/src/ui/tileseteditor.cpp +++ b/src/ui/tileseteditor.cpp @@ -125,16 +125,10 @@ void TilesetEditor::setTilesets(QString primaryTilesetLabel, QString secondaryTi } void TilesetEditor::initAttributesUi() { - // Update the metatile's attributes values when the attribute combo boxes are edited. - // We avoid using the 'currentTextChanged' signal here, we want to know when we can clean up the input field and commit changes. - connect(ui->comboBox_metatileBehaviors->lineEdit(), &QLineEdit::editingFinished, this, &TilesetEditor::commitMetatileBehavior); - connect(ui->comboBox_encounterType->lineEdit(), &QLineEdit::editingFinished, this, &TilesetEditor::commitEncounterType); - connect(ui->comboBox_terrainType->lineEdit(), &QLineEdit::editingFinished, this, &TilesetEditor::commitTerrainType); - connect(ui->comboBox_layerType->lineEdit(), &QLineEdit::editingFinished, this, &TilesetEditor::commitLayerType); - connect(ui->comboBox_metatileBehaviors, QOverload::of(&QComboBox::activated), this, &TilesetEditor::commitMetatileBehavior); - connect(ui->comboBox_encounterType, QOverload::of(&QComboBox::activated), this, &TilesetEditor::commitEncounterType); - connect(ui->comboBox_terrainType, QOverload::of(&QComboBox::activated), this, &TilesetEditor::commitTerrainType); - connect(ui->comboBox_layerType, QOverload::of(&QComboBox::activated), this, &TilesetEditor::commitLayerType); + connect(ui->comboBox_metatileBehaviors, &NoScrollComboBox::editingFinished, this, &TilesetEditor::commitMetatileBehavior); + connect(ui->comboBox_encounterType, &NoScrollComboBox::editingFinished, this, &TilesetEditor::commitEncounterType); + connect(ui->comboBox_terrainType, &NoScrollComboBox::editingFinished, this, &TilesetEditor::commitTerrainType); + connect(ui->comboBox_layerType, &NoScrollComboBox::editingFinished, this, &TilesetEditor::commitLayerType); // Behavior if (projectConfig.metatileBehaviorMask) {