From cbd67266b1a108d55b393ba542bd7352d8521593 Mon Sep 17 00:00:00 2001 From: Mike Nelson Date: Wed, 22 Jul 2026 19:41:34 -0500 Subject: [PATCH] align object dialog initialization --- .../dialogs/JumpNodeEditorDialogModel.cpp | 21 +- .../dialogs/JumpNodeEditorDialogModel.h | 2 + .../mission/dialogs/PropEditorDialogModel.cpp | 21 +- .../mission/dialogs/PropEditorDialogModel.h | 2 + .../src/mission/dialogs/SceneBrowserModel.cpp | 18 +- .../src/mission/dialogs/SceneBrowserModel.h | 2 + .../ShipEditor/ShipEditorDialogModel.cpp | 32 +- .../ShipEditor/ShipEditorDialogModel.h | 11 + .../dialogs/WaypointEditorDialogModel.cpp | 21 +- .../dialogs/WaypointEditorDialogModel.h | 2 + .../mission/dialogs/WingEditorDialogModel.cpp | 19 +- .../mission/dialogs/WingEditorDialogModel.h | 2 + .../dialogs/ShipEditor/ShipEditorDialog.cpp | 407 ++++++++---------- .../ui/dialogs/ShipEditor/ShipEditorDialog.h | 13 +- qtfred/src/ui/dialogs/WingEditorDialog.cpp | 12 +- qtfred/src/ui/dialogs/WingEditorDialog.h | 5 +- 16 files changed, 322 insertions(+), 268 deletions(-) diff --git a/qtfred/src/mission/dialogs/JumpNodeEditorDialogModel.cpp b/qtfred/src/mission/dialogs/JumpNodeEditorDialogModel.cpp index b80bdffde9b..13e7aa509d7 100644 --- a/qtfred/src/mission/dialogs/JumpNodeEditorDialogModel.cpp +++ b/qtfred/src/mission/dialogs/JumpNodeEditorDialogModel.cpp @@ -8,6 +8,8 @@ #include #include +#include + namespace fso::fred::dialogs { JumpNodeEditorDialogModel::JumpNodeEditorDialogModel(QObject* parent, EditorViewport* viewport) @@ -445,16 +447,29 @@ void JumpNodeEditorDialogModel::selectPreviousNode() { selectNodeFromObjectList(GET_PREV(&Objects[_selectedJumpNodes.front()]), false); } +void JumpNodeEditorDialogModel::scheduleInitializeData() { + // Bulk selection changes fire one signal per object, so coalesce + // the burst into a single refresh once the event loop settles. + if (_initPending) { + return; + } + _initPending = true; + QTimer::singleShot(0, this, [this] { + _initPending = false; + initializeData(); + }); +} + void JumpNodeEditorDialogModel::onSelectedObjectChanged(int) { - initializeData(); + scheduleInitializeData(); } void JumpNodeEditorDialogModel::onSelectedObjectMarkingChanged(int, bool) { - initializeData(); + scheduleInitializeData(); } void JumpNodeEditorDialogModel::onMissionChanged() { - initializeData(); + scheduleInitializeData(); } } // namespace fso::fred::dialogs diff --git a/qtfred/src/mission/dialogs/JumpNodeEditorDialogModel.h b/qtfred/src/mission/dialogs/JumpNodeEditorDialogModel.h index 27f374fe0d4..5bd1f47f82d 100644 --- a/qtfred/src/mission/dialogs/JumpNodeEditorDialogModel.h +++ b/qtfred/src/mission/dialogs/JumpNodeEditorDialogModel.h @@ -57,6 +57,7 @@ private slots: private: // NOLINT(readability-redundant-access-specifiers) void initializeData(); + void scheduleInitializeData(); void showErrorDialogNoCancel(const SCP_string& message); bool validateName(const SCP_string& name); void selectNodeFromObjectList(object* start, bool forward); @@ -73,6 +74,7 @@ private slots: bool _hiddenMixed = false; bool _bypass_errors = false; + bool _initPending = false; }; } // namespace fso::fred::dialogs diff --git a/qtfred/src/mission/dialogs/PropEditorDialogModel.cpp b/qtfred/src/mission/dialogs/PropEditorDialogModel.cpp index 035bcc67814..e560389fda1 100644 --- a/qtfred/src/mission/dialogs/PropEditorDialogModel.cpp +++ b/qtfred/src/mission/dialogs/PropEditorDialogModel.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include namespace fso::fred::dialogs { @@ -312,16 +314,29 @@ void PropEditorDialogModel::selectPreviousProp() { selectPropFromObjectList(GET_PREV(&Objects[_selectedPropObjects.front()]), false); } +void PropEditorDialogModel::scheduleInitializeData() { + // Bulk selection changes fire one signal per object, so coalesce + // the burst into a single refresh once the event loop settles. + if (_initPending) { + return; + } + _initPending = true; + QTimer::singleShot(0, this, [this] { + _initPending = false; + initializeData(); + }); +} + void PropEditorDialogModel::onSelectedObjectChanged(int) { - initializeData(); + scheduleInitializeData(); } void PropEditorDialogModel::onSelectedObjectMarkingChanged(int, bool) { - initializeData(); + scheduleInitializeData(); } void PropEditorDialogModel::onMissionChanged() { - initializeData(); + scheduleInitializeData(); } SCP_vector> PropEditorDialogModel::getPropFlagDescriptions() diff --git a/qtfred/src/mission/dialogs/PropEditorDialogModel.h b/qtfred/src/mission/dialogs/PropEditorDialogModel.h index b51ec3d55b4..0dbf6e20876 100644 --- a/qtfred/src/mission/dialogs/PropEditorDialogModel.h +++ b/qtfred/src/mission/dialogs/PropEditorDialogModel.h @@ -41,6 +41,7 @@ class PropEditorDialogModel : public AbstractDialogModel { private: // NOLINT(readability-redundant-access-specifiers) void initializeData(); + void scheduleInitializeData(); void showErrorDialogNoCancel(const SCP_string& message); void selectPropFromObjectList(object* start, bool forward); void selectFirstPropInMission(); @@ -53,6 +54,7 @@ class PropEditorDialogModel : public AbstractDialogModel { SCP_vector _flagState; SCP_vector _selectedPropObjects; bool _bypass_errors = false; + bool _initPending = false; }; } diff --git a/qtfred/src/mission/dialogs/SceneBrowserModel.cpp b/qtfred/src/mission/dialogs/SceneBrowserModel.cpp index cb3837f1504..f2037901b7c 100644 --- a/qtfred/src/mission/dialogs/SceneBrowserModel.cpp +++ b/qtfred/src/mission/dialogs/SceneBrowserModel.cpp @@ -307,16 +307,30 @@ void SceneBrowserModel::setNameFilter(const QString& filter) // Signal handlers // --------------------------------------------------------------------------- +void SceneBrowserModel::scheduleSelectionSync() +{ + // Bulk selection changes fire one signal per object, so coalesce + // the burst into a single refresh once the event loop settles. + if (_syncPending) { + return; + } + _syncPending = true; + QTimer::singleShot(0, this, [this] { + _syncPending = false; + modelChanged(); + }); +} + void SceneBrowserModel::onCurrentObjectChanged(int /*newObj*/) { if (_updatingFromBrowser) return; - modelChanged(); + scheduleSelectionSync(); } void SceneBrowserModel::onObjectMarkingChanged(int /*obj*/, bool /*marked*/) { if (_updatingFromBrowser) return; - modelChanged(); + scheduleSelectionSync(); } void SceneBrowserModel::onLayerVisibilityChanged() diff --git a/qtfred/src/mission/dialogs/SceneBrowserModel.h b/qtfred/src/mission/dialogs/SceneBrowserModel.h index a54206e7025..d6d0578a96c 100644 --- a/qtfred/src/mission/dialogs/SceneBrowserModel.h +++ b/qtfred/src/mission/dialogs/SceneBrowserModel.h @@ -86,11 +86,13 @@ class SceneBrowserModel : public AbstractDialogModel { private: void buildTree(); + void scheduleSelectionSync(); QVector _tree; QString _nameFilter; QVector _filterIff; bool _updatingFromBrowser = false; + bool _syncPending = false; QTimer* _rebuildTimer = nullptr; Q_SLOT void onCurrentObjectChanged(int newObj); diff --git a/qtfred/src/mission/dialogs/ShipEditor/ShipEditorDialogModel.cpp b/qtfred/src/mission/dialogs/ShipEditor/ShipEditorDialogModel.cpp index efb6593b64e..fd883acfde2 100644 --- a/qtfred/src/mission/dialogs/ShipEditor/ShipEditorDialogModel.cpp +++ b/qtfred/src/mission/dialogs/ShipEditor/ShipEditorDialogModel.cpp @@ -27,9 +27,39 @@ namespace fso::fred::dialogs { ShipEditorDialogModel::ShipEditorDialogModel(QObject* parent, EditorViewport* viewport) : AbstractDialogModel(parent, viewport) { + connect(viewport->editor, &Editor::currentObjectChanged, this, &ShipEditorDialogModel::onSelectedObjectChanged); + connect(viewport->editor, + &Editor::objectMarkingChanged, + this, + &ShipEditorDialogModel::onSelectedObjectMarkingChanged); + initializeData(); } +void ShipEditorDialogModel::scheduleInitializeData() +{ + // Bulk selection changes fire one signal per object, so coalesce + // the burst into a single refresh once the event loop settles. + if (_initPending) { + return; + } + _initPending = true; + QTimer::singleShot(0, this, [this] { + _initPending = false; + initializeData(); + }); +} + +void ShipEditorDialogModel::onSelectedObjectChanged(int) +{ + scheduleInitializeData(); +} + +void ShipEditorDialogModel::onSelectedObjectMarkingChanged(int, bool) +{ + scheduleInitializeData(); +} + int ShipEditorDialogModel::tristate_set(int val, int cur_state) { @@ -546,7 +576,7 @@ void ShipEditorDialogModel::initializeData() } } - modelChanged(); + Q_EMIT shipMarkingChanged(); _modified = false; } diff --git a/qtfred/src/mission/dialogs/ShipEditor/ShipEditorDialogModel.h b/qtfred/src/mission/dialogs/ShipEditor/ShipEditorDialogModel.h index c319036d150..550ec24e958 100644 --- a/qtfred/src/mission/dialogs/ShipEditor/ShipEditorDialogModel.h +++ b/qtfred/src/mission/dialogs/ShipEditor/ShipEditorDialogModel.h @@ -149,8 +149,18 @@ class ShipEditorDialogModel : public AbstractDialogModel { void initializeData(); + signals: + // Emitted after the model has re-synced from the current selection; the view + // should do a full (overwrite) refresh in response. + void shipMarkingChanged(); + + private slots: + void onSelectedObjectChanged(int); + void onSelectedObjectMarkingChanged(int, bool); + private: // NOLINT(readability-redundant-access-specifiers) void setModified(); + void scheduleInitializeData(); void shipAltNameClose(int baseShip); void shipCallsignClose(int baseShip); static int makeShipList(int* arr); @@ -203,6 +213,7 @@ class ShipEditorDialogModel : public AbstractDialogModel { int _respawnPriority; SCP_vector> _arrivalPaths; SCP_vector> _departurePaths; + bool _initPending = false; }; } // namespace fso::fred::dialogs diff --git a/qtfred/src/mission/dialogs/WaypointEditorDialogModel.cpp b/qtfred/src/mission/dialogs/WaypointEditorDialogModel.cpp index eddbf1dc955..d7cd93e7e88 100644 --- a/qtfred/src/mission/dialogs/WaypointEditorDialogModel.cpp +++ b/qtfred/src/mission/dialogs/WaypointEditorDialogModel.cpp @@ -5,6 +5,8 @@ #include #include "mission/dialogs/WaypointEditorDialogModel.h" +#include + namespace fso::fred::dialogs { namespace { @@ -425,19 +427,32 @@ void WaypointEditorDialogModel::selectPreviousPath() { selectWaypointPathByIndex(prev); } +void WaypointEditorDialogModel::scheduleInitializeData() { + // Bulk selection changes fire one signal per object, so coalesce + // the burst into a single refresh once the event loop settles.tles. + if (_initPending) { + return; + } + _initPending = true; + QTimer::singleShot(0, this, [this] { + _initPending = false; + initializeData(); + }); +} + void WaypointEditorDialogModel::onSelectedObjectChanged(int) { if (_suppressRefresh) return; - initializeData(); + scheduleInitializeData(); } void WaypointEditorDialogModel::onSelectedObjectMarkingChanged(int, bool) { if (_suppressRefresh) return; - initializeData(); + scheduleInitializeData(); } void WaypointEditorDialogModel::onMissionChanged() { if (_suppressRefresh) return; - initializeData(); + scheduleInitializeData(); } } // namespace fso::fred::dialogs diff --git a/qtfred/src/mission/dialogs/WaypointEditorDialogModel.h b/qtfred/src/mission/dialogs/WaypointEditorDialogModel.h index 52a861f72d2..8c1f843c58e 100644 --- a/qtfred/src/mission/dialogs/WaypointEditorDialogModel.h +++ b/qtfred/src/mission/dialogs/WaypointEditorDialogModel.h @@ -58,6 +58,7 @@ private slots: private: // NOLINT(readability-redundant-access-specifiers) void initializeData(); + void scheduleInitializeData(); void showErrorDialogNoCancel(const SCP_string& message); bool validateName(const SCP_string& name); @@ -75,6 +76,7 @@ private slots: // Guards against re-entry into initializeData() from selection/marking/mission signals // while we're already mutating mission state (e.g., setLayer fans out unmarks). bool _suppressRefresh = false; + bool _initPending = false; }; } // namespace fso::fred::dialogs diff --git a/qtfred/src/mission/dialogs/WingEditorDialogModel.cpp b/qtfred/src/mission/dialogs/WingEditorDialogModel.cpp index 410eff5f90c..38ab3537d58 100644 --- a/qtfred/src/mission/dialogs/WingEditorDialogModel.cpp +++ b/qtfred/src/mission/dialogs/WingEditorDialogModel.cpp @@ -8,6 +8,7 @@ #include "missioneditor/common.h" #include #include +#include namespace fso::fred::dialogs { WingEditorDialogModel::WingEditorDialogModel(QObject* parent, EditorViewport* viewport) @@ -25,14 +26,28 @@ void WingEditorDialogModel::initializeData() _modified = false; } +void WingEditorDialogModel::scheduleReloadFromCurWing() +{ + // Bulk selection changes fire one signal per object, so coalesce + // the burst into a single refresh once the event loop settles. + if (_reloadPending) { + return; + } + _reloadPending = true; + QTimer::singleShot(0, this, [this] { + _reloadPending = false; + reloadFromCurWing(); + }); +} + void WingEditorDialogModel::onEditorSelectionChanged(int) { - reloadFromCurWing(); + scheduleReloadFromCurWing(); } void WingEditorDialogModel::onEditorMissionChanged() { - reloadFromCurWing(); + scheduleReloadFromCurWing(); } void WingEditorDialogModel::reloadFromCurWing() diff --git a/qtfred/src/mission/dialogs/WingEditorDialogModel.h b/qtfred/src/mission/dialogs/WingEditorDialogModel.h index bd427e8294a..d763f2c30df 100644 --- a/qtfred/src/mission/dialogs/WingEditorDialogModel.h +++ b/qtfred/src/mission/dialogs/WingEditorDialogModel.h @@ -134,12 +134,14 @@ class WingEditorDialogModel : public AbstractDialogModel { private: // NOLINT(readability-redundant-access-specifiers) void initializeData(); void reloadFromCurWing(); + void scheduleReloadFromCurWing(); wing* getCurrentWing() const; static SCP_vector> getDockBayPathsForWingMask(uint32_t mask, int anchorShipnum); void prepareSquadLogoList(); int _currentWingIndex = -1; SCP_string _currentWingName; + bool _reloadPending = false; SCP_vector _squadLogoList; }; diff --git a/qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.cpp b/qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.cpp index 620d42f5a98..4b118284d62 100644 --- a/qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.cpp +++ b/qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.cpp @@ -12,7 +12,6 @@ #include #include -#include #include #include @@ -34,9 +33,14 @@ ShipEditorDialog::ShipEditorDialog(FredView* parent, EditorViewport* viewport) ui->callsignCombo->lineEdit()->setMaxLength(CALLSIGN_LEN); ui->cargoTitleEdit->setMaxLength(NAME_LENGTH - 1); - connect(_model.get(), &AbstractDialogModel::modelChanged, this, [this] { updateUi(false); }); - connect(viewport->editor, &Editor::currentObjectChanged, this, &ShipEditorDialog::update); - connect(viewport->editor, &Editor::objectMarkingChanged, this, &ShipEditorDialog::update); + initializeUi(); + updateUi(); + + connect(_model.get(), &AbstractDialogModel::modelChanged, this, [this] { initializeUi(); }); + connect(_model.get(), &ShipEditorDialogModel::shipMarkingChanged, this, [this] { + initializeUi(); + updateUi(); + }); connect(ui->arrivalTree, &sexp_tree_view::modified, this, &ShipEditorDialog::on_arrivalTree_modified); connect(ui->arrivalTree, &sexp_tree_view::helpChanged, this, &ShipEditorDialog::on_arrivalTree_helpChanged); @@ -74,8 +78,6 @@ ShipEditorDialog::ShipEditorDialog(FredView* parent, EditorViewport* viewport) }, tr("&Select Ship")); - updateUi(true); - // Resize the dialog to the minimum size resize(QDialog::sizeHint()); } @@ -97,22 +99,6 @@ bool ShipEditorDialog::getIfMultipleShips() const return _model->getIfMultipleShips(); } -void ShipEditorDialog::closeEvent(QCloseEvent* e) -{ - QDialog::closeEvent(e); -} - -void ShipEditorDialog::hideEvent(QHideEvent* e) -{ - QDialog::hideEvent(e); -} -void ShipEditorDialog::showEvent(QShowEvent* e) -{ - _model->initializeData(); - updateUi(true); - QDialog::showEvent(e); -} - void ShipEditorDialog::on_miscButton_clicked() { auto dialog = new dialogs::ShipFlagsDialog(this, _viewport); @@ -143,125 +129,24 @@ void ShipEditorDialog::on_tblInfoButton_clicked() dialog->show(); } -void ShipEditorDialog::update() -{ - if (this->isVisible()) { - _model->initializeData(); - updateUi(true); - } -} - -void ShipEditorDialog::updateUi(bool overwrite) +// Syncs selection-dependent structure: enabled states, window title, and the combos +// whose contents depend on current mission state. Safe to run mid-edit — does not +// overwrite user-editable values or reload the sexp trees. +void ShipEditorDialog::initializeUi() { util::SignalBlockers blockers(this); + enableDisable(); - updateColumnOne(overwrite); - updateColumnTwo(overwrite); - updateArrival(overwrite); - updateDeparture(overwrite); -} -void ShipEditorDialog::updateColumnOne(bool overwrite) -{ - util::SignalBlockers blockers(this); - int idx; - if (overwrite) { - ui->shipNameEdit->setText(_model->getShipName().c_str()); - ui->shipDisplayNameEdit->setText(_model->getShipDisplayName().c_str()); - idx = _model->getShipClass(); - ui->shipClassCombo->clear(); - for (size_t i = 0; i < Ship_info.size(); i++) { - ui->shipClassCombo->addItem(Ship_info[i].name, QVariant(static_cast(i))); - } - ui->shipClassCombo->setCurrentIndex(ui->shipClassCombo->findData(idx)); - auto ai = _model->getAIClass(); - ui->AIClassCombo->clear(); - for (auto j = 0; j < Num_ai_classes; j++) { - ui->AIClassCombo->addItem(Ai_class_names[j], QVariant(j)); - } - ui->AIClassCombo->setCurrentIndex(ui->AIClassCombo->findData(ai)); - } if (_model->getNumSelectedPlayers()) { - if (_model->getTeam() != -1) { - ui->teamCombo->setEnabled(true); - } else { - ui->teamCombo->setEnabled(false); - } - if (overwrite) { - ui->teamCombo->clear(); - for (auto i = 0; i < MAX_TVT_TEAMS; i++) { - ui->teamCombo->addItem(Iff_info[i].iff_name, QVariant(static_cast(i))); - } - } + ui->teamCombo->setEnabled(_model->getTeam() != -1); } else { ui->teamCombo->setEnabled(_model->getUIEnable()); - if (overwrite) { - idx = _model->getTeam(); - ui->teamCombo->clear(); - for (size_t i = 0; i < Iff_info.size(); i++) { - ui->teamCombo->addItem(Iff_info[i].iff_name, QVariant(static_cast(i))); - } - ui->teamCombo->setCurrentIndex(ui->teamCombo->findData(idx)); - } } - if (overwrite) { - auto cargo = _model->getCargo(); - ui->cargoCombo->clear(); - int j; - for (j = 0; j < Num_cargo; j++) { - ui->cargoCombo->addItem(Cargo_names[j]); - } - if (ui->cargoCombo->findText(QString(cargo.c_str()))) { - ui->cargoCombo->setCurrentIndex(ui->cargoCombo->findText(QString(cargo.c_str()))); - } else { - ui->cargoCombo->addItem(cargo.c_str()); - ui->cargoCombo->setCurrentIndex(ui->cargoCombo->findText(QString(cargo.c_str()))); - } - ui->cargoTitleEdit->setText(_model->getCargoTitle().c_str()); - } if (_model->getNumSelectedObjects()) { - if (_model->getIfMultipleShips()) { - ui->altNameCombo->setEnabled(false); - } else { - auto altname = _model->getAltName(); - ui->altNameCombo->setEnabled(true); - if (overwrite) { - ui->altNameCombo->clear(); - ui->altNameCombo->addItem(""); - for (auto j = 0; j < Mission_alt_type_count; j++) { - ui->altNameCombo->addItem(Mission_alt_types[j]); - } - int altNameIdx = ui->altNameCombo->findText(QString(altname.c_str())); - if (altNameIdx >= 0) { - ui->altNameCombo->setCurrentIndex(altNameIdx); - } else { - ui->altNameCombo->setEditText(""); - } - } - } - } - if (_model->getNumSelectedObjects()) { - if (_model->getIfMultipleShips()) { - ui->callsignCombo->setEnabled(false); - } else { - auto callsign = _model->getCallsign(); - ui->callsignCombo->setEnabled(true); - if (overwrite) { - ui->callsignCombo->clear(); - ui->callsignCombo->addItem(""); - for (auto j = 0; j < Mission_callsign_count; j++) { - SCP_string current = Mission_callsigns[j]; - ui->callsignCombo->addItem(Mission_callsigns[j], current.c_str()); - } - int callsignIdx = ui->callsignCombo->findText(QString(callsign.c_str())); - if (callsignIdx >= 0) { - ui->callsignCombo->setCurrentIndex(callsignIdx); - } else { - ui->callsignCombo->setEditText(""); - } - } - } + ui->altNameCombo->setEnabled(!_model->getIfMultipleShips()); + ui->callsignCombo->setEnabled(!_model->getIfMultipleShips()); } // Layer combo — always rebuild so it reflects current mission layers @@ -271,37 +156,8 @@ void ShipEditorDialog::updateColumnOne(bool overwrite) } ui->layerCombo->setCurrentIndex(ui->layerCombo->findData(QString::fromStdString(_model->getLayer()))); ui->layerCombo->setEnabled(_model->getNumSelectedObjects() > 0); -} -void ShipEditorDialog::updateColumnTwo(bool overwrite) -{ - util::SignalBlockers blockers(this); - if (overwrite) { - ui->wing->setText(_model->getWing().c_str()); - auto idx = _model->getPersona(); - ui->personaCombo->setCurrentIndex(ui->personaCombo->findData(idx)); - - ui->killScoreEdit->setValue(_model->getScore()); - - ui->assistEdit->setValue(_model->getAssist()); - - ui->playerShipCheckBox->setChecked(_model->getPlayer()); - ui->respawnSpinBox->setValue(_model->getRespawn()); - ui->hotkeyCombo->setCurrentIndex(_model->getHotkey()); - } -} -void ShipEditorDialog::updateArrival(bool overwrite) -{ - util::SignalBlockers blockers(this); - if (overwrite) { - auto idx = _model->getArrivalLocationIndex(); - int i; - ui->arrivalLocationCombo->clear(); - for (i = 0; i < MAX_ARRIVAL_NAMES; i++) { - ui->arrivalLocationCombo->addItem(Arrival_location_names[i], QVariant(i)); - } - ui->arrivalLocationCombo->setCurrentIndex(ui->arrivalLocationCombo->findData(idx)); - } + // Arrival target combo — contents depend on which ships are currently marked object* objp; int restrict_to_players; ui->arrivalTargetCombo->clear(); @@ -340,53 +196,8 @@ void ShipEditorDialog::updateArrival(bool overwrite) } } ui->arrivalTargetCombo->setCurrentIndex(ui->arrivalTargetCombo->findData(_model->getArrivalTarget())); - if (overwrite) { - ui->arrivalDistanceEdit->clear(); - ui->arrivalDistanceEdit->setValue(_model->getArrivalDistance()); - ui->arrivalDelaySpinBox->setValue(_model->getArrivalDelay()); - - ui->updateArrivalCueCheckBox->setChecked(_model->getArrivalCue()); - - ui->arrivalTree->initializeEditor(_viewport->editor, this, _viewport); - if (_model->getNumSelectedShips()) { - - if (_model->getIfMultipleShips()) { - ui->arrivalTree->clear_tree(""); - } - if (_model->getUseCue()) { - ui->arrivalTree->load_tree(_model->getArrivalFormula()); - ui->arrivalTree->expandAll(); - } else { - ui->arrivalTree->clear_tree(""); - } - if (!_model->getIfMultipleShips()) { - int j = ui->arrivalTree->select_sexp_node; - if (j != -1) { - ui->arrivalTree->hilite_item(j); - } - } - } else { - ui->arrivalTree->clear_tree(""); - } - - ui->noArrivalWarpCheckBox->setCheckState(Qt::CheckState(_model->getNoArrivalWarp())); - ui->dockWarpinCheckBox->setCheckState(Qt::CheckState(_model->getDockWarpinChange())); - } -} -void ShipEditorDialog::updateDeparture(bool overwrite) -{ - util::SignalBlockers blockers(this); - if (overwrite) { - auto idx = _model->getDepartureLocationIndex(); - int i; - ui->departureLocationCombo->clear(); - for (i = 0; i < MAX_DEPARTURE_NAMES; i++) { - ui->departureLocationCombo->addItem(Departure_location_names[i], QVariant(i)); - } - ui->departureLocationCombo->setCurrentIndex(ui->departureLocationCombo->findData(idx)); - } - object* objp; + // Departure target combo — only ships with docking bays ui->departureTargetCombo->clear(); for (objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp)) { if (((objp->type == OBJ_SHIP) || (objp->type == OBJ_START)) && !(objp->flags[Object::Object_Flags::Marked])) { @@ -402,37 +213,173 @@ void ShipEditorDialog::updateDeparture(bool overwrite) } } ui->departureTargetCombo->setCurrentIndex(ui->departureTargetCombo->findData(_model->getDepartureTarget())); - if (overwrite) { - ui->departureDelaySpinBox->setValue(_model->getDepartureDelay()); +} - ui->departureTree->initializeEditor(_viewport->editor, this, _viewport); - if (_model->getNumSelectedShips()) { +// Overwrites every editable value from the model, including rebuilding the static +// combos and reloading the arrival/departure sexp trees. +void ShipEditorDialog::updateUi() +{ + util::SignalBlockers blockers(this); - if (_model->getIfMultipleShips()) { - ui->departureTree->clear_tree(""); - } - if (_model->getUseCue()) { - ui->departureTree->load_tree(_model->getDepartureFormula(), "false"); - ui->departureTree->expandAll(); - } else { - ui->departureTree->clear_tree(""); - } - if (!_model->getIfMultipleShips()) { - auto i = ui->arrivalTree->select_sexp_node; - if (i != -1) { - i = ui->departureTree->select_sexp_node; - ui->departureTree->hilite_item(i); - } + // Column one + ui->shipNameEdit->setText(_model->getShipName().c_str()); + ui->shipDisplayNameEdit->setText(_model->getShipDisplayName().c_str()); + + auto shipClass = _model->getShipClass(); + ui->shipClassCombo->clear(); + for (size_t i = 0; i < Ship_info.size(); i++) { + ui->shipClassCombo->addItem(Ship_info[i].name, QVariant(static_cast(i))); + } + ui->shipClassCombo->setCurrentIndex(ui->shipClassCombo->findData(shipClass)); + + auto ai = _model->getAIClass(); + ui->AIClassCombo->clear(); + for (auto j = 0; j < Num_ai_classes; j++) { + ui->AIClassCombo->addItem(Ai_class_names[j], QVariant(j)); + } + ui->AIClassCombo->setCurrentIndex(ui->AIClassCombo->findData(ai)); + + ui->teamCombo->clear(); + if (_model->getNumSelectedPlayers()) { + for (auto i = 0; i < MAX_TVT_TEAMS; i++) { + ui->teamCombo->addItem(Iff_info[i].iff_name, QVariant(static_cast(i))); + } + } else { + auto team = _model->getTeam(); + for (size_t i = 0; i < Iff_info.size(); i++) { + ui->teamCombo->addItem(Iff_info[i].iff_name, QVariant(static_cast(i))); + } + ui->teamCombo->setCurrentIndex(ui->teamCombo->findData(team)); + } + + auto cargo = _model->getCargo(); + ui->cargoCombo->clear(); + for (int j = 0; j < Num_cargo; j++) { + ui->cargoCombo->addItem(Cargo_names[j]); + } + int cargoIdx = ui->cargoCombo->findText(QString(cargo.c_str())); + if (cargoIdx < 0) { + ui->cargoCombo->addItem(cargo.c_str()); + cargoIdx = ui->cargoCombo->count() - 1; + } + ui->cargoCombo->setCurrentIndex(cargoIdx); + ui->cargoTitleEdit->setText(_model->getCargoTitle().c_str()); + + if (_model->getNumSelectedObjects() && !_model->getIfMultipleShips()) { + auto altname = _model->getAltName(); + ui->altNameCombo->clear(); + ui->altNameCombo->addItem(""); + for (auto j = 0; j < Mission_alt_type_count; j++) { + ui->altNameCombo->addItem(Mission_alt_types[j]); + } + int altNameIdx = ui->altNameCombo->findText(QString(altname.c_str())); + if (altNameIdx >= 0) { + ui->altNameCombo->setCurrentIndex(altNameIdx); + } else { + ui->altNameCombo->setEditText(""); + } + + auto callsign = _model->getCallsign(); + ui->callsignCombo->clear(); + ui->callsignCombo->addItem(""); + for (auto j = 0; j < Mission_callsign_count; j++) { + SCP_string current = Mission_callsigns[j]; + ui->callsignCombo->addItem(Mission_callsigns[j], current.c_str()); + } + int callsignIdx = ui->callsignCombo->findText(QString(callsign.c_str())); + if (callsignIdx >= 0) { + ui->callsignCombo->setCurrentIndex(callsignIdx); + } else { + ui->callsignCombo->setEditText(""); + } + } + + // Column two + ui->wing->setText(_model->getWing().c_str()); + + ui->personaCombo->setCurrentIndex(ui->personaCombo->findData(_model->getPersona())); + + ui->killScoreEdit->setValue(_model->getScore()); + ui->assistEdit->setValue(_model->getAssist()); + + ui->playerShipCheckBox->setChecked(_model->getPlayer()); + ui->respawnSpinBox->setValue(_model->getRespawn()); + ui->hotkeyCombo->setCurrentIndex(_model->getHotkey()); + + // Arrival + auto arrivalLocation = _model->getArrivalLocationIndex(); + ui->arrivalLocationCombo->clear(); + for (int i = 0; i < MAX_ARRIVAL_NAMES; i++) { + ui->arrivalLocationCombo->addItem(Arrival_location_names[i], QVariant(i)); + } + ui->arrivalLocationCombo->setCurrentIndex(ui->arrivalLocationCombo->findData(arrivalLocation)); + + ui->arrivalDistanceEdit->clear(); + ui->arrivalDistanceEdit->setValue(_model->getArrivalDistance()); + ui->arrivalDelaySpinBox->setValue(_model->getArrivalDelay()); + + ui->updateArrivalCueCheckBox->setChecked(_model->getArrivalCue()); + + ui->arrivalTree->initializeEditor(_viewport->editor, this, _viewport); + if (_model->getNumSelectedShips()) { + if (_model->getIfMultipleShips()) { + ui->arrivalTree->clear_tree(""); + } + if (_model->getUseCue()) { + ui->arrivalTree->load_tree(_model->getArrivalFormula()); + ui->arrivalTree->expandAll(); + } else { + ui->arrivalTree->clear_tree(""); + } + if (!_model->getIfMultipleShips()) { + int j = ui->arrivalTree->select_sexp_node; + if (j != -1) { + ui->arrivalTree->hilite_item(j); } + } + } else { + ui->arrivalTree->clear_tree(""); + } + + ui->noArrivalWarpCheckBox->setCheckState(Qt::CheckState(_model->getNoArrivalWarp())); + ui->dockWarpinCheckBox->setCheckState(Qt::CheckState(_model->getDockWarpinChange())); + + // Departure + auto departureLocation = _model->getDepartureLocationIndex(); + ui->departureLocationCombo->clear(); + for (int i = 0; i < MAX_DEPARTURE_NAMES; i++) { + ui->departureLocationCombo->addItem(Departure_location_names[i], QVariant(i)); + } + ui->departureLocationCombo->setCurrentIndex(ui->departureLocationCombo->findData(departureLocation)); + + ui->departureDelaySpinBox->setValue(_model->getDepartureDelay()); + + ui->departureTree->initializeEditor(_viewport->editor, this, _viewport); + if (_model->getNumSelectedShips()) { + if (_model->getIfMultipleShips()) { + ui->departureTree->clear_tree(""); + } + if (_model->getUseCue()) { + ui->departureTree->load_tree(_model->getDepartureFormula(), "false"); + ui->departureTree->expandAll(); } else { ui->departureTree->clear_tree(""); } + if (!_model->getIfMultipleShips()) { + auto i = ui->arrivalTree->select_sexp_node; + if (i != -1) { + i = ui->departureTree->select_sexp_node; + ui->departureTree->hilite_item(i); + } + } + } else { + ui->departureTree->clear_tree(""); + } - ui->noDepartureWarpCheckBox->setCheckState(Qt::CheckState(_model->getNoDepartureWarp())); - ui->dockWarpoutCheckBox->setCheckState(Qt::CheckState(_model->getDockWarpoutChange())); + ui->noDepartureWarpCheckBox->setCheckState(Qt::CheckState(_model->getNoDepartureWarp())); + ui->dockWarpoutCheckBox->setCheckState(Qt::CheckState(_model->getDockWarpoutChange())); - ui->updateDepartureCueCheckBox->setChecked(_model->getDepartureCue()); - } + ui->updateDepartureCueCheckBox->setChecked(_model->getDepartureCue()); } // Enables disbales controls based on what is selected void ShipEditorDialog::enableDisable() diff --git a/qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.h b/qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.h index 0b6a6b210f4..0c3f8b3f554 100644 --- a/qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.h +++ b/qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.h @@ -32,10 +32,6 @@ class ShipEditorDialog : public QDialog, public SexpTreeEditorInterface { int getSingleShip() const; bool getIfMultipleShips() const; - protected: - void closeEvent(QCloseEvent*) override; - void hideEvent(QHideEvent*) override; - void showEvent(QShowEvent*) override; private slots: void on_textureReplacementButton_clicked(); @@ -103,13 +99,8 @@ class ShipEditorDialog : public QDialog, public SexpTreeEditorInterface { bool _cues_hidden = false; - void update(); - - void updateUi(bool overwrite = false); - void updateColumnOne(bool overwrite = false); - void updateColumnTwo(bool ovewrite = false); - void updateArrival(bool overwrite = false); - void updateDeparture(bool overwrite = false); + void initializeUi(); + void updateUi(); void enableDisable(); // column one diff --git a/qtfred/src/ui/dialogs/WingEditorDialog.cpp b/qtfred/src/ui/dialogs/WingEditorDialog.cpp index dd40fdea28e..80ee91525c8 100644 --- a/qtfred/src/ui/dialogs/WingEditorDialog.cpp +++ b/qtfred/src/ui/dialogs/WingEditorDialog.cpp @@ -1,5 +1,4 @@ #include "WingEditorDialog.h" -#include #include "General/CheckBoxListDialog.h" #include "General/ImagePickerDialog.h" #include "ShipEditor/ShipGoalsDialog.h" @@ -34,7 +33,7 @@ WingEditorDialog::WingEditorDialog(FredView* parent, EditorViewport* viewport) // Whenever the model reports changes, refresh the UI connect(_model.get(), &AbstractDialogModel::modelChanged, this, &WingEditorDialog::updateUi); connect(_model.get(), &WingEditorDialogModel::wingChanged, this, [this] { - refreshAllDynamicCombos(); + initializeUi(); updateUi(); }); @@ -62,7 +61,7 @@ WingEditorDialog::WingEditorDialog(FredView* parent, EditorViewport* viewport) [editor](int wing) { editor->mark_wing(wing); }, tr("&Select Wing")); - refreshAllDynamicCombos(); + initializeUi(); updateUi(); // Resize the dialog to the minimum size @@ -71,11 +70,6 @@ WingEditorDialog::WingEditorDialog(FredView* parent, EditorViewport* viewport) WingEditorDialog::~WingEditorDialog() = default; -void WingEditorDialog::closeEvent(QCloseEvent* e) -{ - QDialog::closeEvent(e); -} - void WingEditorDialog::updateUi() { util::SignalBlockers blockers(this); @@ -358,7 +352,7 @@ void WingEditorDialog::refreshDepartureTargetCombo() } } -void WingEditorDialog::refreshAllDynamicCombos() +void WingEditorDialog::initializeUi() { refreshLeaderCombo(); refreshHotkeyCombo(); diff --git a/qtfred/src/ui/dialogs/WingEditorDialog.h b/qtfred/src/ui/dialogs/WingEditorDialog.h index 35e50d3a15c..214f503e3ae 100644 --- a/qtfred/src/ui/dialogs/WingEditorDialog.h +++ b/qtfred/src/ui/dialogs/WingEditorDialog.h @@ -72,9 +72,6 @@ class WingEditorDialog : public QDialog, public SexpTreeEditorInterface { void on_departureTree_helpChanged(const QString& help); void on_departureTree_miniHelpChanged(const QString& help); - protected: - void closeEvent(QCloseEvent* e) override; - private: // NOLINT(readability-redundant-access-specifiers) std::unique_ptr ui; std::unique_ptr _model; @@ -82,6 +79,7 @@ class WingEditorDialog : public QDialog, public SexpTreeEditorInterface { bool _cues_hidden = false; + void initializeUi(); void updateUi(); void enableOrDisableControls(); @@ -96,7 +94,6 @@ class WingEditorDialog : public QDialog, public SexpTreeEditorInterface { void refreshDepartureLocationCombo(); void refreshArrivalTargetCombo(); void refreshDepartureTargetCombo(); - void refreshAllDynamicCombos(); void updateLogoPreview(); };