From 744c9476be251351ff7d7a7ef75346ad67141925 Mon Sep 17 00:00:00 2001 From: The Force <2040992+TheForce172@users.noreply.github.com> Date: Wed, 22 May 2024 07:52:38 +0100 Subject: [PATCH 1/4] Add Weapons Dialog Move Ship Files To there own folder for legibility Set File stucture Create Layout Rough outline established Ship data fully loading limit multiselection to one type Add in missing conditon Add weaponlist loading and move Bank model to its own file Delete Missed file Fix Cmake file Change to size_ts Fix Arrivals Partial Drag and drop / better multi-select Finish drag and drop / add ammo editing Add Saving Feature Complete --- code/ship/ship.cpp | 25 ++ code/ship/ship.h | 2 + qtfred/source_groups.cmake | 11 + .../ShipEditor/ShipWeaponsDialogModel.cpp | 379 ++++++++++++++++ .../ShipEditor/ShipWeaponsDialogModel.h | 80 ++++ .../src/ui/dialogs/ShipEditor/BankModel.cpp | 405 ++++++++++++++++++ qtfred/src/ui/dialogs/ShipEditor/BankModel.h | 92 ++++ .../dialogs/ShipEditor/ShipEditorDialog.cpp | 3 +- .../ui/dialogs/ShipEditor/ShipEditorDialog.h | 1 + .../dialogs/ShipEditor/ShipWeaponsDialog.cpp | 136 ++++++ .../ui/dialogs/ShipEditor/ShipWeaponsDialog.h | 50 +++ qtfred/src/ui/widgets/bankTree.cpp | 105 +++++ qtfred/src/ui/widgets/bankTree.h | 24 ++ qtfred/src/ui/widgets/weaponList.cpp | 103 +++++ qtfred/src/ui/widgets/weaponList.h | 39 ++ qtfred/ui/ShipWeaponsDialog.ui | 216 ++++++++++ 16 files changed, 1670 insertions(+), 1 deletion(-) create mode 100644 qtfred/src/mission/dialogs/ShipEditor/ShipWeaponsDialogModel.cpp create mode 100644 qtfred/src/mission/dialogs/ShipEditor/ShipWeaponsDialogModel.h create mode 100644 qtfred/src/ui/dialogs/ShipEditor/BankModel.cpp create mode 100644 qtfred/src/ui/dialogs/ShipEditor/BankModel.h create mode 100644 qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.cpp create mode 100644 qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.h create mode 100644 qtfred/src/ui/widgets/bankTree.cpp create mode 100644 qtfred/src/ui/widgets/bankTree.h create mode 100644 qtfred/src/ui/widgets/weaponList.cpp create mode 100644 qtfred/src/ui/widgets/weaponList.h create mode 100644 qtfred/ui/ShipWeaponsDialog.ui diff --git a/code/ship/ship.cpp b/code/ship/ship.cpp index 8c150a6ad30..7f4d39c600a 100644 --- a/code/ship/ship.cpp +++ b/code/ship/ship.cpp @@ -17981,6 +17981,31 @@ int get_max_ammo_count_for_primary_bank(int ship_class, int bank, int ammo_type) return (int)std::lround(capacity / size); } +/** + * The same as above, but for a specific turret's bank. + */ +int get_max_ammo_count_for_primary_turret_bank(ship_weapon* swp, int bank, int ammo_type) +{ + float capacity, size; + + Assertion(bank < MAX_SHIP_PRIMARY_BANKS, + "Invalid primary bank of %d (max is %d); get a coder!\n", + bank, + MAX_SHIP_PRIMARY_BANKS - 1); + Assertion(ammo_type < weapon_info_size(), + "Invalid ammo_type of %d is >= Weapon_info.size() (%d); get a coder!\n", + ammo_type, + weapon_info_size()); + + if (!swp || bank < 0 || ammo_type < 0 || !(Weapon_info[ammo_type].wi_flags[Weapon::Info_Flags::Ballistic])) { + return 0; + } else { + capacity = (float)swp->primary_bank_capacity[bank]; + size = (float)Weapon_info[ammo_type].cargo_size; + return (int)(capacity / size); + } +} + /** * Determine the number of secondary ammo units (missile/bomb) allowed max for a ship */ diff --git a/code/ship/ship.h b/code/ship/ship.h index 077f6192013..a7a2b01b99d 100644 --- a/code/ship/ship.h +++ b/code/ship/ship.h @@ -1913,6 +1913,8 @@ float ship_get_secondary_weapon_range(ship *shipp); // Goober5000 int get_max_ammo_count_for_primary_bank(int ship_class, int bank, int ammo_type); +int get_max_ammo_count_for_primary_turret_bank(ship_weapon* swp, int bank, int ammo_type); + int get_max_ammo_count_for_bank(int ship_class, int bank, int ammo_type); int get_max_ammo_count_for_turret_bank(ship_weapon *swp, int bank, int ammo_type); diff --git a/qtfred/source_groups.cmake b/qtfred/source_groups.cmake index 8a00be0f7e2..0cd75f63b14 100644 --- a/qtfred/source_groups.cmake +++ b/qtfred/source_groups.cmake @@ -86,6 +86,8 @@ add_file_folder("Source/Mission/Dialogs/ShipEditor" src/mission/dialogs/ShipEditor/ShipTextureReplacementDialogModel.cpp src/mission/dialogs/ShipEditor/ShipTBLViewerModel.cpp src/mission/dialogs/ShipEditor/ShipTBLViewerModel.h + src/mission/dialogs/ShipEditor/ShipWeaponsDialogModel.cpp + src/mission/dialogs/ShipEditor/ShipWeaponsDialogModel.h ) add_file_folder("Source/UI" @@ -152,6 +154,10 @@ add_file_folder("Source/UI/Dialogs/ShipEditor" src/ui/dialogs/ShipEditor/ShipTextureReplacementDialog.cpp src/ui/dialogs/ShipEditor/ShipTBLViewer.h src/ui/dialogs/ShipEditor/ShipTBLViewer.cpp + src/ui/dialogs/ShipEditor/ShipWeaponsDialog.cpp + src/ui/dialogs/ShipEditor/ShipWeaponsDialog.h + src/ui/dialogs/ShipEditor/BankModel.cpp + src/ui/dialogs/ShipEditor/BankModel.h ) add_file_folder("Source/UI/Util" @@ -170,6 +176,10 @@ add_file_folder("Source/UI/Widgets" src/ui/widgets/sexp_tree.h src/ui/widgets/ShipFlagCheckbox.h src/ui/widgets/ShipFlagCheckbox.cpp + src/ui/widgets/weaponList.cpp + src/ui/widgets/weaponList.h + src/ui/widgets/BankTree.cpp + src/ui/widgets/BankTree.h ) add_file_folder("UI" @@ -201,6 +211,7 @@ add_file_folder("UI" ui/PlayerOrdersDialog.ui ui/ShipTextureReplacementDialog.ui ui/ShipTBLViewer.ui + ui/ShipWeaponsDialog.ui ) add_file_folder("Resources" diff --git a/qtfred/src/mission/dialogs/ShipEditor/ShipWeaponsDialogModel.cpp b/qtfred/src/mission/dialogs/ShipEditor/ShipWeaponsDialogModel.cpp new file mode 100644 index 00000000000..efad53ec636 --- /dev/null +++ b/qtfred/src/mission/dialogs/ShipEditor/ShipWeaponsDialogModel.cpp @@ -0,0 +1,379 @@ +#include "ShipWeaponsDialogModel.h" +namespace fso { +namespace fred { +Banks::Banks(const SCP_string& name, int aiIndex, int ship, int multiedit, ship_subsys* subsys) + : name(name), subsys(subsys), ship(ship), m_isMultiEdit(multiedit), initalAI(aiIndex) +{ + aiClass = aiIndex; +} +void Banks::add(Bank* bank) +{ + banks.push_back(bank); +} +Bank* Banks::getByBankId(const int id) +{ + for (auto bank : banks) { + if (id == bank->getWeaponId()) + return bank; + } + return nullptr; +} +SCP_string Banks::getName() const +{ + return name; +} +int Banks::getShip() const +{ + return ship; +} +ship_subsys* Banks::getSubsys() const +{ + return subsys; +} +bool Banks::empty() const +{ + return banks.empty(); +} +const SCP_vector Banks::getBanks() const +{ + return banks; +} +int Banks::getAiClass() const +{ + if (name == "Pilot") { + return Ships[ship].weapons.ai_class; + } else { + return subsys->weapons.ai_class; + } +} +void Banks::setAiClass(int newClass) +{ + if (m_isMultiEdit) { + object* ptr; + int inst; + ptr = GET_FIRST(&obj_used_list); + while (ptr != END_OF_LIST(&obj_used_list)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + inst = ptr->instance; + if (name == "Pilot") { + Ships[inst].ai_index = newClass; + } else { + subsys->weapons.ai_class = newClass; + } + } + } + } else { + if (name == "Pilot") { + Ships[ship].weapons.ai_class = newClass; + } else { + subsys->weapons.ai_class = newClass; + } + } +} +int Banks::getInitalAI() +{ + return initalAI; +} +Bank::Bank(const int weaponId, const int bankId, const int ammoMax, const int ammo, Banks* parent) +{ + this->weaponId = weaponId; + this->bankId = bankId; + this->ammo = ammo; + this->ammoMax = ammoMax; + this->parent = parent; +} +int Bank::getWeaponId() const +{ + return weaponId; +} +int Bank::getAmmo() const +{ + return ammo; +} +int Bank::getBankId() const +{ + return bankId; +} +int Bank::getMaxAmmo() const +{ + return ammoMax; +} +void Bank::setWeapon(const int id) +{ + weaponId = id; + if (Weapon_info[id].subtype == WP_LASER || Weapon_info[id].subtype == WP_BEAM) { + if (parent->getName() == "Pilot") { + ammoMax = get_max_ammo_count_for_primary_bank(parent->getShip(), bankId, id); + } else { + ammoMax = get_max_ammo_count_for_primary_turret_bank(&parent->getSubsys()->weapons, bankId, id); + } + } else { + if (parent->getName() == "Pilot") { + ammoMax = get_max_ammo_count_for_bank(parent->getShip(), bankId, id); + } else { + ammoMax = get_max_ammo_count_for_turret_bank(&parent->getSubsys()->weapons, bankId, id); + } + } +} +void Bank::setAmmo(const int newAmmo) +{ + this->ammo = newAmmo; +} +namespace dialogs { +ShipWeaponsDialogModel::ShipWeaponsDialogModel(QObject* parent, EditorViewport* viewport, bool isMultiEdit) + : AbstractDialogModel(parent, viewport) +{ + initializeData(isMultiEdit); +} +void ShipWeaponsDialogModel::initializeData(bool isMultiEdit) +{ + m_isMultiEdit = isMultiEdit; + PrimaryBanks.clear(); + SecondaryBanks.clear(); + int inst; + bool first = true; + object* ptr; + + m_ship = _editor->cur_ship; + if (m_ship == -1) + m_ship = Objects[_editor->currentObject].instance; + + if (m_isMultiEdit) { + ptr = GET_FIRST(&obj_used_list); + while (ptr != END_OF_LIST(&obj_used_list)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + inst = ptr->instance; + if (!(Ship_info[Ships[inst].ship_info_index].is_big_or_huge())) + big = 0; + initPrimary(inst, first); + initSecondary(inst, first); + // initTertiary(inst, first); + first = false; + } + } + } else { + if (!(Ship_info[Ships[m_ship].ship_info_index].is_big_or_huge())) + big = 0; + initPrimary(m_ship, true); + initSecondary(m_ship, true); + } +} + +void ShipWeaponsDialogModel::initPrimary(int inst, bool first) +{ + auto pilotBank = new Banks("Pilot", Ships[inst].weapons.ai_class, inst, m_isMultiEdit); + if (first) { + auto pilot = Ships[inst].weapons; + for (int i = 0; i < MAX_SHIP_PRIMARY_BANKS; i++) { + if (pilot.primary_bank_weapons[i] >= 0) { + const int maxAmmo = + get_max_ammo_count_for_primary_bank(Ships[inst].ship_info_index, i, pilot.primary_bank_weapons[i]); + const int ammo = fl2ir(pilot.primary_bank_ammo[i] * maxAmmo / 100.0f); + pilotBank->add(new Bank(pilot.primary_bank_weapons[i], i, maxAmmo, ammo, pilotBank)); + } + } + PrimaryBanks.push_back(pilotBank); + ship_subsys* ssl = &Ships[inst].subsys_list; + ship_subsys* pss; + for (pss = GET_FIRST(ssl); pss != END_OF_LIST(ssl); pss = GET_NEXT(pss)) { + model_subsystem* psub = pss->system_info; + if (psub->type == SUBSYSTEM_TURRET) { + auto turretBank = new Banks(psub->subobj_name, pss->weapons.ai_class, inst, m_isMultiEdit, pss); + for (int i = 0; i < MAX_SHIP_PRIMARY_BANKS; i++) { + if (pss->weapons.primary_bank_weapons[i] >= 0) { + const int maxAmmo = get_max_ammo_count_for_primary_turret_bank(&pss->weapons, + i, + pss->weapons.primary_bank_weapons[i]); + const int ammo = fl2ir(pss->weapons.primary_bank_ammo[i] * maxAmmo / 100.0f); + turretBank->add(new Bank(pss->weapons.primary_bank_weapons[i], i, maxAmmo, ammo, turretBank)); + } + } + if (!turretBank->empty()) { + PrimaryBanks.push_back(turretBank); + } else { + delete turretBank; + } + } + } + } else { + for (int i = 0; i < MAX_SHIP_PRIMARY_BANKS; i++) { + if (PrimaryBanks[0]->getByBankId(i)->getWeaponId() != Ships[inst].weapons.primary_bank_weapons[i]) { + PrimaryBanks[0]->getByBankId(i)->setWeapon(-2); + } + if (PrimaryBanks[0]->getByBankId(i)->getAmmo() != Ships[inst].weapons.primary_bank_ammo[i]) { + PrimaryBanks[0]->getByBankId(i)->setAmmo(-2); + } + } + ship_subsys* ssl = &Ships[inst].subsys_list; + ship_subsys* pss; + for (pss = GET_FIRST(ssl); pss != END_OF_LIST(ssl); pss = GET_NEXT(pss)) { + model_subsystem* psub = pss->system_info; + if (psub->type == SUBSYSTEM_TURRET) { + for (auto banks : PrimaryBanks) { + if (banks->getSubsys() == pss) { + for (int i = 0; i < MAX_SHIP_PRIMARY_BANKS; i++) { + if (banks->getByBankId(i)->getWeaponId() != pss->weapons.primary_bank_weapons[i]) { + banks->getByBankId(i)->setWeapon(-2); + } + if (banks->getByBankId(i)->getAmmo() != pss->weapons.primary_bank_ammo[i]) { + banks->getByBankId(i)->setAmmo(-2); + } + } + } + } + } + } + } +} + +void ShipWeaponsDialogModel::initSecondary(int inst, bool first) +{ + auto pilotBank = new Banks("Pilot", Ships[inst].weapons.ai_class, inst, m_isMultiEdit); + if (first) { + auto pilot = Ships[inst].weapons; + for (int i = 0; i < MAX_SHIP_SECONDARY_BANKS; i++) { + if (pilot.secondary_bank_weapons[i] >= 0) { + const int maxAmmo = + get_max_ammo_count_for_bank(Ships[inst].ship_info_index, i, pilot.secondary_bank_weapons[i]); + const int ammo = fl2ir(pilot.secondary_bank_ammo[i] * maxAmmo / 100.0f); + pilotBank->add(new Bank(pilot.secondary_bank_weapons[i], i, maxAmmo, ammo, pilotBank)); + } + } + SecondaryBanks.push_back(pilotBank); + ship_subsys* ssl = &Ships[inst].subsys_list; + ship_subsys* pss; + for (pss = GET_FIRST(ssl); pss != END_OF_LIST(ssl); pss = GET_NEXT(pss)) { + model_subsystem* psub = pss->system_info; + if (psub->type == SUBSYSTEM_TURRET) { + auto turretBank = new Banks(psub->subobj_name, pss->weapons.ai_class, inst, m_isMultiEdit, pss); + for (int i = 0; i < MAX_SHIP_SECONDARY_BANKS; i++) { + if (pss->weapons.secondary_bank_weapons[i] >= 0) { + const int maxAmmo = get_max_ammo_count_for_turret_bank(&pss->weapons, + i, + pss->weapons.secondary_bank_weapons[i]); + const int ammo = fl2ir(pss->weapons.secondary_bank_ammo[i] * maxAmmo / 100.0f); + turretBank->add(new Bank(pss->weapons.secondary_bank_weapons[i], i, maxAmmo, ammo, turretBank)); + } + } + if (!turretBank->empty()) { + SecondaryBanks.push_back(turretBank); + } else { + delete turretBank; + } + } + } + } else { + for (int i = 0; i < MAX_SHIP_SECONDARY_BANKS; i++) { + if (SecondaryBanks[0]->getByBankId(i)->getWeaponId() != Ships[inst].weapons.secondary_bank_weapons[i]) { + SecondaryBanks[0]->getByBankId(i)->setWeapon(-2); + } + if (SecondaryBanks[0]->getByBankId(i)->getAmmo() != Ships[inst].weapons.secondary_bank_ammo[i]) { + SecondaryBanks[0]->getByBankId(i)->setAmmo(-2); + } + } + ship_subsys* ssl = &Ships[inst].subsys_list; + ship_subsys* pss; + for (pss = GET_FIRST(ssl); pss != END_OF_LIST(ssl); pss = GET_NEXT(pss)) { + model_subsystem* psub = pss->system_info; + if (psub->type == SUBSYSTEM_TURRET) { + for (auto banks : SecondaryBanks) { + if (banks->getSubsys() == pss) { + for (int i = 0; i < MAX_SHIP_SECONDARY_BANKS; i++) { + if (banks->getByBankId(i)->getWeaponId() != pss->weapons.secondary_bank_weapons[i]) { + banks->getByBankId(i)->setWeapon(-2); + } + if (banks->getByBankId(i)->getAmmo() != pss->weapons.secondary_bank_ammo[i]) { + banks->getByBankId(i)->setAmmo(-2); + } + } + } + } + } + } + } +} +void ShipWeaponsDialogModel::saveShip(int inst) +{ + for (auto Turret : PrimaryBanks) { + if (Turret->getName() == "Pilot") { + for (auto bank : Turret->getBanks()) { + if (bank->getWeaponId() != -2) { + Ships[inst].weapons.primary_bank_weapons[bank->getBankId()] = bank->getWeaponId(); + Ships[inst].weapons.primary_bank_ammo[bank->getBankId()] = + bank->getMaxAmmo() ? fl2ir(bank->getAmmo() * 100.0f / bank->getMaxAmmo()) : 0; + } + } + } else { + ship_subsys* pss = Turret->getSubsys(); + for (auto bank : Turret->getBanks()) { + if (bank->getWeaponId() != -2) { + pss->weapons.primary_bank_weapons[bank->getBankId()] = bank->getWeaponId(); + pss->weapons.primary_bank_ammo[bank->getBankId()] = + bank->getMaxAmmo() ? fl2ir(bank->getAmmo() * 100.0f / bank->getMaxAmmo()) : 0; + } + } + } + } + for (auto Turret : SecondaryBanks) { + if (Turret->getName() == "Pilot") { + for (auto bank : Turret->getBanks()) { + if (bank->getWeaponId() != -2) { + Ships[inst].weapons.secondary_bank_weapons[bank->getBankId()] = bank->getWeaponId(); + Ships[inst].weapons.secondary_bank_ammo[bank->getBankId()] = + bank->getMaxAmmo() ? fl2ir(bank->getAmmo() * 100.0f / bank->getMaxAmmo()) : 0; + } + } + } else { + ship_subsys* pss = Turret->getSubsys(); + for (auto bank : Turret->getBanks()) { + if (bank->getWeaponId() != -2) { + pss->weapons.secondary_bank_weapons[bank->getBankId()] = bank->getWeaponId(); + pss->weapons.secondary_bank_ammo[bank->getBankId()] = + bank->getMaxAmmo() ? fl2ir(bank->getAmmo() * 100.0f / bank->getMaxAmmo()) : 0; + } + } + } + } +} +bool ShipWeaponsDialogModel::apply() +{ + if (m_isMultiEdit) { + object* ptr; + int inst; + ptr = GET_FIRST(&obj_used_list); + while (ptr != END_OF_LIST(&obj_used_list)) { + if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) { + inst = ptr->instance; + saveShip(inst); + } + } + } else { + saveShip(m_ship); + } + _editor->missionChanged(); + return true; +} +void ShipWeaponsDialogModel::reject() +{ + for (auto Turret : PrimaryBanks) { + Turret->setAiClass(Turret->getInitalAI()); + } + for (auto Turret : SecondaryBanks) { + Turret->setAiClass(Turret->getInitalAI()); + } +} +SCP_vector ShipWeaponsDialogModel::getPrimaryBanks() const +{ + return PrimaryBanks; +} +SCP_vector ShipWeaponsDialogModel::getSecondaryBanks() const +{ + return SecondaryBanks; +} +/* void ShipWeaponsDialogModel::initTertiary(int inst, bool first) { + +} +*/ +} // namespace dialogs +} // namespace fred +} // namespace fso \ No newline at end of file diff --git a/qtfred/src/mission/dialogs/ShipEditor/ShipWeaponsDialogModel.h b/qtfred/src/mission/dialogs/ShipEditor/ShipWeaponsDialogModel.h new file mode 100644 index 00000000000..37adbb4dd89 --- /dev/null +++ b/qtfred/src/mission/dialogs/ShipEditor/ShipWeaponsDialogModel.h @@ -0,0 +1,80 @@ +#pragma once + +#include "../AbstractDialogModel.h" + +#include + +namespace fso { +namespace fred { +struct Bank; +struct Banks { + Banks(const SCP_string& name, int aiIndex, int ship,int multiedit, ship_subsys* subsys = nullptr); + + public: + void add(Bank*); + Bank* getByBankId(const int id); + SCP_string getName() const; + int getShip() const; + ship_subsys* getSubsys() const; + bool empty() const; + const SCP_vector getBanks() const; + int getAiClass() const; + void setAiClass(int); + bool m_isMultiEdit; + int getInitalAI(); + private: + SCP_string name; + ship_subsys* subsys; + int aiClass; + int initalAI; + SCP_vector banks; + int ship; +}; +struct Bank { + public: + Bank(const int weaponId, const int bankId, const int ammoMax, const int ammo, Banks* parent); + + int getWeaponId() const; + int getAmmo() const; + int getBankId() const; + int getMaxAmmo() const; + + void setWeapon(const int id); + void setAmmo(const int ammo); + + private: + int weaponId; + int bankId; + int ammo; + int ammoMax; + Banks* parent; +}; +namespace dialogs { +class ShipWeaponsDialogModel : public AbstractDialogModel { + public: + ShipWeaponsDialogModel(QObject* parent, EditorViewport* viewport, bool multi); + + // void initTertiary(int inst, bool first); + + bool apply() override; + void reject() override; + SCP_vector getPrimaryBanks() const; + SCP_vector getSecondaryBanks() const; + // SCP_vector getTertiaryBanks() const; + + private: + void saveShip(int inst); + void initPrimary(const int inst, bool first); + + void initSecondary(int inst, bool first); + void initializeData(bool multi); + int m_isMultiEdit; + int m_ship; + int big = 1; + SCP_vector PrimaryBanks; + SCP_vector SecondaryBanks; + // SCP_vector TertiaryBanks; +}; +} // namespace dialogs +} // namespace fred +} // namespace fso \ No newline at end of file diff --git a/qtfred/src/ui/dialogs/ShipEditor/BankModel.cpp b/qtfred/src/ui/dialogs/ShipEditor/BankModel.cpp new file mode 100644 index 00000000000..87e72d0e9f5 --- /dev/null +++ b/qtfred/src/ui/dialogs/ShipEditor/BankModel.cpp @@ -0,0 +1,405 @@ +#include "ShipWeaponsDialog.h" + +#include +#include +namespace fso { +namespace fred { +BankTreeItem::BankTreeItem(BankTreeItem* parentItem) : m_parentItem(parentItem) {} +BankTreeItem::~BankTreeItem() +{ + qDeleteAll(m_childItems); +} +void BankTreeItem::appendChild(BankTreeItem* item) +{ + m_childItems.append(item); +} +BankTreeItem* BankTreeItem::child(int row) const +{ + if (row < 0 || row >= m_childItems.size()) + return nullptr; + return m_childItems.at(row); +} +int BankTreeItem::childCount() const +{ + return m_childItems.count(); +} +int BankTreeItem::childNumber() const +{ + if (m_parentItem) + return m_parentItem->m_childItems.indexOf(const_cast(this)); + return 0; +} +BankTreeItem* BankTreeItem::parentItem() +{ + return m_parentItem; +} + +bool BankTreeItem::insertLabel(int position, const QString& newName, Banks* newBanks) +{ + if (position < 0 || position > m_childItems.size()) + return false; + + auto* item = new BankTreeLabel(newName, newBanks, this); + m_childItems.insert(position, item); + + return true; +} + +bool BankTreeItem::insertBank(int position, Bank* newBank) +{ + if (position < 0 || position > m_childItems.size()) + return false; + + auto* item = new BankTreeBank(newBank, this); + m_childItems.insert(position, item); + + return true; +} + +QString BankTreeItem::getName() const +{ + return name; +} + +int BankTreeBank::getId() const +{ + return bank->getWeaponId(); +} + +BankTreeBank::BankTreeBank(Bank* bank, BankTreeItem* parentItem) : BankTreeItem(parentItem) +{ + this->bank = bank; + switch (bank->getWeaponId()) { + case -2: + this->name = "CONFLICT"; + break; + case -1: + this->name = "None"; + break; + default: + this->name = Weapon_info[bank->getWeaponId()].name; + } +} + +QVariant BankTreeBank::data(int column) const +{ + switch (column) { + case 0: + return name; + break; + case 1: + return bank->getAmmo(); + break; + default: + return {}; + } +} + +Qt::ItemFlags BankTreeBank::getFlags(int column) const +{ + switch (column) { + case 0: + return Qt::ItemIsDropEnabled | Qt::ItemIsSelectable; + break; + case 1: + return Qt::ItemIsEditable; + break; + default: + return {}; + } +} + +void BankTreeBank::setWeapon(int id) +{ + bank->setWeapon(id); + if (id == -1) { + name = "None"; + } else { + name = Weapon_info[id].name; + } +} + +void BankTreeBank::setAmmo(int value) +{ + Assert(bank != nullptr); + bank->setAmmo(value); +} + +BankTreeLabel::BankTreeLabel(const QString& name, Banks* banks, BankTreeItem* parentItem) : BankTreeItem(parentItem) +{ + this->name = name; + this->banks = banks; +} + +QVariant BankTreeLabel::data(int column) const +{ + switch (column) { + case 0: + return name + " (" + Ai_class_names[banks->getAiClass()] + + ")"; + break; + default: + return {}; + } +} + +Qt::ItemFlags BankTreeLabel::getFlags(int column) const +{ + return Qt::ItemIsSelectable; +} + +void BankTreeLabel::setAIClass(int value) +{ + Assert(banks != nullptr); + banks->setAiClass(value); +} + +bool BankTreeLabel::setData(int column, const QVariant& value) +{ + setAIClass(value.toInt()); + return true; +} + +bool BankTreeBank::setData(int column, const QVariant& value) +{ + switch (column) { + case 1: + setAmmo(value.toInt()); + return true; + break; + default: + return false; + } +} +BankTreeModel::BankTreeModel(const SCP_vector& data, QObject* parent) : QAbstractItemModel(parent) +{ + rootItem = new BankTreeRoot(); + + setupModelData(data, rootItem); +} + +void BankTreeModel::setupModelData(const SCP_vector& data, BankTreeItem* parent) +{ + for (auto banks : data) { + parent->insertLabel(parent->childCount(), banks->getName().c_str(), banks); + BankTreeItem* currentParent = parent->child(parent->childCount() - 1); + for (auto bank : banks->getBanks()) { + currentParent->insertBank(currentParent->childCount(), bank); + } + } +} + +QVariant BankTreeModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role == Qt::DisplayRole) { + switch (section) { + case 0: + return tr("Bank Name/Weapon"); + case 1: + return tr("Ammo"); + default: + return QString(""); + } + } + return {}; +} + +BankTreeModel::~BankTreeModel() +{ + delete rootItem; +} + +int BankTreeModel::columnCount(const QModelIndex& parent) const +{ + Q_UNUSED(parent); + return 2; +} + +QVariant BankTreeModel::data(const QModelIndex& index, int role) const +{ + if (!index.isValid()) { + return {}; + } + + if (role != Qt::DisplayRole && role != Qt::EditRole) + return {}; + + BankTreeItem* item = getItem(index); + + return item->data(index.column()); +} + +BankTreeItem* BankTreeModel::getItem(const QModelIndex index) const +{ + if (index.isValid()) { + auto* item = static_cast(index.internalPointer()); + if (item) + return item; + } + return rootItem; +} + +bool BankTreeModel::setData(const QModelIndex& index, const QVariant& value, int role) +{ + if (role != Qt::EditRole) + return false; + + BankTreeItem* item = getItem(index); // getItem(index); + if (!item) { + return false; + } + bool result = item->setData(index.column(), value); + + return result; +} + +int BankTreeModel::rowCount(const QModelIndex& parent) const +{ + if (parent.isValid() && parent.column() > 0) + return 0; + + const BankTreeItem* parentItem = getItem(parent); + + return parentItem ? parentItem->childCount() : 0; +} + +Qt::ItemFlags BankTreeModel::flags(const QModelIndex& index) const +{ + Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index); + defaultFlags.setFlag(Qt::ItemIsSelectable, false); + + if (index.isValid()) { + auto* item = static_cast(index.internalPointer()); + return item->getFlags(index.column()) | defaultFlags; + } else { + return Qt::NoItemFlags; + } +} + +QModelIndex BankTreeModel::index(int row, int column, const QModelIndex& parent) const +{ + if (parent.isValid() && parent.column() != 0) + return {}; + + BankTreeItem* parentItem = getItem(parent); + if (!parentItem) + return {}; + + BankTreeItem* childItem = parentItem->child(row); + if (childItem) + return createIndex(row, column, childItem); + return {}; +} +QModelIndex BankTreeModel::parent(const QModelIndex& index) const +{ + if (!index.isValid()) + return {}; + BankTreeItem* childItem = getItem(index); + BankTreeItem* parentItem = childItem ? childItem->parentItem() : nullptr; + + if (parentItem == rootItem || !parentItem) + return {}; + return createIndex(parentItem->childNumber(), 0, parentItem); +} +QStringList BankTreeModel::mimeTypes() const +{ + QStringList types; + types << "application/weaponid"; + return types; +} + +bool BankTreeModel::canDropMimeData(const QMimeData* data, + Qt::DropAction action, + int row, + int column, + const QModelIndex& parent) const +{ + Q_UNUSED(action); + Q_UNUSED(row); + Q_UNUSED(parent); + + if (!data->hasFormat("application/weaponid")) + return false; + BankTreeItem* item = this->getItem(parent); + Qt::ItemFlags flags = item->getFlags(column); + return flags.testFlag(Qt::ItemIsDropEnabled); +} +bool BankTreeModel::dropMimeData(const QMimeData* data, + Qt::DropAction action, + int row, + int column, + const QModelIndex& parent) +{ + if (!canDropMimeData(data, action, row, column, parent)) + return false; + + if (action == Qt::IgnoreAction) + return true; + + int beginRow; + + if (row != -1) + beginRow = row; + else if (parent.isValid()) + beginRow = parent.row(); + else + return false; + + QByteArray encodedData = data->data("application/weaponid"); + QDataStream stream(&encodedData, QIODevice::ReadOnly); + while (!stream.atEnd()) { + int id = 0; + stream >> id; + setWeapon(parent, id); + } + return true; +} + +void BankTreeModel::setWeapon(const QModelIndex& index, int data) const +{ + auto item = dynamic_cast(this->getItem(index)); + Assert(item != nullptr); + if (item != nullptr) { + item->setWeapon(data); + } +} + +bool BankTreeRoot::setData(int column, const QVariant& value) +{ + return false; +} +QVariant BankTreeRoot::data(int column) const +{ + switch (column) { + case 0: + return "Name/Weapon"; + break; + case 1: + return "Ammo"; + break; + default: + return {}; + } +} +Qt::ItemFlags BankTreeRoot::getFlags(int column) const +{ + return {}; +} + +int BankTreeModel::checktype(const QModelIndex index) const +{ + int type; + BankTreeItem* item = getItem(index); + auto bankTest = dynamic_cast(item); + auto labelTest = dynamic_cast(item); + if (bankTest) { + type = 0; + } else if (labelTest) { + type = 1; + } else { + type = -1; + } + return type; +} +} // namespace fred +} // namespace fso \ No newline at end of file diff --git a/qtfred/src/ui/dialogs/ShipEditor/BankModel.h b/qtfred/src/ui/dialogs/ShipEditor/BankModel.h new file mode 100644 index 00000000000..df912ae5f6b --- /dev/null +++ b/qtfred/src/ui/dialogs/ShipEditor/BankModel.h @@ -0,0 +1,92 @@ +#pragma once +#include "mission/dialogs/ShipEditor/ShipWeaponsDialogModel.h" +#include +namespace fso { +namespace fred { +class BankTreeItem { + public: + explicit BankTreeItem(BankTreeItem* parentItem = nullptr); + virtual ~BankTreeItem(); + virtual QVariant data(int column) const = 0; + void appendChild(BankTreeItem* child); + BankTreeItem* child(int row) const; + int childCount() const; + int childNumber() const; + BankTreeItem* parentItem(); + bool insertLabel(int position, const QString& name, Banks* banks); + bool insertBank(int position, Bank* banks); + + QString getName() const; + virtual bool setData(int column, const QVariant& value) = 0; + virtual Qt::ItemFlags getFlags(int column) const = 0; + QList m_childItems; + + protected: + QString name; + + private: + BankTreeItem* m_parentItem; +}; +class BankTreeRoot : public BankTreeItem { + bool setData(int column, const QVariant& value) override; + QVariant data(int column) const override; + Qt::ItemFlags getFlags(int column) const override; +}; +class BankTreeBank : public BankTreeItem { + public: + explicit BankTreeBank(Bank* bank, BankTreeItem* parentItem = nullptr); + void setWeapon(int id); + void setAmmo(int value); + int getId() const; + bool setData(int column, const QVariant& value) override; + QVariant data(int column) const override; + Qt::ItemFlags getFlags(int column) const override; + + private: + Bank* bank; +}; +class BankTreeLabel : public BankTreeItem { + public: + explicit BankTreeLabel(const QString& name, Banks* banks, BankTreeItem* parentItem = nullptr); + void setAIClass(int value); + bool setData(int column, const QVariant& value) override; + QVariant data(int column) const override; + Qt::ItemFlags getFlags(int column) const override; + + private: + Banks* banks; +}; + +class BankTreeModel : public QAbstractItemModel { + Q_OBJECT + public: + BankTreeModel(const SCP_vector& data, QObject* parent = nullptr); + ~BankTreeModel() override; + int columnCount(const QModelIndex& parent) const override; + QVariant data(const QModelIndex& index, int role) const override; + + QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex& index) const override; + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + + Qt::ItemFlags flags(const QModelIndex& index) const override; + + QStringList mimeTypes() const override; + bool + canDropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) const; + bool + dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) override; + void setWeapon(const QModelIndex& index, int data) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + + bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; + int checktype(const QModelIndex index) const; + + private: + BankTreeItem* rootItem; + BankTreeItem* getItem(const QModelIndex index) const; + static void setupModelData(const SCP_vector& data, BankTreeItem* parent); +}; +} // namespace fred +} // namespace fso \ No newline at end of file diff --git a/qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.cpp b/qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.cpp index 2ec6512a3ed..fb4e700b96a 100644 --- a/qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.cpp +++ b/qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.cpp @@ -826,7 +826,8 @@ void ShipEditorDialog::on_deleteButton_clicked() } void ShipEditorDialog::on_weaponsButton_clicked() { - //TODO + auto weaponsDialog = new dialogs::ShipWeaponsDialog(this, _viewport, getIfMultipleShips()); + weaponsDialog->show(); } void ShipEditorDialog::on_playerOrdersButton_clicked() { diff --git a/qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.h b/qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.h index 773e9b2665b..584af3a3a3c 100644 --- a/qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.h +++ b/qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.h @@ -11,6 +11,7 @@ #include "ShipSpecialStatsDialog.h" #include "ShipTextureReplacementDialog.h" #include "ShipTBLViewer.h" +#include "ShipWeaponsDialog.h" #include #include diff --git a/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.cpp b/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.cpp new file mode 100644 index 00000000000..d19a4d2210c --- /dev/null +++ b/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.cpp @@ -0,0 +1,136 @@ +#include "ShipWeaponsDialog.h" + +#include "ui_ShipWeaponsDialog.h" + +#include +#include + +#include +#include +namespace fso { +namespace fred { +namespace dialogs { +ShipWeaponsDialog::ShipWeaponsDialog(QDialog* parent, EditorViewport* viewport, bool isMultiEdit) + : QDialog(parent), ui(new Ui::ShipWeaponsDialog()), _model(new ShipWeaponsDialogModel(this, viewport, isMultiEdit)), + _viewport(viewport) +{ + ui->setupUi(this); + + connect(ui->radioPrimary, &QRadioButton::toggled, this, [this](bool param) { modeChanged(param, 0); }); + connect(ui->radioSecondary, &QRadioButton::toggled, this, [this](bool param) { modeChanged(param, 1); }); + connect(ui->radioTertiary, &QRadioButton::toggled, this, [this](bool param) { modeChanged(param, 2); }); + + + connect(this, &QDialog::accepted, _model.get(), &ShipWeaponsDialogModel::apply); + if (!_model->getPrimaryBanks().empty()) { + const util::SignalBlockers blockers(this); + bankModel = new BankTreeModel(_model->getPrimaryBanks(), this); + ui->radioPrimary->setChecked(true); + dialogMode = 0; + weapons = new WeaponModel(0); + } else if (!_model->getSecondaryBanks().empty()) { + const util::SignalBlockers blockers(this); + bankModel = new BankTreeModel(_model->getSecondaryBanks(), this); + ui->radioSecondary->setChecked(true); + dialogMode = 1; + weapons = new WeaponModel(1); + } else { + Error("No Valid Weapon banks on ship"); + } + ui->treeBanks->setModel(bankModel); + connect(ui->treeBanks->selectionModel(), + &QItemSelectionModel::selectionChanged, + this, + &ShipWeaponsDialog::updateUI); + connect(ui->AICombo, + static_cast(&QComboBox::currentIndexChanged), + this, + &ShipWeaponsDialog::aiClassChanged); + ui->listWeapons->setModel(weapons); + ui->treeBanks->expandAll(); + ui->treeBanks->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + updateUI(); +} + +ShipWeaponsDialog::~ShipWeaponsDialog() { + delete bankModel; + delete weapons; +} + +void ShipWeaponsDialog::closeEvent(QCloseEvent* event) +{ + accept(); + QDialog::closeEvent(event); +} +void ShipWeaponsDialog::on_setAllButton_clicked() +{ + int test = 0; + for (auto& index : ui->treeBanks->selectionModel()->selectedIndexes()) { + bankModel->setWeapon(index, ui->listWeapons->currentIndex().data(Qt::UserRole).toInt()); + } +} +void ShipWeaponsDialog::modeChanged(const bool enabled, const int mode) +{ + if (enabled) { + if (mode == 0) { + bankModel = new BankTreeModel(_model->getPrimaryBanks(), this); + dialogMode = 0; + } else if (mode == 1) { + bankModel = new BankTreeModel(_model->getSecondaryBanks(), this); + dialogMode = 1; + } else if (mode == 2) { + // bankModel = new BankTreeModel(_model->getTertiaryBanks(), this); + dialogMode = 2; + } else { + _viewport->dialogProvider->showButtonDialog(DialogType::Error, + "Illegal Mode", + "Somehow an Illegal mode has been set. Get a coder.\n Illegal mode is " + mode, + {DialogButton::Ok}); + ui->radioPrimary->toggled(true); + bankModel = new BankTreeModel(_model->getPrimaryBanks(), this); + dialogMode = 0; + } + ui->treeBanks->setModel(bankModel); + ui->treeBanks->expandAll(); + } + updateUI(); +} +void ShipWeaponsDialog::updateUI() +{ + const util::SignalBlockers blockers(this); + ui->radioPrimary->setEnabled(!_model->getPrimaryBanks().empty()); + ui->radioSecondary->setEnabled(!_model->getSecondaryBanks().empty()); + ui->radioTertiary->setEnabled(false); + ui->treeBanks->expandAll(); + + if (ui->treeBanks->getTypeSelected() == 0) { + ui->setAllButton->setEnabled(true); + } else { + ui->setAllButton->setEnabled(false); + } + + if (ui->treeBanks->getTypeSelected() == 1) { + ui->AIButton->setEnabled(true); + } else { + ui->AIButton->setEnabled(false); + } + ui->AICombo->clear(); + for (int i = 0; i < Num_ai_classes; i++) { + ui->AICombo->addItem(Ai_class_names[i], QVariant(i)); + } + ui->AICombo->setCurrentIndex(ui->AICombo->findData(m_currentAI)); +} + +void ShipWeaponsDialog::aiClassChanged(const int index) { + m_currentAI = ui->AICombo->itemData(index).toInt(); +} + +void ShipWeaponsDialog::on_AIButton_clicked() { + for (auto& index : ui->treeBanks->selectionModel()->selectedIndexes()) { + bankModel->setData(index, m_currentAI); + } +} + +} // namespace dialogs +} // namespace fred +} // namespace fso \ No newline at end of file diff --git a/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.h b/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.h new file mode 100644 index 00000000000..90168a8ea72 --- /dev/null +++ b/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.h @@ -0,0 +1,50 @@ +#ifndef SHIPWEAPONSDIALOG_H +#define SHIPWEAPONSDIALOG_H + +#include "ui/dialogs/ShipEditor/BankModel.h" +#include "ui/widgets/weaponList.h" + +#include +#include + +#include +#include + +namespace fso { +namespace fred { +namespace dialogs { + +namespace Ui { +class ShipWeaponsDialog; +} + +class ShipWeaponsDialog : public QDialog { + Q_OBJECT + + public: + explicit ShipWeaponsDialog(QDialog* parent, EditorViewport* viewport, bool isMultiEdit); + ~ShipWeaponsDialog() override; + + protected: + void closeEvent(QCloseEvent*) override; + + private slots: + void on_AIButton_clicked(); + void on_setAllButton_clicked(); + + private: + std::unique_ptr ui; + std::unique_ptr _model; + void modeChanged(const bool enabled, const int mode); + EditorViewport* _viewport; + void updateUI(); + BankTreeModel* bankModel; + int dialogMode; + WeaponModel* weapons; + int m_currentAI = 0; + void aiClassChanged(const int index); +}; +} // namespace dialogs +} // namespace fred +} // namespace fso +#endif \ No newline at end of file diff --git a/qtfred/src/ui/widgets/bankTree.cpp b/qtfred/src/ui/widgets/bankTree.cpp new file mode 100644 index 00000000000..c61a0ec58d3 --- /dev/null +++ b/qtfred/src/ui/widgets/bankTree.cpp @@ -0,0 +1,105 @@ +#include "bankTree.h" +namespace fso { +namespace fred { +bankTree::bankTree(QWidget* parent) : QTreeView(parent) +{ + setAcceptDrops(true); +} +void bankTree::dragEnterEvent(QDragEnterEvent* event) +{ + if (event->mimeData()->hasFormat("application/weaponid")) { + event->acceptProposedAction(); + } +} +void bankTree::dropEvent(QDropEvent* event) +{ + auto item = indexAt(event->pos()); + if (!item.isValid()) { + return; + } + bool accepted = model()->dropMimeData(event->mimeData(), Qt::CopyAction, -1, 0, item); + if (accepted) { + event->acceptProposedAction(); + } +} +void bankTree::dragMoveEvent(QDragMoveEvent* event) +{ + auto pos = QCursor::pos(); + auto index = indexAt(pos); + if (!index.isValid()) { + return; + } + if (dynamic_cast(model())->checktype(index) == 0) { + event->accept(); + } else { + event->ignore(); + } +} +void bankTree::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected) +{ + QItemSelection newlySelected; + QItemSelection select; + QItemSelection deselect(deselected); + if (selected.empty()) { + QTreeView::selectionChanged(selected, deselected); + if (selectionModel()->selectedIndexes().size() == 0) { + typeSelected = -1; + } + return; + } + for (auto& sidx : selected.indexes()) { + bool match = false; + for (auto& didx : deselected.indexes()) { + if (sidx == didx) { + match = true; + break; + } + } + if (!match) { + QItemSelectionRange selection(sidx); + newlySelected.append(selection); + } + } + if (!newlySelected.empty()) { + if (typeSelected == -1) { + typeSelected = dynamic_cast(model())->checktype(newlySelected.indexes().first()); + for (auto& sidx : newlySelected.indexes()) { + if (dynamic_cast(model())->checktype(sidx) == typeSelected) { + QItemSelectionRange selection(sidx); + select.append(selection); + } + } + } else { + int type = dynamic_cast(model())->checktype(newlySelected.indexes().first()); + if (type != typeSelected) { + typeSelected = type; + for (auto& sidx : selected.indexes()) { + QItemSelectionRange selection(sidx); + deselect.append(selection); + } + for (auto& sidx : newlySelected.indexes()) { + if (dynamic_cast(model())->checktype(sidx) == typeSelected) { + QItemSelectionRange selection(sidx); + select.append(selection); + } + } + selectionModel()->clear(); + typeSelected = -1; + } else { + for (auto& sidx : newlySelected.indexes()) { + if (dynamic_cast(model())->checktype(sidx) == typeSelected) { + QItemSelectionRange selection(sidx); + select.append(selection); + } + } + } + } + } + QTreeView::selectionChanged(select, deselect); +} +int bankTree::getTypeSelected() const +{ + return typeSelected; +} +} // namespace fred +} // namespace fso \ No newline at end of file diff --git a/qtfred/src/ui/widgets/bankTree.h b/qtfred/src/ui/widgets/bankTree.h new file mode 100644 index 00000000000..7a445ca89bc --- /dev/null +++ b/qtfred/src/ui/widgets/bankTree.h @@ -0,0 +1,24 @@ +#pragma once +#include +#include +#include +#include +#include +#include "ui/dialogs/ShipEditor/BankModel.h" +#include +namespace fso { +namespace fred { +class bankTree : public QTreeView { + Q_OBJECT + public: + bankTree(QWidget*); + void selectionChanged(const QItemSelection& selected, const QItemSelection& deselected); + int getTypeSelected() const; + protected: + void dragEnterEvent(QDragEnterEvent*); + void dropEvent(QDropEvent* event); + void dragMoveEvent(QDragMoveEvent*); + int typeSelected = -1; +}; +} // namespace fred +} // namespace fso \ No newline at end of file diff --git a/qtfred/src/ui/widgets/weaponList.cpp b/qtfred/src/ui/widgets/weaponList.cpp new file mode 100644 index 00000000000..3f67af99348 --- /dev/null +++ b/qtfred/src/ui/widgets/weaponList.cpp @@ -0,0 +1,103 @@ +#include "weaponList.h" + +namespace fso { +namespace fred { +weaponList::weaponList(QWidget* parent) : QListView(parent) {} + +void weaponList::mousePressEvent(QMouseEvent* event) +{ + if (event->button() == Qt::LeftButton) + dragStartPosition = event->pos(); + QListView::mousePressEvent(event); +} +void weaponList::mouseMoveEvent(QMouseEvent* event) +{ + if (!(event->buttons() & Qt::LeftButton)) + return; + if ((event->pos() - dragStartPosition).manhattanLength() < QApplication::startDragDistance()) + return; + QModelIndex idx = currentIndex(); + if (!idx.isValid()) { + return; + } + QDrag* drag = new QDrag(this); + QModelIndexList idxs; + idxs.append(idx); + QMimeData* mimeData = model()->mimeData(idxs); + QPixmap* iconPixmap = new QPixmap(); + QPainter painter(iconPixmap); + painter.setFont(QFont("Arial")); + painter.drawText(QPoint(100, 100), model()->data(idx, Qt::DisplayRole).toString()); + drag->setPixmap(*iconPixmap); + drag->setMimeData(mimeData); + Qt::DropAction dropAction = drag->exec(); +} + +WeaponModel::WeaponModel(int type) +{ + auto noWeapon = new WeaponItem(-1, "None"); + weapons.push_back(noWeapon); + if (type == 0) { + for (int i = 0; i < static_cast(Weapon_info.size()); i++) { + const auto& w = Weapon_info[i]; + if (w.subtype == WP_LASER || w.subtype == WP_BEAM) { + if (!w.wi_flags[Weapon::Info_Flags::No_fred]) { + auto newWeapon = new WeaponItem(i, w.name); + weapons.push_back(newWeapon); + } + } + } + } else if (type == 1) { + for (int i = 0; i < static_cast(Weapon_info.size()); i++) { + const auto& w = Weapon_info[i]; + if (w.subtype == WP_MISSILE) { + if (!w.wi_flags[Weapon::Info_Flags::No_fred]) { + auto newWeapon = new WeaponItem(i, w.name); + weapons.push_back(newWeapon); + } + } + } + } +} +WeaponModel::~WeaponModel() +{ + for (auto pointer : weapons) { + delete pointer; + } +} +int WeaponModel::rowCount(const QModelIndex& parent) const +{ + return static_cast(weapons.size()); +} +QVariant WeaponModel::data(const QModelIndex& index, int role) const +{ + if (role == Qt::DisplayRole) { + const QString out = + weapons[index.row()]->name; + return out; + } + if (role == Qt::UserRole) { + const size_t id = weapons[index.row()]->id; + return id; + } + return {}; +} +QMimeData* WeaponModel::mimeData(const QModelIndexList& indexes) const +{ + auto mimeData = new QMimeData(); + QByteArray encodedData; + QDataStream stream(&encodedData, QIODevice::WriteOnly); + for (auto& index : indexes) { + if (index.isValid()) { + int id = data(index, Qt::UserRole).toInt(); + stream << id; + } + } + + mimeData->setData("application/weaponid", encodedData); + + return mimeData; +} +WeaponItem::WeaponItem(const int id, const QString& name) : name(name), id(id) {} +} // namespace fred +} // namespace fso \ No newline at end of file diff --git a/qtfred/src/ui/widgets/weaponList.h b/qtfred/src/ui/widgets/weaponList.h new file mode 100644 index 00000000000..9511af93d9f --- /dev/null +++ b/qtfred/src/ui/widgets/weaponList.h @@ -0,0 +1,39 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +namespace fso { +namespace fred { +struct WeaponItem { + WeaponItem(const int id, const QString& name); + const QString name; + const int id; +}; +class WeaponModel : public QAbstractListModel { + Q_OBJECT + public: + WeaponModel(int type); + ~WeaponModel(); + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + QMimeData* mimeData(const QModelIndexList& indexes) const; + QVector weapons; +}; +class weaponList : public QListView { + Q_OBJECT + public: + weaponList(QWidget* parent); + + protected: + void mousePressEvent(QMouseEvent* event); + void mouseMoveEvent(QMouseEvent* event); + QPoint dragStartPosition; + + private: +}; +} +} // namespace fso \ No newline at end of file diff --git a/qtfred/ui/ShipWeaponsDialog.ui b/qtfred/ui/ShipWeaponsDialog.ui new file mode 100644 index 00000000000..db8a7b71cbd --- /dev/null +++ b/qtfred/ui/ShipWeaponsDialog.ui @@ -0,0 +1,216 @@ + + + fso::fred::dialogs::ShipWeaponsDialog + + + + 0 + 0 + 764 + 622 + + + + Weapons Editor + + + true + + + + + + Mode + + + + + + Primary + + + + + + + Secondary + + + + + + + Tertiary + + + + + + + + + + + + Weapons + + + + + + QAbstractScrollArea::AdjustIgnored + + + QAbstractItemView::NoEditTriggers + + + true + + + QAbstractItemView::DragOnly + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Set Selected + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Banks + + + + + + QAbstractScrollArea::AdjustToContentsOnFirstShow + + + QAbstractItemView::DropOnly + + + QAbstractItemView::MultiSelection + + + QAbstractItemView::SelectItems + + + false + + + + + + + + + + + + + + + + + Change AI + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Close + + + + + + + + + + fso::fred::weaponList + QListView +
ui/widgets/weaponList.h
+
+ + fso::fred::bankTree + QTreeView +
ui/widgets/bankTree.h
+
+
+ + + + + + buttonClose + clicked() + fso::fred::dialogs::ShipWeaponsDialog + accept() + + + 490 + 322 + + + 340 + 335 + + + + +
From 32fecda339ab3fa5bcb433722112a8f9c268d063 Mon Sep 17 00:00:00 2001 From: The Force <2040992+TheForce172@users.noreply.github.com> Date: Sun, 26 May 2024 12:26:27 +0100 Subject: [PATCH 2/4] Add TBL Viewer --- qtfred/source_groups.cmake | 4 + .../ShipEditor/WeaponsTBLViewerModel.cpp | 153 ++++++++++++++++++ .../ShipEditor/WeaponsTBLViewerModel.h | 22 +++ .../dialogs/ShipEditor/ShipWeaponsDialog.cpp | 29 ++++ .../ui/dialogs/ShipEditor/ShipWeaponsDialog.h | 1 + .../dialogs/ShipEditor/WeaponsTBLViewer.cpp | 38 +++++ .../ui/dialogs/ShipEditor/WeaponsTBLViewer.h | 36 +++++ qtfred/ui/ShipWeaponsDialog.ui | 9 +- 8 files changed, 291 insertions(+), 1 deletion(-) create mode 100644 qtfred/src/mission/dialogs/ShipEditor/WeaponsTBLViewerModel.cpp create mode 100644 qtfred/src/mission/dialogs/ShipEditor/WeaponsTBLViewerModel.h create mode 100644 qtfred/src/ui/dialogs/ShipEditor/WeaponsTBLViewer.cpp create mode 100644 qtfred/src/ui/dialogs/ShipEditor/WeaponsTBLViewer.h diff --git a/qtfred/source_groups.cmake b/qtfred/source_groups.cmake index 0cd75f63b14..c815cf4cc08 100644 --- a/qtfred/source_groups.cmake +++ b/qtfred/source_groups.cmake @@ -88,6 +88,8 @@ add_file_folder("Source/Mission/Dialogs/ShipEditor" src/mission/dialogs/ShipEditor/ShipTBLViewerModel.h src/mission/dialogs/ShipEditor/ShipWeaponsDialogModel.cpp src/mission/dialogs/ShipEditor/ShipWeaponsDialogModel.h + src/mission/dialogs/ShipEditor/WeaponsTBLViewerModel.cpp + src/mission/dialogs/ShipEditor/WeaponsTBLViewerModel.h ) add_file_folder("Source/UI" @@ -158,6 +160,8 @@ add_file_folder("Source/UI/Dialogs/ShipEditor" src/ui/dialogs/ShipEditor/ShipWeaponsDialog.h src/ui/dialogs/ShipEditor/BankModel.cpp src/ui/dialogs/ShipEditor/BankModel.h + src/ui/dialogs/ShipEditor/WeaponsTBLViewer.cpp + src/ui/dialogs/ShipEditor/WeaponsTBLViewer.h ) add_file_folder("Source/UI/Util" diff --git a/qtfred/src/mission/dialogs/ShipEditor/WeaponsTBLViewerModel.cpp b/qtfred/src/mission/dialogs/ShipEditor/WeaponsTBLViewerModel.cpp new file mode 100644 index 00000000000..5aa5587651c --- /dev/null +++ b/qtfred/src/mission/dialogs/ShipEditor/WeaponsTBLViewerModel.cpp @@ -0,0 +1,153 @@ +#include "WeaponsTBLViewerModel.h" +#include +namespace fso { +namespace fred { +namespace dialogs { +WeaponsTBLViewerModel::WeaponsTBLViewerModel(QObject* parent, EditorViewport* viewport, int wc) + : AbstractDialogModel(parent, viewport) +{ + initializeData(wc); +} +bool WeaponsTBLViewerModel::apply() +{ + return true; +} +void WeaponsTBLViewerModel::reject() {} +void WeaponsTBLViewerModel::initializeData(const int wc) +{ + char line[256], line2[256]{}, file_text[82]{}; + const weapon_info* sip = &Weapon_info[wc]; + int i, j, n, found = 0, comment = 0, num_files = 0; + CFILE* fp = nullptr; + SCP_vector tbl_file_names; + text.clear(); + + if (!sip) { + return; + } + + fp = cfopen("weapons.tbl", "r"); + Assert(fp); + + while (cfgets(line, 255, fp)) { + while (line[strlen(line) - 1] == '\n') + line[strlen(line) - 1] = 0; + + for (i = j = 0; line[i]; i++) { + if (line[i] == '/' && line[i + 1] == '/') + break; + if (line[i] == '/' && line[i + 1] == '*') { + comment = 1; + i++; + continue; + } + + if (line[i] == '*' && line[i + 1] == '/') { + comment = 0; + i++; + continue; + } + + if (!comment) { + line2[j++] = line[i]; + } + } + + line2[j] = 0; + if (!strnicmp(line2, "$Name:", 6)) { + drop_trailing_white_space(line2); + found = 0; + i = 6; + + while (line2[i] == ' ' || line2[i] == '\t' || line2[i] == '@') + i++; + + if (!stricmp(line2 + i, sip->name)) { + text += "-- weapons.tbl -------------------------------\r\n"; + found = 1; + } + } + + if (found) { + text += line; + text += "\r\n"; + } + } + + cfclose(fp); + + // done with ships.tbl, so now check all modular ship tables... + num_files = cf_get_file_list(tbl_file_names, CF_TYPE_TABLES, NOX("*-wep.tbm"), CF_SORT_REVERSE); + + for (n = 0; n < num_files; n++) { + tbl_file_names[n] += ".tbm"; + + fp = cfopen(tbl_file_names[n].c_str(), "r"); + Assert(fp); + + memset(line, 0, sizeof(line)); + memset(line2, 0, sizeof(line2)); + found = 0; + comment = 0; + + while (cfgets(line, 255, fp)) { + while (line[strlen(line) - 1] == '\n') + line[strlen(line) - 1] = 0; + + for (i = j = 0; line[i]; i++) { + if (line[i] == '/' && line[i + 1] == '/') + break; + + if (line[i] == '/' && line[i + 1] == '*') { + comment = 1; + i++; + continue; + } + + if (line[i] == '*' && line[i + 1] == '/') { + comment = 0; + i++; + continue; + } + + if (!comment) + line2[j++] = line[i]; + } + + line2[j] = 0; + if (!strnicmp(line2, "$Name:", 6)) { + drop_trailing_white_space(line2); + found = 0; + i = 6; + + while (line2[i] == ' ' || line2[i] == '\t' || line2[i] == '@') + i++; + + if (!stricmp(line2 + i, sip->name)) { + memset(file_text, 0, sizeof(file_text)); + snprintf(file_text, + sizeof(file_text) - 1, + "-- %s -------------------------------\r\n", + tbl_file_names[n].c_str()); + text += file_text; + found = 1; + } + } + + if (found) { + text += line; + text += "\r\n"; + } + } + + cfclose(fp); + } + modelChanged(); +} +SCP_string WeaponsTBLViewerModel::getText() const +{ + return text; +} +} // namespace dialogs +} // namespace fred +} // namespace fso \ No newline at end of file diff --git a/qtfred/src/mission/dialogs/ShipEditor/WeaponsTBLViewerModel.h b/qtfred/src/mission/dialogs/ShipEditor/WeaponsTBLViewerModel.h new file mode 100644 index 00000000000..dbcba064aa7 --- /dev/null +++ b/qtfred/src/mission/dialogs/ShipEditor/WeaponsTBLViewerModel.h @@ -0,0 +1,22 @@ +#pragma once + +#include "../AbstractDialogModel.h" + +namespace fso { +namespace fred { +namespace dialogs { +class WeaponsTBLViewerModel : public AbstractDialogModel { + private: + SCP_string text; + + public: + WeaponsTBLViewerModel(QObject* parent, EditorViewport* viewport, int wc); + bool apply() override; + void reject() override; + void initializeData(const int ship_class); + + SCP_string getText() const; +}; +} // namespace dialogs +} // namespace fred +} // namespace fso \ No newline at end of file diff --git a/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.cpp b/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.cpp index d19a4d2210c..d948026f429 100644 --- a/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.cpp +++ b/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.cpp @@ -1,6 +1,7 @@ #include "ShipWeaponsDialog.h" #include "ui_ShipWeaponsDialog.h" +#include "WeaponsTBLViewer.h" #include #include @@ -48,6 +49,10 @@ ShipWeaponsDialog::ShipWeaponsDialog(QDialog* parent, EditorViewport* viewport, &ShipWeaponsDialog::aiClassChanged); ui->listWeapons->setModel(weapons); ui->treeBanks->expandAll(); + connect(ui->listWeapons->selectionModel(), + &QItemSelectionModel::selectionChanged, + this, + &ShipWeaponsDialog::updateUI); ui->treeBanks->header()->setSectionResizeMode(QHeaderView::ResizeToContents); updateUI(); } @@ -69,15 +74,29 @@ void ShipWeaponsDialog::on_setAllButton_clicked() bankModel->setWeapon(index, ui->listWeapons->currentIndex().data(Qt::UserRole).toInt()); } } +void ShipWeaponsDialog::on_TBLButton_clicked() { + if (ui->listWeapons->currentIndex().data(Qt::UserRole).toInt() >= 0) { + auto dialog = new WeaponsTBLViewer(this, _viewport, ui->listWeapons->currentIndex().data(Qt::UserRole).toInt()); + dialog->show(); + } else { + return; + } +} void ShipWeaponsDialog::modeChanged(const bool enabled, const int mode) { if (enabled) { if (mode == 0) { bankModel = new BankTreeModel(_model->getPrimaryBanks(), this); dialogMode = 0; + delete weapons; + weapons = new WeaponModel(0); + ui->listWeapons->setModel(weapons); } else if (mode == 1) { bankModel = new BankTreeModel(_model->getSecondaryBanks(), this); dialogMode = 1; + delete weapons; + weapons = new WeaponModel(1); + ui->listWeapons->setModel(weapons); } else if (mode == 2) { // bankModel = new BankTreeModel(_model->getTertiaryBanks(), this); dialogMode = 2; @@ -90,6 +109,10 @@ void ShipWeaponsDialog::modeChanged(const bool enabled, const int mode) bankModel = new BankTreeModel(_model->getPrimaryBanks(), this); dialogMode = 0; } + connect(ui->listWeapons->selectionModel(), + &QItemSelectionModel::selectionChanged, + this, + &ShipWeaponsDialog::updateUI); ui->treeBanks->setModel(bankModel); ui->treeBanks->expandAll(); } @@ -119,6 +142,12 @@ void ShipWeaponsDialog::updateUI() ui->AICombo->addItem(Ai_class_names[i], QVariant(i)); } ui->AICombo->setCurrentIndex(ui->AICombo->findData(m_currentAI)); + if (ui->listWeapons->selectionModel()->hasSelection() && + ui->listWeapons->currentIndex().data(Qt::UserRole).toInt() != -1) { + ui->TBLButton->setEnabled(true); + } else { + ui->TBLButton->setEnabled(false); + } } void ShipWeaponsDialog::aiClassChanged(const int index) { diff --git a/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.h b/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.h index 90168a8ea72..278cdd23b93 100644 --- a/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.h +++ b/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.h @@ -31,6 +31,7 @@ class ShipWeaponsDialog : public QDialog { private slots: void on_AIButton_clicked(); void on_setAllButton_clicked(); + void on_TBLButton_clicked(); private: std::unique_ptr ui; diff --git a/qtfred/src/ui/dialogs/ShipEditor/WeaponsTBLViewer.cpp b/qtfred/src/ui/dialogs/ShipEditor/WeaponsTBLViewer.cpp new file mode 100644 index 00000000000..1f9e7765540 --- /dev/null +++ b/qtfred/src/ui/dialogs/ShipEditor/WeaponsTBLViewer.cpp @@ -0,0 +1,38 @@ +#include "WeaponsTBLViewer.h" +#include "ui_ShipTBLViewer.h" + +#include + +#include + +namespace fso { +namespace fred { +namespace dialogs { +WeaponsTBLViewer::WeaponsTBLViewer(QWidget* parent, EditorViewport* viewport, int wc) + : QDialog(parent), ui(new Ui::ShipTBLViewer()), _viewport(viewport), + _model(new WeaponsTBLViewerModel(this, viewport, wc)) +{ + + ui->setupUi(this); + this->setWindowTitle("Weapon TBL Data"); + connect(_model.get(), &AbstractDialogModel::modelChanged, this, &WeaponsTBLViewer::updateUI); + + updateUI(); + + // Resize the dialog to the minimum size + resize(QDialog::sizeHint()); +} + +WeaponsTBLViewer::~WeaponsTBLViewer() = default; +void WeaponsTBLViewer::closeEvent(QCloseEvent* event) +{ + QDialog::closeEvent(event); +} +void WeaponsTBLViewer::updateUI() +{ + util::SignalBlockers blockers(this); + ui->TBLData->setPlainText(_model->getText().c_str()); +} +} // namespace dialogs +} // namespace fred +} // namespace fso \ No newline at end of file diff --git a/qtfred/src/ui/dialogs/ShipEditor/WeaponsTBLViewer.h b/qtfred/src/ui/dialogs/ShipEditor/WeaponsTBLViewer.h new file mode 100644 index 00000000000..ca9608af7af --- /dev/null +++ b/qtfred/src/ui/dialogs/ShipEditor/WeaponsTBLViewer.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include + +namespace fso { +namespace fred { +namespace dialogs { + +namespace Ui { +class ShipTBLViewer; +} +class WeaponsTBLViewer : public QDialog { + Q_OBJECT + + public: + explicit WeaponsTBLViewer(QWidget* parent, EditorViewport* viewport, int wc); + ~WeaponsTBLViewer() override; + + protected: + void closeEvent(QCloseEvent*) override; + + private: + std::unique_ptr ui; + std::unique_ptr _model; + EditorViewport* _viewport; + + + int sc; + + void updateUI(); +}; +} // namespace dialogs +} // namespace fred +} // namespace fso \ No newline at end of file diff --git a/qtfred/ui/ShipWeaponsDialog.ui b/qtfred/ui/ShipWeaponsDialog.ui index db8a7b71cbd..899c32326b3 100644 --- a/qtfred/ui/ShipWeaponsDialog.ui +++ b/qtfred/ui/ShipWeaponsDialog.ui @@ -54,7 +54,7 @@ Weapons - + @@ -71,6 +71,13 @@ + + + + View Table + + + From 0b241253c57d58bc2e82c232a92463494edc2444 Mon Sep 17 00:00:00 2001 From: The Force <2040992+TheForce172@users.noreply.github.com> Date: Sun, 26 May 2024 12:58:48 +0100 Subject: [PATCH 3/4] Add Comments --- .../ShipEditor/ShipWeaponsDialogModel.h | 9 ++++++ .../dialogs/ShipEditor/ShipWeaponsDialog.cpp | 31 ++++++++++++++----- .../ui/dialogs/ShipEditor/ShipWeaponsDialog.h | 15 ++++++++- 3 files changed, 47 insertions(+), 8 deletions(-) diff --git a/qtfred/src/mission/dialogs/ShipEditor/ShipWeaponsDialogModel.h b/qtfred/src/mission/dialogs/ShipEditor/ShipWeaponsDialogModel.h index 37adbb4dd89..8006c054ba2 100644 --- a/qtfred/src/mission/dialogs/ShipEditor/ShipWeaponsDialogModel.h +++ b/qtfred/src/mission/dialogs/ShipEditor/ShipWeaponsDialogModel.h @@ -50,8 +50,17 @@ struct Bank { Banks* parent; }; namespace dialogs { +/** + * @brief QTFred's Weapons Editor Model + */ class ShipWeaponsDialogModel : public AbstractDialogModel { public: + /** + * @brief QTFred's Weapons Editor Model Constructer. + * @param [in/out] parent The dialogs parent. + * @param [in/out] viewport Editor viewport. + * @param [in] multi If editing multiple ships. + */ ShipWeaponsDialogModel(QObject* parent, EditorViewport* viewport, bool multi); // void initTertiary(int inst, bool first); diff --git a/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.cpp b/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.cpp index d948026f429..c2ccb5250db 100644 --- a/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.cpp +++ b/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.cpp @@ -17,12 +17,15 @@ ShipWeaponsDialog::ShipWeaponsDialog(QDialog* parent, EditorViewport* viewport, { ui->setupUi(this); + //Connect the mode change buttons connect(ui->radioPrimary, &QRadioButton::toggled, this, [this](bool param) { modeChanged(param, 0); }); connect(ui->radioSecondary, &QRadioButton::toggled, this, [this](bool param) { modeChanged(param, 1); }); connect(ui->radioTertiary, &QRadioButton::toggled, this, [this](bool param) { modeChanged(param, 2); }); connect(this, &QDialog::accepted, _model.get(), &ShipWeaponsDialogModel::apply); + + //Build the model of ship weapons and set inital mode. if (!_model->getPrimaryBanks().empty()) { const util::SignalBlockers blockers(this); bankModel = new BankTreeModel(_model->getPrimaryBanks(), this); @@ -39,20 +42,26 @@ ShipWeaponsDialog::ShipWeaponsDialog(QDialog* parent, EditorViewport* viewport, Error("No Valid Weapon banks on ship"); } ui->treeBanks->setModel(bankModel); + ui->listWeapons->setModel(weapons); + + //Update the UI whenever selections change connect(ui->treeBanks->selectionModel(), &QItemSelectionModel::selectionChanged, this, &ShipWeaponsDialog::updateUI); + connect(ui->listWeapons->selectionModel(), + &QItemSelectionModel::selectionChanged, + this, + &ShipWeaponsDialog::updateUI); + + //Setup ai combo box connect(ui->AICombo, static_cast(&QComboBox::currentIndexChanged), this, &ShipWeaponsDialog::aiClassChanged); - ui->listWeapons->setModel(weapons); + + //Resize Bank view ui->treeBanks->expandAll(); - connect(ui->listWeapons->selectionModel(), - &QItemSelectionModel::selectionChanged, - this, - &ShipWeaponsDialog::updateUI); ui->treeBanks->header()->setSectionResizeMode(QHeaderView::ResizeToContents); updateUI(); } @@ -109,6 +118,11 @@ void ShipWeaponsDialog::modeChanged(const bool enabled, const int mode) bankModel = new BankTreeModel(_model->getPrimaryBanks(), this); dialogMode = 0; } + //Reconnect Meacuse the model has changed + connect(ui->treeBanks->selectionModel(), + &QItemSelectionModel::selectionChanged, + this, + &ShipWeaponsDialog::updateUI); connect(ui->listWeapons->selectionModel(), &QItemSelectionModel::selectionChanged, this, @@ -121,22 +135,25 @@ void ShipWeaponsDialog::modeChanged(const bool enabled, const int mode) void ShipWeaponsDialog::updateUI() { const util::SignalBlockers blockers(this); + //Radio Buttons ui->radioPrimary->setEnabled(!_model->getPrimaryBanks().empty()); ui->radioSecondary->setEnabled(!_model->getSecondaryBanks().empty()); ui->radioTertiary->setEnabled(false); - ui->treeBanks->expandAll(); + ui->treeBanks->expandAll(); + // Setall button if (ui->treeBanks->getTypeSelected() == 0) { ui->setAllButton->setEnabled(true); } else { ui->setAllButton->setEnabled(false); } - + // Change AI Button if (ui->treeBanks->getTypeSelected() == 1) { ui->AIButton->setEnabled(true); } else { ui->AIButton->setEnabled(false); } + // AI Combo Box ui->AICombo->clear(); for (int i = 0; i < Num_ai_classes; i++) { ui->AICombo->addItem(Ai_class_names[i], QVariant(i)); diff --git a/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.h b/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.h index 278cdd23b93..ab721579077 100644 --- a/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.h +++ b/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.h @@ -17,11 +17,19 @@ namespace dialogs { namespace Ui { class ShipWeaponsDialog; } - +/** + * @brief QTFred's Weapons Editor + */ class ShipWeaponsDialog : public QDialog { Q_OBJECT public: + /** + * @brief QTFred's Weapons Editor Constructer. + * @param [in/out] parent The dialogs parent. + * @param [in/out] viewport Editor viewport. + * @param [in] isMultiEdit If editing multiple ships. + */ explicit ShipWeaponsDialog(QDialog* parent, EditorViewport* viewport, bool isMultiEdit); ~ShipWeaponsDialog() override; @@ -36,6 +44,11 @@ class ShipWeaponsDialog : public QDialog { private: std::unique_ptr ui; std::unique_ptr _model; + /** + * @brief Changes current weapon type. + * @param [in] enabled Always True + * @param [in] mode The mode to change to. 0 = Primary, 1 = Secondary + */ void modeChanged(const bool enabled, const int mode); EditorViewport* _viewport; void updateUI(); From 144822c461193626f3f7264f670e41111ac10ef3 Mon Sep 17 00:00:00 2001 From: The Force <2040992+TheForce172@users.noreply.github.com> Date: Mon, 27 May 2024 08:43:05 +0100 Subject: [PATCH 4/4] Appease GCC / Clang Appease GCC This is a silly error AAAAAGH Fix Model Sick of this Fix Supposed Shadowing Hopefully the last Or maybe not Please --- qtfred/source_groups.cmake | 4 +-- .../ShipEditor/ShipWeaponsDialogModel.cpp | 16 +++++------ .../src/ui/dialogs/ShipEditor/BankModel.cpp | 28 +++++++++---------- qtfred/src/ui/dialogs/ShipEditor/BankModel.h | 11 +++++--- .../dialogs/ShipEditor/ShipWeaponsDialog.cpp | 3 +- .../dialogs/ShipEditor/WeaponsTBLViewer.cpp | 5 ++-- qtfred/src/ui/widgets/weaponList.cpp | 15 +++++----- qtfred/src/ui/widgets/weaponList.h | 2 +- 8 files changed, 43 insertions(+), 41 deletions(-) diff --git a/qtfred/source_groups.cmake b/qtfred/source_groups.cmake index c815cf4cc08..7cf873bb240 100644 --- a/qtfred/source_groups.cmake +++ b/qtfred/source_groups.cmake @@ -182,8 +182,8 @@ add_file_folder("Source/UI/Widgets" src/ui/widgets/ShipFlagCheckbox.cpp src/ui/widgets/weaponList.cpp src/ui/widgets/weaponList.h - src/ui/widgets/BankTree.cpp - src/ui/widgets/BankTree.h + src/ui/widgets/bankTree.cpp + src/ui/widgets/bankTree.h ) add_file_folder("UI" diff --git a/qtfred/src/mission/dialogs/ShipEditor/ShipWeaponsDialogModel.cpp b/qtfred/src/mission/dialogs/ShipEditor/ShipWeaponsDialogModel.cpp index efad53ec636..4ba51620ee4 100644 --- a/qtfred/src/mission/dialogs/ShipEditor/ShipWeaponsDialogModel.cpp +++ b/qtfred/src/mission/dialogs/ShipEditor/ShipWeaponsDialogModel.cpp @@ -1,8 +1,8 @@ #include "ShipWeaponsDialogModel.h" namespace fso { namespace fred { -Banks::Banks(const SCP_string& name, int aiIndex, int ship, int multiedit, ship_subsys* subsys) - : name(name), subsys(subsys), ship(ship), m_isMultiEdit(multiedit), initalAI(aiIndex) +Banks::Banks(const SCP_string& _name, int aiIndex, int _ship, int multiedit, ship_subsys* _subsys) + : m_isMultiEdit(multiedit) ,name(_name), subsys(_subsys), initalAI(aiIndex), ship(_ship) { aiClass = aiIndex; } @@ -74,13 +74,13 @@ int Banks::getInitalAI() { return initalAI; } -Bank::Bank(const int weaponId, const int bankId, const int ammoMax, const int ammo, Banks* parent) +Bank::Bank(const int _weaponId, const int _bankId, const int _ammoMax, const int _ammo, Banks* _parent) { - this->weaponId = weaponId; - this->bankId = bankId; - this->ammo = ammo; - this->ammoMax = ammoMax; - this->parent = parent; + this->weaponId = _weaponId; + this->bankId = _bankId; + this->ammo = _ammo; + this->ammoMax = _ammoMax; + this->parent = _parent; } int Bank::getWeaponId() const { diff --git a/qtfred/src/ui/dialogs/ShipEditor/BankModel.cpp b/qtfred/src/ui/dialogs/ShipEditor/BankModel.cpp index 87e72d0e9f5..3f37aab3a62 100644 --- a/qtfred/src/ui/dialogs/ShipEditor/BankModel.cpp +++ b/qtfred/src/ui/dialogs/ShipEditor/BankModel.cpp @@ -4,7 +4,8 @@ #include namespace fso { namespace fred { -BankTreeItem::BankTreeItem(BankTreeItem* parentItem) : m_parentItem(parentItem) {} +BankTreeItem::BankTreeItem(BankTreeItem* parentItem, const QString& inName) : name(inName), m_parentItem(parentItem) { +} BankTreeItem::~BankTreeItem() { qDeleteAll(m_childItems); @@ -66,9 +67,8 @@ int BankTreeBank::getId() const return bank->getWeaponId(); } -BankTreeBank::BankTreeBank(Bank* bank, BankTreeItem* parentItem) : BankTreeItem(parentItem) +BankTreeBank::BankTreeBank(Bank* inBank, BankTreeItem* parentItem) : BankTreeItem(parentItem), bank(inBank) { - this->bank = bank; switch (bank->getWeaponId()) { case -2: this->name = "CONFLICT"; @@ -125,11 +125,9 @@ void BankTreeBank::setAmmo(int value) bank->setAmmo(value); } -BankTreeLabel::BankTreeLabel(const QString& name, Banks* banks, BankTreeItem* parentItem) : BankTreeItem(parentItem) -{ - this->name = name; - this->banks = banks; -} +BankTreeLabel::BankTreeLabel(const QString& inName, Banks* inBanks, BankTreeItem* parentItem) + : BankTreeItem(parentItem, inName), banks(inBanks) +{} QVariant BankTreeLabel::data(int column) const { @@ -145,6 +143,7 @@ QVariant BankTreeLabel::data(int column) const Qt::ItemFlags BankTreeLabel::getFlags(int column) const { + Q_UNUSED(column); return Qt::ItemIsSelectable; } @@ -156,6 +155,7 @@ void BankTreeLabel::setAIClass(int value) bool BankTreeLabel::setData(int column, const QVariant& value) { + Q_UNUSED(column); setAIClass(value.toInt()); return true; } @@ -191,6 +191,7 @@ void BankTreeModel::setupModelData(const SCP_vector& data, BankTreeItem* QVariant BankTreeModel::headerData(int section, Qt::Orientation orientation, int role) const { + Q_UNUSED(orientation); if (role == Qt::DisplayRole) { switch (section) { case 0: @@ -336,13 +337,7 @@ bool BankTreeModel::dropMimeData(const QMimeData* data, if (action == Qt::IgnoreAction) return true; - int beginRow; - - if (row != -1) - beginRow = row; - else if (parent.isValid()) - beginRow = parent.row(); - else + if (!(row != -1 || parent.isValid())) return false; QByteArray encodedData = data->data("application/weaponid"); @@ -366,6 +361,8 @@ void BankTreeModel::setWeapon(const QModelIndex& index, int data) const bool BankTreeRoot::setData(int column, const QVariant& value) { + Q_UNUSED(column); + Q_UNUSED(value); return false; } QVariant BankTreeRoot::data(int column) const @@ -383,6 +380,7 @@ QVariant BankTreeRoot::data(int column) const } Qt::ItemFlags BankTreeRoot::getFlags(int column) const { + Q_UNUSED(column); return {}; } diff --git a/qtfred/src/ui/dialogs/ShipEditor/BankModel.h b/qtfred/src/ui/dialogs/ShipEditor/BankModel.h index df912ae5f6b..3fc99df4180 100644 --- a/qtfred/src/ui/dialogs/ShipEditor/BankModel.h +++ b/qtfred/src/ui/dialogs/ShipEditor/BankModel.h @@ -5,7 +5,7 @@ namespace fso { namespace fred { class BankTreeItem { public: - explicit BankTreeItem(BankTreeItem* parentItem = nullptr); + explicit BankTreeItem(BankTreeItem* parentItem = nullptr, const QString& inName = ""); virtual ~BankTreeItem(); virtual QVariant data(int column) const = 0; void appendChild(BankTreeItem* child); @@ -34,7 +34,7 @@ class BankTreeRoot : public BankTreeItem { }; class BankTreeBank : public BankTreeItem { public: - explicit BankTreeBank(Bank* bank, BankTreeItem* parentItem = nullptr); + explicit BankTreeBank(Bank* inBank, BankTreeItem* parentItem = nullptr); void setWeapon(int id); void setAmmo(int value); int getId() const; @@ -73,8 +73,11 @@ class BankTreeModel : public QAbstractItemModel { Qt::ItemFlags flags(const QModelIndex& index) const override; QStringList mimeTypes() const override; - bool - canDropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) const; + bool canDropMimeData(const QMimeData* data, + Qt::DropAction action, + int row, + int column, + const QModelIndex& parent) const override; bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) override; void setWeapon(const QModelIndex& index, int data) const; diff --git a/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.cpp b/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.cpp index c2ccb5250db..2285e2d3157 100644 --- a/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.cpp +++ b/qtfred/src/ui/dialogs/ShipEditor/ShipWeaponsDialog.cpp @@ -78,7 +78,6 @@ void ShipWeaponsDialog::closeEvent(QCloseEvent* event) } void ShipWeaponsDialog::on_setAllButton_clicked() { - int test = 0; for (auto& index : ui->treeBanks->selectionModel()->selectedIndexes()) { bankModel->setWeapon(index, ui->listWeapons->currentIndex().data(Qt::UserRole).toInt()); } @@ -112,7 +111,7 @@ void ShipWeaponsDialog::modeChanged(const bool enabled, const int mode) } else { _viewport->dialogProvider->showButtonDialog(DialogType::Error, "Illegal Mode", - "Somehow an Illegal mode has been set. Get a coder.\n Illegal mode is " + mode, + "Somehow an Illegal mode has been set. Get a coder.\n Illegal mode is " + std::to_string(mode), {DialogButton::Ok}); ui->radioPrimary->toggled(true); bankModel = new BankTreeModel(_model->getPrimaryBanks(), this); diff --git a/qtfred/src/ui/dialogs/ShipEditor/WeaponsTBLViewer.cpp b/qtfred/src/ui/dialogs/ShipEditor/WeaponsTBLViewer.cpp index 1f9e7765540..20f0f7bff85 100644 --- a/qtfred/src/ui/dialogs/ShipEditor/WeaponsTBLViewer.cpp +++ b/qtfred/src/ui/dialogs/ShipEditor/WeaponsTBLViewer.cpp @@ -1,4 +1,5 @@ #include "WeaponsTBLViewer.h" + #include "ui_ShipTBLViewer.h" #include @@ -9,8 +10,8 @@ namespace fso { namespace fred { namespace dialogs { WeaponsTBLViewer::WeaponsTBLViewer(QWidget* parent, EditorViewport* viewport, int wc) - : QDialog(parent), ui(new Ui::ShipTBLViewer()), _viewport(viewport), - _model(new WeaponsTBLViewerModel(this, viewport, wc)) + : QDialog(parent), ui(new Ui::ShipTBLViewer()), _model(new WeaponsTBLViewerModel(this, viewport, wc)), + _viewport(viewport) { ui->setupUi(this); diff --git a/qtfred/src/ui/widgets/weaponList.cpp b/qtfred/src/ui/widgets/weaponList.cpp index 3f67af99348..ede822c8481 100644 --- a/qtfred/src/ui/widgets/weaponList.cpp +++ b/qtfred/src/ui/widgets/weaponList.cpp @@ -6,9 +6,10 @@ weaponList::weaponList(QWidget* parent) : QListView(parent) {} void weaponList::mousePressEvent(QMouseEvent* event) { - if (event->button() == Qt::LeftButton) + if (event->button() == Qt::LeftButton) { dragStartPosition = event->pos(); - QListView::mousePressEvent(event); + } + QListView::mousePressEvent(event); } void weaponList::mouseMoveEvent(QMouseEvent* event) { @@ -30,7 +31,7 @@ void weaponList::mouseMoveEvent(QMouseEvent* event) painter.drawText(QPoint(100, 100), model()->data(idx, Qt::DisplayRole).toString()); drag->setPixmap(*iconPixmap); drag->setMimeData(mimeData); - Qt::DropAction dropAction = drag->exec(); + drag->exec(); } WeaponModel::WeaponModel(int type) @@ -67,17 +68,17 @@ WeaponModel::~WeaponModel() } int WeaponModel::rowCount(const QModelIndex& parent) const { + Q_UNUSED(parent); return static_cast(weapons.size()); } QVariant WeaponModel::data(const QModelIndex& index, int role) const { if (role == Qt::DisplayRole) { - const QString out = - weapons[index.row()]->name; + const QString out = weapons[index.row()]->name; return out; } if (role == Qt::UserRole) { - const size_t id = weapons[index.row()]->id; + const int id = weapons[index.row()]->id; return id; } return {}; @@ -98,6 +99,6 @@ QMimeData* WeaponModel::mimeData(const QModelIndexList& indexes) const return mimeData; } -WeaponItem::WeaponItem(const int id, const QString& name) : name(name), id(id) {} +WeaponItem::WeaponItem(const int inID, const QString& inName) : name(inName), id(inID) {} } // namespace fred } // namespace fso \ No newline at end of file diff --git a/qtfred/src/ui/widgets/weaponList.h b/qtfred/src/ui/widgets/weaponList.h index 9511af93d9f..8a9d02a0b3e 100644 --- a/qtfred/src/ui/widgets/weaponList.h +++ b/qtfred/src/ui/widgets/weaponList.h @@ -20,7 +20,7 @@ class WeaponModel : public QAbstractListModel { ~WeaponModel(); int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; - QMimeData* mimeData(const QModelIndexList& indexes) const; + QMimeData* mimeData(const QModelIndexList& indexes) const override; QVector weapons; }; class weaponList : public QListView {