From c4ae144f32930e2c4c789180fd918a4d6c4a7be3 Mon Sep 17 00:00:00 2001 From: T1ti Date: Mon, 14 Nov 2022 23:57:28 +0100 Subject: [PATCH] Area editor + sound player + various DBC pickers/editors --- CMakeLists.txt | 3 +- src/noggit/DBC.cpp | 22 + src/noggit/DBC.h | 99 ++ src/noggit/DBCFile.h | 21 + src/noggit/ui/ZoneIDBrowser.cpp | 918 +++++++++++++++--- src/noggit/ui/ZoneIDBrowser.h | 96 +- .../EditorWindows/SoundEntryPickerWindow.cpp | 479 +++++++++ .../EditorWindows/SoundEntryPickerWindow.h | 156 +++ .../ZoneIntroMusicPickerWindow.cpp | 250 +++++ .../ZoneIntroMusicPickerWindow.h | 50 + .../EditorWindows/ZoneMusicPickerWindow.cpp | 326 +++++++ .../EditorWindows/ZoneMusicPickerWindow.h | 53 + .../windows/SoundPlayer/SoundEntryPlayer.cpp | 213 ++++ .../ui/windows/SoundPlayer/SoundEntryPlayer.h | 49 + 14 files changed, 2585 insertions(+), 150 deletions(-) create mode 100644 src/noggit/ui/windows/EditorWindows/SoundEntryPickerWindow.cpp create mode 100644 src/noggit/ui/windows/EditorWindows/SoundEntryPickerWindow.h create mode 100644 src/noggit/ui/windows/EditorWindows/ZoneIntroMusicPickerWindow.cpp create mode 100644 src/noggit/ui/windows/EditorWindows/ZoneIntroMusicPickerWindow.h create mode 100644 src/noggit/ui/windows/EditorWindows/ZoneMusicPickerWindow.cpp create mode 100644 src/noggit/ui/windows/EditorWindows/ZoneMusicPickerWindow.h create mode 100644 src/noggit/ui/windows/SoundPlayer/SoundEntryPlayer.cpp create mode 100644 src/noggit/ui/windows/SoundPlayer/SoundEntryPlayer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0dde6e20..ae15b214 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,7 +108,7 @@ set(FASTNOISE2_NOISETOOL OFF CACHE BOOL "") FIND_PACKAGE(FastNoise2 REQUIRED) FIND_PACKAGE(Sol2 REQUIRED) -FIND_PACKAGE(Qt5 COMPONENTS Widgets OpenGL OpenGLExtensions Network Xml REQUIRED) +FIND_PACKAGE(Qt5 COMPONENTS Widgets OpenGL OpenGLExtensions Network Xml Multimedia REQUIRED) IF(USE_SQL) FIND_LIBRARY(MYSQL_LIBRARY NAMES libmysql @@ -342,6 +342,7 @@ TARGET_LINK_LIBRARIES (noggit Qt5::OpenGLExtensions Qt5::Xml Qt5::Network + Qt5::Multimedia ColorWidgets-qt5 FramelessHelper qt_imgui_widgets diff --git a/src/noggit/DBC.cpp b/src/noggit/DBC.cpp index df6ea937..4a032398 100755 --- a/src/noggit/DBC.cpp +++ b/src/noggit/DBC.cpp @@ -17,6 +17,11 @@ LightFloatBandDB gLightFloatBandDB; GroundEffectDoodadDB gGroundEffectDoodadDB; GroundEffectTextureDB gGroundEffectTextureDB; LiquidTypeDB gLiquidTypeDB; +SoundProviderPreferencesDB gSoundProviderPreferencesDB; +SoundAmbienceDB gSoundAmbienceDB; +ZoneMusicDB gZoneMusicDB; +ZoneIntroMusicTableDB gZoneIntroMusicTableDB; +SoundEntriesDB gSoundEntriesDB; void OpenDBs(std::shared_ptr clientData) { @@ -31,6 +36,11 @@ void OpenDBs(std::shared_ptr clientData) gGroundEffectDoodadDB.open(clientData); gGroundEffectTextureDB.open(clientData); gLiquidTypeDB.open(clientData); + gSoundProviderPreferencesDB.open(clientData); + gSoundAmbienceDB.open(clientData); + gZoneMusicDB.open(clientData); + gZoneIntroMusicTableDB.open(clientData); + gSoundEntriesDB.open(clientData); } @@ -89,6 +99,18 @@ std::uint32_t AreaDB::get_area_parent(int area_id) } } +std::uint32_t AreaDB::get_new_areabit() +{ + unsigned int areabit = 0; + + for (Iterator i = gAreaDB.begin(); i != gAreaDB.end(); ++i) + { + areabit = std::max(i->getUInt(AreaDB::AreaBit), areabit); + } + + return static_cast(++areabit); +} + std::string MapDB::getMapName(int pMapID) { if (pMapID<0) return "Unknown map"; diff --git a/src/noggit/DBC.h b/src/noggit/DBC.h index c2c3862c..c0ae2e1e 100755 --- a/src/noggit/DBC.h +++ b/src/noggit/DBC.h @@ -17,11 +17,24 @@ public: static const size_t AreaID = 0; // uint static const size_t Continent = 1; // uint static const size_t Region = 2; // uint [AreaID] + static const size_t AreaBit = 3; // uint static const size_t Flags = 4; // bit field + static const size_t SoundProviderPreferences = 5; // uint + static const size_t UnderwaterSoundProviderPreferences = 6; // uint + static const size_t SoundAmbience = 7; // uint + static const size_t ZoneMusic = 8; // uint + static const size_t ZoneIntroMusicTable = 9; // uint + static const size_t ExplorationLevel = 10; // int static const size_t Name = 11; // localisation string + static const size_t FactionGroup = 28; // uint + static const size_t LiquidType = 29; // uint[4] + static const size_t MinElevation = 33; // float + static const size_t AmbientMultiplier = 34; // float + static const size_t LightId = 35; // int static std::string getAreaName(int pAreaID); static std::uint32_t get_area_parent(int area_id); + static std::uint32_t get_new_areabit(); }; class MapDB : public DBCFile @@ -184,6 +197,87 @@ public: static std::string getLiquidName(int pID); }; +class SoundProviderPreferencesDB : public DBCFile +{ +public: + SoundProviderPreferencesDB() : + DBCFile("DBFilesClient\\SoundProviderPreferences.dbc") + { } + + /// Fields + static const size_t ID = 0; // uint + static const size_t Description = 1; // string +}; + +class SoundAmbienceDB : public DBCFile +{ +public: + SoundAmbienceDB() : + DBCFile("DBFilesClient\\SoundAmbience.dbc") + { } + + /// Fields + static const size_t ID = 0; // uint + static const size_t SoundEntry_day = 1; // uint + static const size_t SoundEntry_night = 2; // uint +}; + +class ZoneMusicDB : public DBCFile +{ +public: + ZoneMusicDB() : + DBCFile("DBFilesClient\\ZoneMusic.dbc") + { } + + /// Fields + static const size_t ID = 0; // uint + static const size_t Name = 1; // string + static const size_t SilenceIntervalMinDay = 2; // uint + static const size_t SilenceIntervalMinNight = 3; // uint + static const size_t SilenceIntervalMaxDay = 4; // uint + static const size_t SilenceIntervalMaxNight = 5; // uint + static const size_t DayMusic = 6; // uint [soundEntries] + static const size_t NightMusic = 7; // uint [soundEntries] +}; + +class ZoneIntroMusicTableDB : public DBCFile +{ +public: + ZoneIntroMusicTableDB() : + DBCFile("DBFilesClient\\ZoneIntroMusicTable.dbc") + { } + + /// Fields + static const size_t ID = 0; // uint + static const size_t Name = 1; // string + static const size_t SoundId = 2; // uint + static const size_t Priority = 3; // uint + static const size_t MinDelayMinutes = 4; // uint +}; + +class SoundEntriesDB : public DBCFile +{ +public: + SoundEntriesDB() : + DBCFile("DBFilesClient\\SoundEntries.dbc") + { } + + /// Fields + static const size_t ID = 0; // uint + static const size_t SoundType = 1; // uint + static const size_t Name = 2; // string + static const size_t Filenames = 3; // string[10] + static const size_t Freq = 13; // uint[10) + static const size_t FilePath = 23; // string[10) + static const size_t Volume = 24; // float + static const size_t Flags = 25; // int + static const size_t minDistance = 26; // float + static const size_t distanceCutoff = 27; // float + static const size_t EAXDef = 28; // int + static const size_t soundEntriesAdvancedID = 29; // int + +}; + void OpenDBs(std::shared_ptr clientData); const char * getGroundEffectDoodad(unsigned int effectID, int DoodadNum); @@ -199,3 +293,8 @@ extern LightFloatBandDB gLightFloatBandDB; extern GroundEffectDoodadDB gGroundEffectDoodadDB; extern GroundEffectTextureDB gGroundEffectTextureDB; extern LiquidTypeDB gLiquidTypeDB; +extern SoundProviderPreferencesDB gSoundProviderPreferencesDB; +extern SoundAmbienceDB gSoundAmbienceDB; +extern ZoneMusicDB gZoneMusicDB; +extern ZoneIntroMusicTableDB gZoneIntroMusicTableDB; +extern SoundEntriesDB gSoundEntriesDB; diff --git a/src/noggit/DBCFile.h b/src/noggit/DBCFile.h index 34ff4f64..61350003 100755 --- a/src/noggit/DBCFile.h +++ b/src/noggit/DBCFile.h @@ -181,6 +181,27 @@ public: } throw NotFound(); } + inline bool CheckIfIdExists(unsigned int id, size_t field = 0) + { + for (Iterator i = begin(); i != end(); ++i) + { + if (i->getUInt(field) == id) + return (true); + } + return (false); + } + inline int getRecordRowId(unsigned int id, size_t field = 0) + { + int row_id = 0; + for (Iterator i = begin(); i != end(); ++i) + { + if (i->getUInt(field) == id) + return row_id; + + row_id++; + } + throw NotFound(); + } Record addRecord(size_t id, size_t id_field = 0); Record addRecordCopy(size_t id, size_t id_from, size_t id_field = 0); diff --git a/src/noggit/ui/ZoneIDBrowser.cpp b/src/noggit/ui/ZoneIDBrowser.cpp index 8c514848..68450a4e 100755 --- a/src/noggit/ui/ZoneIDBrowser.cpp +++ b/src/noggit/ui/ZoneIDBrowser.cpp @@ -1,176 +1,800 @@ // This file is part of Noggit3, licensed under GNU General Public License (version 3). #include +#include +#include +#include +#include +#include #include #include #include +#include +#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include #include #include +#include namespace Noggit { - namespace Ui - { - zone_id_browser::zone_id_browser(QWidget* parent) - : QWidget(parent) - , _area_tree(new QTreeWidget()) - , mapID(-1) + namespace Ui { - auto layout = new QFormLayout(this); - - _radius_spin = new QDoubleSpinBox (this); - _radius_spin->setRange (0.0f, 1000.0f); - _radius_spin->setDecimals (2); - _radius_spin->setValue (_radius); - - layout->addRow ("Radius:", _radius_spin); - - _radius_slider = new QSlider (Qt::Orientation::Horizontal, this); - _radius_slider->setRange (0, 250); - _radius_slider->setSliderPosition (_radius); - - layout->addRow (_radius_slider); - layout->addRow (_area_tree); - - setMinimumWidth(250); - - connect ( _area_tree, &QTreeWidget::itemSelectionChanged - , [this] - { - auto const& selected_items = _area_tree->selectedItems(); - if (selected_items.size()) - { - emit selected (selected_items.back()->data(0, 1).toInt()); - } - } - ); - - connect ( _radius_spin, qOverload (&QDoubleSpinBox::valueChanged) - , [&] (double v) - { - _radius = v; - QSignalBlocker const blocker(_radius_slider); - _radius_slider->setSliderPosition ((int)std::round (v)); - } - ); - - connect ( _radius_slider, &QSlider::valueChanged - , [&] (int v) - { - _radius = v; - QSignalBlocker const blocker(_radius_spin); - _radius_spin->setValue(v); - } - ); - } - - void zone_id_browser::setMapID(int id) - { - mapID = id; - - for (DBCFile::Iterator i = gMapDB.begin(); i != gMapDB.end(); ++i) - { - if (i->getInt(MapDB::MapID) == id) + zone_id_browser::zone_id_browser(QWidget* parent) + : QWidget(parent) + , _area_tree(new QTreeWidget()) + , mapID(-1) { - std::stringstream ss; - ss << id << "-" << i->getString(MapDB::InternalName); - _area_tree->setHeaderLabel(ss.str().c_str()); + + auto layout = new QFormLayout(this); + + _radius_spin = new QDoubleSpinBox(this); + _radius_spin->setRange(0.0f, 1000.0f); + _radius_spin->setDecimals(2); + _radius_spin->setValue(_radius); + + layout->addRow("Radius:", _radius_spin); + + _radius_slider = new QSlider(Qt::Orientation::Horizontal, this); + _radius_slider->setRange(0, 250); + _radius_slider->setSliderPosition(_radius); + + QPushButton* edit_area_button = new QPushButton("Edit selected Area", this); + edit_area_button->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::cog)); + QPushButton* add_zone_button = new QPushButton("Add a new Zone(parent Area)", this); + add_zone_button->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::plus)); + QPushButton* add_subzone_button = new QPushButton("Add a new Subzone(selected as Parent)", this); + add_subzone_button->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::plus)); + + + _area_editor = new AreaEditor(this); + + layout->addRow(_radius_slider); + layout->addRow(_area_tree); + layout->addRow(edit_area_button); + layout->addRow(add_zone_button); + layout->addRow(add_subzone_button); + + setMinimumWidth(250); + + connect(_area_tree, &QTreeWidget::itemSelectionChanged + , [this] + { + auto const& selected_items = _area_tree->selectedItems(); + if (selected_items.size()) + { + emit selected(selected_items.back()->data(0, 1).toInt()); + } + } + ); + + connect(_area_tree, &QTreeWidget::itemDoubleClicked + , [this] + { + open_area_editor(); + }); + + connect(_radius_spin, qOverload(&QDoubleSpinBox::valueChanged) + , [&](double v) + { + _radius = v; + QSignalBlocker const blocker(_radius_slider); + _radius_slider->setSliderPosition((int)std::round(v)); + } + ); + + connect(_radius_slider, &QSlider::valueChanged + , [&](int v) + { + _radius = v; + QSignalBlocker const blocker(_radius_spin); + _radius_spin->setValue(v); + } + ); + + connect(edit_area_button, &QPushButton::clicked, [=]() { + open_area_editor(); + }); + + connect(add_zone_button, &QPushButton::clicked, [=]() { + add_new_zone(); + }); + + connect(add_subzone_button, &QPushButton::clicked, [=]() { + add_new_subzone(); + }); } - } - buildAreaList(); - } - - void zone_id_browser::setZoneID(int id) - { - QSignalBlocker const block_area_tree(_area_tree); - - if (_items.find(id) != _items.end()) - { - _area_tree->selectionModel()->clear(); - auto* item = _items.at(id); - - item->setSelected(true); - - while ((item = item->parent())) + void zone_id_browser::setMapID(int id) { - item->setExpanded(true); + mapID = id; + + for (DBCFile::Iterator i = gMapDB.begin(); i != gMapDB.end(); ++i) + { + if (i->getInt(MapDB::MapID) == id) + { + std::stringstream ss; + ss << id << "-" << i->getString(MapDB::InternalName); + _area_tree->setHeaderLabel(ss.str().c_str()); + } + } + + buildAreaList(); } - } - } - void zone_id_browser::buildAreaList() - { - QSignalBlocker const block_area_tree(_area_tree); - _area_tree->clear(); - _area_tree->setColumnCount(1); - _items.clear(); - - // Read out Area List. - for (DBCFile::Iterator i = gAreaDB.begin(); i != gAreaDB.end(); ++i) - { - if (i->getInt(AreaDB::Continent) == mapID) + void zone_id_browser::setZoneID(int id) { - add_area(i->getInt(AreaDB::AreaID)); + QSignalBlocker const block_area_tree(_area_tree); + + if (_items.find(id) != _items.end()) + { + _area_tree->selectionModel()->clear(); + auto* item = _items.at(id); + + item->setSelected(true); + + while ((item = item->parent())) + { + item->setExpanded(true); + } + } } - } + + void zone_id_browser::buildAreaList() + { + QSignalBlocker const block_area_tree(_area_tree); + _area_tree->clear(); + _area_tree->setColumnCount(1); + _items.clear(); + + // Read out Area List. + for (DBCFile::Iterator i = gAreaDB.begin(); i != gAreaDB.end(); ++i) + { + if (i->getInt(AreaDB::Continent) == mapID) + { + add_area(i->getInt(AreaDB::AreaID)); + } + } + } + + void zone_id_browser::changeRadius(float change) + { + _radius_spin->setValue(_radius + change); + } + + void zone_id_browser::setRadius(float radius) + { + _radius_spin->setValue(radius); + } + + int zone_id_browser::GetSelectedAreaId() + { + auto const& selected_items = _area_tree->selectedItems(); + if (selected_items.size()) + { + int selected_area_id = selected_items.back()->data(0, 1).toInt(); + return selected_area_id; + } + return 0; + } + + QTreeWidgetItem* zone_id_browser::create_or_get_tree_widget_item(int area_id) + { + auto it = _items.find(area_id); + + if (it != _items.end()) + { + return _items.at(area_id); + } + else + { + QTreeWidgetItem* item = new QTreeWidgetItem(); + + std::stringstream ss; + // ss << area_id << "-" << gAreaDB.getAreaName(area_id); + std::string areaName = ""; + try + { + AreaDB::Record rec = gAreaDB.getByID(area_id); + areaName = rec.getLocalizedString(AreaDB::Name); + } + catch (AreaDB::NotFound) + { + areaName = "Unknown location"; + } + ss << area_id << "-" << areaName; + item->setData(0, 1, QVariant(area_id)); + item->setText(0, QString(ss.str().c_str())); + _items.emplace(area_id, item); + + return item; + } + } + + QTreeWidgetItem* zone_id_browser::add_area(int area_id) + { + QTreeWidgetItem* item = create_or_get_tree_widget_item(area_id); + + std::uint32_t parent_area_id = gAreaDB.get_area_parent(area_id); + + if (parent_area_id && parent_area_id != area_id) + { + QTreeWidgetItem* parent_item = add_area(parent_area_id); + parent_item->addChild(item); + } + else + { + _area_tree->addTopLevelItem(item); + } + + return item; + } + + void zone_id_browser::open_area_editor() + { + // opens and loads the area editor with the currently selected item in the tree. + int selected_area_id = GetSelectedAreaId(); + if (selected_area_id != 0) + { + _area_editor->load_area(selected_area_id); + _area_editor->show(); + } + else + { + // No selected area popup + } + } + + void zone_id_browser::add_new_zone() + { + // create new zone area id + auto new_id = gAreaDB.getEmptyRecordID(); + auto new_record = gAreaDB.addRecord(new_id); + // init some defaults + new_record.write(AreaDB::Continent, mapID); + // get new areabit + new_record.write(AreaDB::AreaBit, gAreaDB.get_new_areabit()); + new_record.write(AreaDB::Flags, 64); // allow dueling, seems to the be the common default for regions + new_record.write(AreaDB::UnderwaterSoundProviderPreferences, 11); // underwater sound pref, usually set + + // locale stuff + new_record.writeString(AreaDB::Name, "Unnamed Noggit Zone"); // only write default name for enUS and enGB ? maybe get the client's locale somehow + new_record.writeString(AreaDB::Name + 1, "Unnamed Noggit Zone"); // enGB + new_record.write(AreaDB::Name + 16, 16712190); // loc mask, only verified for enUS + + new_record.write(AreaDB::MinElevation, -500.0f); // loc mask, only verified for enUS + // save dbc instantly ? + gAreaDB.save(); + // add to tree + auto areawidgetitem = add_area(new_id); + // select the new item + _area_tree->clearSelection(); + areawidgetitem->setSelected(true); + open_area_editor();// open the editor + } + + void zone_id_browser::add_new_subzone() + { + // create new subzone area id + // set selected as parent + int selected_areaid = GetSelectedAreaId(); + if (!selected_areaid) // no valid item selected + return; + // check if it's a valid parent : it shouldn't have a parent + std::uint32_t selected_parent_area_id = gAreaDB.get_area_parent(selected_areaid); // the selected area's parentid + if (selected_parent_area_id) + { + // error, parent must not have a parent + QMessageBox messagebox; + messagebox.setIcon(QMessageBox::Information); + messagebox.setWindowIcon(QIcon(":/icon")); + messagebox.setWindowTitle("Wrong Parent type"); + messagebox.setText("The parent must be a Zone, not a Subzone."); + messagebox.exec(); + return; + } + + auto new_id = gAreaDB.getEmptyRecordID(); + auto new_record = gAreaDB.addRecord(new_id); + // init some defaults + new_record.write(AreaDB::Continent, mapID); + + new_record.write(AreaDB::Region, selected_areaid); // set selecetd area as parent. + // get new areabit + new_record.write(AreaDB::AreaBit, gAreaDB.get_new_areabit()); + new_record.write(AreaDB::Flags, 1073759296); // allow dueling + force area on dynamic transport + enable flight bounds+ subzone flags + new_record.write(AreaDB::UnderwaterSoundProviderPreferences, 11); // underwater sound pref, usually set + // lcoale stuff + new_record.writeString(AreaDB::Name, "Unnamed Noggit Subzone"); // only write default name for enUS and enGB ? maybe get the client's locale somehow + new_record.writeString(AreaDB::Name + 1, "Unnamed Noggit Subzone"); // enGB + new_record.write(AreaDB::Name + 16, 16712190); // loc mask, only verified for enUS + + new_record.write(AreaDB::MinElevation, -500.0f); // loc mask, only verified for enUS + // save dbc instantly ? + gAreaDB.save(); + // add to tree + auto areawidgetitem = add_area(new_id); + // select the new item + _area_tree->clearSelection(); + areawidgetitem->setSelected(true); + open_area_editor();// open the editor + } + + + AreaEditor::AreaEditor(QWidget* parent) + : QWidget(parent) + { + setWindowTitle("Area Editor"); + setWindowFlags(Qt::Dialog); + // setWindowFlags(Qt::Widget); + + auto main_layout = new QHBoxLayout(this); + + QGroupBox* area_settings_group = new QGroupBox("Area Settings", this); + main_layout->addWidget(area_settings_group); + auto layout = new QFormLayout(area_settings_group); + // main_layout->addLayout(layout); + + _area_id_label = new QLabel("0", this); + _area_id_label->setEnabled(false); + + _parent_area_label = new QLabel("-NONE-", area_settings_group); + _parent_area_label->setEnabled(false); + + // auto parent_set_layout = new QHBoxLayout(this); + _set_parent_button = new QPushButton("Set Selected Zone as Parent", area_settings_group); + // QPushButton* unset_parent_button = new QPushButton("Unset Parent", this); + // parent_set_layout->addWidget(set_parent_button); + // parent_set_layout->addWidget(unset_parent_button); + + _area_name = new Tools::MapCreationWizard::Ui::LocaleDBCEntry(area_settings_group); + + _exploration_level_spinbox = new QSpinBox(this); + _exploration_level_spinbox->setRange(-1, 255); + + _ambiant_multiplier = new QSlider(Qt::Horizontal, this); + _ambiant_multiplier->setRange(0, 100); // 0.0 - 1.0, decimal not supported so *100 + _ambiant_multiplier->setTickInterval(5); + _ambiant_multiplier->setSingleStep(5); + + // faction group + // read FactionGroup.dbc or just hardcode? + _faction_group_combobox = new QComboBox(this); + _faction_group_combobox->addItem("Contested"); // 0 + _faction_group_combobox->addItem("Alliance"); // 2 + _faction_group_combobox->addItem("Horde"); // 4 + _faction_group_combobox->addItem("Horde & Alliance"); // mask : 2 + 4 + + // _liquid_type_water_combobox = new QComboBox(this); + // _liquid_type_water_combobox->addItem("None"); + // _liquid_type_ocean_combobox = new QComboBox(this); + // _liquid_type_ocean_combobox->addItem("None"); + // _liquid_type_magma_combobox = new QComboBox(this); + // _liquid_type_magma_combobox->addItem("None"); + // _liquid_type_slime_combobox = new QComboBox(this); + // _liquid_type_slime_combobox->addItem("None"); + // for (DBCFile::Iterator i = gLiquidTypeDB.begin(); i != gLiquidTypeDB.end(); ++i) + // { + // std::stringstream ss; + // int liquid_type = i->getInt(LiquidTypeDB::Type); + // ss << i->getInt(LiquidTypeDB::ID) << "-" << i->getString(LiquidTypeDB::Name); + // switch (liquid_type) + // { + // case 0: + // _liquid_type_water_combobox->addItem(i->getString(LiquidTypeDB::Name)); + // break; + // case 1: + // _liquid_type_ocean_combobox->addItem(i->getString(LiquidTypeDB::Name)); + // break; + // case 2: + // _liquid_type_magma_combobox->addItem(i->getString(LiquidTypeDB::Name)); + // break; + // case 3: + // _liquid_type_slime_combobox->addItem(i->getString(LiquidTypeDB::Name)); + // } + // } + + _sound_provider_preferences_cbbox = new QComboBox(this); + _sound_provider_preferences_cbbox->addItem("None"); + + _underwater_sound_provider_preferences_cbbox = new QComboBox(this); + _underwater_sound_provider_preferences_cbbox->addItem("None"); + for (DBCFile::Iterator i = gSoundProviderPreferencesDB.begin(); i != gSoundProviderPreferencesDB.end(); ++i) + { + std::stringstream ss; + ss << i->getInt(SoundProviderPreferencesDB::ID) << "-" << i->getString(SoundProviderPreferencesDB::Description); + + _sound_provider_preferences_cbbox->addItem(ss.str().c_str()); + _underwater_sound_provider_preferences_cbbox->addItem(ss.str().c_str()); + } + + _sound_ambiance_day_button = new QPushButton("-None-", this); + _sound_ambiance_day_button->setProperty("id", 0); + connect(_sound_ambiance_day_button, &QPushButton::clicked, [=]() { + auto window = new SoundEntryPickerWindow(_sound_ambiance_day_button, SoundEntryTypes::ZONE_AMBIENCE, false, this); + window->show(); + }); + + _sound_ambiance_night_button = new QPushButton("-None-", this); + _sound_ambiance_night_button->setProperty("id", 0); + connect(_sound_ambiance_night_button, &QPushButton::clicked, [=]() { + auto window = new SoundEntryPickerWindow(_sound_ambiance_night_button, SoundEntryTypes::ZONE_AMBIENCE, false, this); + window->show(); + }); + + _zone_music_button = new QPushButton("-None-", this); + _zone_music_button->setProperty("id", 0); + connect(_zone_music_button, &QPushButton::clicked, [=]() { + auto window = new ZoneMusicPickerWindow(_zone_music_button, this); + window->show(); + }); + + _zone_intro_music_button = new QPushButton("-None-", this); + _zone_intro_music_button->setProperty("id", 0); + connect(_zone_intro_music_button, &QPushButton::clicked, [=]() { + auto window = new ZoneIntroMusicPickerWindow(_zone_intro_music_button, this); + window->show(); + }); + + // advanced settings group + auto* AdvancedOptionsBox = new ExpanderWidget(this); + AdvancedOptionsBox->setExpanderTitle("Advanced Options"); + // selectionOptionsBox->setExpanded(_settings->value("object_editor/movement_options", false).toBool()); + + auto advancedOptionsBox_content = new QWidget(this); + auto advancedOptions_layout = new QFormLayout(advancedOptionsBox_content); + // advancedOptions_layout->setAlignment(Qt::AlignTop); + AdvancedOptionsBox->addPage(advancedOptionsBox_content); + AdvancedOptionsBox->setExpanded(false); + + _min_elevation_spinbox = new QDoubleSpinBox(this); + _min_elevation_spinbox->setRange(-5000, 5000); // only 3 known values : -5000, -500, 1000 + _min_elevation_spinbox->setSingleStep(100); + + advancedOptions_layout->addRow("Min Elevation:", _min_elevation_spinbox); + advancedOptions_layout->addRow("Ambiant Multiplier:", _ambiant_multiplier); + // advancedOptions_layout->addRow("Water Liquid Type override:", _liquid_type_water_combobox); + // advancedOptions_layout->addRow("Ocean Liquid Type override:", _liquid_type_ocean_combobox); + // advancedOptions_layout->addRow("Magma Liquid Type override:", _liquid_type_magma_combobox); + // advancedOptions_layout->addRow("Slime Liquid Type override:", _liquid_type_slime_combobox); + advancedOptions_layout->addRow("Sound Provider Preference:", _sound_provider_preferences_cbbox); + advancedOptions_layout->addRow("Underwater Sound Provider Preference:", _underwater_sound_provider_preferences_cbbox); + + + QPushButton* save_area_button = new QPushButton("Save changes (write DBC)", this); + // TODO : unset parent button? + + // flags tab **************************// + + QGroupBox* area_flags_group = new QGroupBox("Flags", this); + main_layout->addWidget(area_flags_group); + auto flags_layout = new QVBoxLayout(area_flags_group); + + _flags_value_spinbox = new QSpinBox(this); + _flags_value_spinbox->setRange(0, INT_MAX); // uint? + flags_layout->addWidget(_flags_value_spinbox); + + // TODO : update checkboxes when value is changed, temporarly disable it from edit + _flags_value_spinbox->setEnabled(false); + + for (int i = 0; i < 31; ++i) + { + QCheckBox* flag_checkbox = new QCheckBox(QString::fromStdString(area_flags_names.at(i)), this); + flags_checkboxes[i] = flag_checkbox; + + flags_layout->addWidget(flag_checkbox); + + connect(flag_checkbox, &QCheckBox::stateChanged, [&, i](bool state) { + // connect(flag_checkbox, &QCheckBox::clicked, [=]() { + // int old_value = _flags_value_spinbox->value(); + int new_value = _flags_value_spinbox->value(); + if (state) // set bit + new_value |= (1ULL << (i)); + else // remove bit + new_value &= ~(1ULL << (i)); + + _flags_value_spinbox->setValue(new_value); + }); + } + // hide some useless flags to gain space + flags_checkboxes[30]->setEnabled(false); // user can't set subzone flag. + flags_checkboxes[30]->setHidden(true); // subzone flag + flags_checkboxes[20]->setHidden(true); // tournement realm thingy, useless for pservers + flags_checkboxes[17]->setHidden(true); // "Area not in use", prob some blizz dev stuff + //************************************// + layout->addRow("Area ID:", _area_id_label); + layout->addRow("Area Name:", _area_name); + layout->addWidget(_set_parent_button); + layout->addRow("Parent Area ID:", _parent_area_label); + layout->addRow("Faction Group:", _faction_group_combobox); + layout->addRow("Exploration Level:", _exploration_level_spinbox); + layout->addRow("Zone Music:", _zone_music_button); + layout->addRow("Zone Intro Music:", _zone_intro_music_button); + layout->addRow("Sound Ambience Day:", _sound_ambiance_day_button); + layout->addRow("Sound Ambience Night:", _sound_ambiance_night_button); + + layout->addRow(AdvancedOptionsBox); + layout->addRow(save_area_button); + + layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); + + // main_layout->addStretch(); + + connect(_set_parent_button, &QPushButton::clicked, [=]() { + + // Current design choice : Cannot change a zone to be a subzone or the opposite, only current subzones can have a parent set. + auto parent = static_cast(this->parentWidget()); + auto tree_selected_id = parent->GetSelectedAreaId(); + if (!tree_selected_id) + return; + // can only set a zone as parent, not a subzone. + // a zone must be a top level item, and not have a parent or the subzone flag. + + // checks : + // 1 : current area must be a subzone + if (!_parent_area_id) + return; + + std::uint32_t selected_parent_area_id = gAreaDB.get_area_parent(tree_selected_id); // the selected area's parentid + if (selected_parent_area_id) + { + // error, parent must not have a parent + QMessageBox messagebox; + messagebox.setIcon(QMessageBox::Information); + messagebox.setWindowIcon(QIcon(":/icon")); + messagebox.setWindowTitle("Wrong Parent type"); + messagebox.setText("The parent must be a Zone, not a Subzone."); + messagebox.exec(); + return; + } + // can't be self + if (tree_selected_id == _parent_area_id) + return;// same parent, ignore + if (tree_selected_id == _area_id_label->text().toInt()) + return; // error, can't select self + + // save the change for the session (don't write dbc yet) + _parent_area_id = tree_selected_id; + std::stringstream ss; + ss << _parent_area_id << "-" << gAreaDB.getAreaName(_parent_area_id); + _parent_area_label->setText(ss.str().c_str()); + + // _parent_area_label->setText(std::to_string( tree_selected_id).c_str()); + auto curr_record = gAreaDB.getByID(_area_id_label->text().toInt()); + curr_record.write(AreaDB::Region, tree_selected_id); + // update the tree + parent->buildAreaList(); + // select the item ? + auto item = parent->create_or_get_tree_widget_item(_area_id_label->text().toInt()); + // parent->selected(_area_id_label->text().toInt()); + }); + + connect(save_area_button, &QPushButton::clicked, [=]() { + save_area();// save and write DBC + }); + + connect(_flags_value_spinbox, qOverload(&QSpinBox::valueChanged), [&](int v) { + + // std::bitset<32> IntBits(_flags_value_spinbox->value()); + // + // for (int i = 0; i < 31; i++) + // flags_checkboxes[i]->setChecked(IntBits[i]); + }); + } + + void AreaEditor::load_area(int area_id) + { + DBCFile::Record record = gAreaDB.getByID(area_id); + // record.getString(AreaDB::Name) + + _area_id_label->setText(QString(std::to_string(area_id).c_str())); + + _areabit = record.getInt(AreaDB::AreaBit); + + _parent_area_id = record.getInt(AreaDB::Region); + + if (_parent_area_id) + { + std::stringstream ss; + ss << _parent_area_id << "-" << gAreaDB.getAreaName(_parent_area_id); + _parent_area_label->setText(ss.str().c_str()); + } + else + _parent_area_label->setText("-NONE-"); + + // hide some UI if not subzone + _set_parent_button->setHidden(_parent_area_id ? false : true); + + // _area_name_ledit->setText(record.getString(AreaDB::Name)); + _area_name->fill(record, AreaDB::Name); + + _flags_value_spinbox->setValue(record.getInt(AreaDB::Flags)); + + std::bitset<32> IntBits(_flags_value_spinbox->value()); + for (int i = 0; i < 31; i++) + flags_checkboxes[i]->setChecked(IntBits[i]); + + _exploration_level_spinbox->setValue(record.getInt(AreaDB::ExplorationLevel)); + + int faction_group_mask = record.getInt(AreaDB::FactionGroup); + switch (faction_group_mask) // hardcoded but can be read from factiongroup.dbc + { + case 2: + _faction_group_combobox->setCurrentIndex(1); + break; + case 4: + _faction_group_combobox->setCurrentIndex(2); + break; + case 6: + _faction_group_combobox->setCurrentIndex(3); + break; + default: + _faction_group_combobox->setCurrentIndex(0); + } + + _min_elevation_spinbox->setValue(record.getFloat(AreaDB::MinElevation)); // only 3 known values : -5000, -500, 1000 + + _ambiant_multiplier->setValue(record.getFloat(AreaDB::AmbientMultiplier) * 100); + + int sound_provider_id = record.getInt(AreaDB::SoundProviderPreferences); + if (sound_provider_id != 0) + { + int row_id = gSoundProviderPreferencesDB.getRecordRowId(sound_provider_id); + _sound_provider_preferences_cbbox->setCurrentIndex(row_id + 1); // index 0 = "None" + } + else + _sound_provider_preferences_cbbox->setCurrentIndex(0); + + int underwater_sound_provider_id = record.getInt(AreaDB::UnderwaterSoundProviderPreferences); + if (underwater_sound_provider_id != 0) + { + int row_id = gSoundProviderPreferencesDB.getRecordRowId(underwater_sound_provider_id); + _underwater_sound_provider_preferences_cbbox->setCurrentIndex(row_id + 1); // index 0 = "None" + } + else + _underwater_sound_provider_preferences_cbbox->setCurrentIndex(0); + + int zone_music_id = record.getInt(AreaDB::ZoneMusic); + _zone_music_button->setProperty("id", zone_music_id); + if (zone_music_id != 0) + { + auto zone_music_record = gZoneMusicDB.getByID(zone_music_id); + std::stringstream ss; + ss << zone_music_id << "-" << zone_music_record.getString(ZoneMusicDB::Name); + _zone_music_button->setText(ss.str().c_str()); + } + else + _zone_music_button->setText("-NONE-"); + + + int zone_intro_music_id = record.getInt(AreaDB::ZoneIntroMusicTable); + _zone_intro_music_button->setProperty("id", zone_intro_music_id); + if (zone_intro_music_id != 0) + { + auto zone_intro_music_record = gZoneIntroMusicTableDB.getByID(zone_intro_music_id); + std::stringstream ss; + ss << zone_intro_music_id << "-" << zone_intro_music_record.getString(ZoneIntroMusicTableDB::Name); + _zone_intro_music_button->setText(ss.str().c_str()); + } + else + _zone_intro_music_button->setText("-NONE-"); + + int sound_ambiance_id = record.getInt(AreaDB::SoundAmbience); + if (sound_ambiance_id != 0) + { + auto sound_ambiance_record = gSoundAmbienceDB.getByID(sound_ambiance_id); + + int day_sound_id = sound_ambiance_record.getInt(SoundAmbienceDB::SoundEntry_day); + auto sound_entry_day_record = gSoundEntriesDB.getByID(day_sound_id); + int night_sound_id = sound_ambiance_record.getInt(SoundAmbienceDB::SoundEntry_night); + auto sound_entry_night_record = gSoundEntriesDB.getByID(night_sound_id); + + std::stringstream ss_day; + ss_day << day_sound_id << "-" << sound_entry_day_record.getString(SoundEntriesDB::Name); + _sound_ambiance_day_button->setText(ss_day.str().c_str()); + _sound_ambiance_day_button->setProperty("id", day_sound_id); + + std::stringstream ss_night; + ss_night << night_sound_id << "-" << sound_entry_night_record.getString(SoundEntriesDB::Name); + _sound_ambiance_night_button->setText(ss_night.str().c_str()); + _sound_ambiance_night_button->setProperty("id", night_sound_id); + } + else + { + _sound_ambiance_day_button->setProperty("id", 0); + _sound_ambiance_day_button->setText("-NONE-"); + _sound_ambiance_night_button->setProperty("id", 0); + _sound_ambiance_night_button->setText("-NONE-"); + } + + } + + void AreaEditor::save_area() + { + DBCFile::Record record = gAreaDB.getByID(_area_id_label->text().toInt()); // is_new_record ? gLightDB.addRecord(Id) : gLightDB.getByID(Id); + // record.write(AreaDB::ID, entry_id); + // rewrite mapid ? + record.write(AreaDB::Region, _parent_area_id); + record.write(AreaDB::AreaBit, _areabit); + record.write(AreaDB::Flags, _flags_value_spinbox->value()); + + int SoundProviderPreferences_id = 0; + if (_sound_provider_preferences_cbbox->currentIndex() != 0) + { + auto rec = gSoundProviderPreferencesDB.getRecord(_sound_provider_preferences_cbbox->currentIndex() - 1); + SoundProviderPreferences_id = rec.getInt(SoundProviderPreferencesDB::ID); + } + record.write(AreaDB::SoundProviderPreferences, SoundProviderPreferences_id); + + int underwaterSoundProviderPreferences_id = 0; + if (_underwater_sound_provider_preferences_cbbox->currentIndex() != 0) + { + auto rec = gSoundProviderPreferencesDB.getRecord(_underwater_sound_provider_preferences_cbbox->currentIndex() - 1); + underwaterSoundProviderPreferences_id = rec.getInt(SoundProviderPreferencesDB::ID); + } + record.write(AreaDB::UnderwaterSoundProviderPreferences, underwaterSoundProviderPreferences_id); + + // Ambiance ID. Blizzard stores those as unamed pair + // Just iterate the DBC to see if an entry with our settings already exists, if not create it. + // The reasoning for not having a selector/picker with the existing pairs is that it has less freedom, is harder to use and it's ugly if they don't have a name. + // This doesn't have the option to edit that entry for all its users though. + bool sound_ambiance_exists {false}; + for (DBCFile::Iterator i = gSoundAmbienceDB.begin(); i != gSoundAmbienceDB.end(); ++i) + { + int day_id = i->getInt(SoundAmbienceDB::SoundEntry_day); + int night_id = i->getInt(SoundAmbienceDB::SoundEntry_night); + if (day_id == _sound_ambiance_day_button->property("id").toInt() && night_id == _sound_ambiance_night_button->property("id").toInt()) + { + record.write(AreaDB::SoundAmbience, i->getInt(SoundAmbienceDB::ID)); + sound_ambiance_exists = true; + break; + } + } + if (!sound_ambiance_exists) + { + // create new sond entry record + auto new_id = gSoundAmbienceDB.getEmptyRecordID(); + auto new_record = gSoundAmbienceDB.addRecord(new_id); + + new_record.write(SoundAmbienceDB::SoundEntry_day, _sound_ambiance_day_button->property("id").toInt()); + new_record.write(SoundAmbienceDB::SoundEntry_night, _sound_ambiance_night_button->property("id").toInt()); + gSoundAmbienceDB.save(); + } + + record.write(AreaDB::ZoneMusic, _zone_music_button->property("id").toInt()); + record.write(AreaDB::ZoneIntroMusicTable, _zone_intro_music_button->property("id").toInt()); + + record.write(AreaDB::ExplorationLevel, _exploration_level_spinbox->value()); + + _area_name->toRecord(record, AreaDB::Name); + + record.write(AreaDB::FactionGroup, _faction_group_combobox->currentIndex() * 2); + record.write(AreaDB::MinElevation, static_cast(_min_elevation_spinbox->value())); + record.write(AreaDB::AmbientMultiplier, _ambiant_multiplier->value() / 100.0f); + record.write(AreaDB::LightId, 0); // never used + + gAreaDB.save(); + } + } - void zone_id_browser::changeRadius(float change) - { - _radius_spin->setValue (_radius + change); - } - - void zone_id_browser::setRadius(float radius) - { - _radius_spin->setValue(radius); - } - - QTreeWidgetItem* zone_id_browser::create_or_get_tree_widget_item(int area_id) - { - auto it = _items.find(area_id); - - if (it != _items.end()) - { - return _items.at(area_id); - } - else - { - QTreeWidgetItem* item = new QTreeWidgetItem(); - - std::stringstream ss; - ss << area_id << "-" << gAreaDB.getAreaName(area_id); - item->setData(0, 1, QVariant(area_id)); - item->setText(0, QString(ss.str().c_str())); - _items.emplace(area_id, item); - - return item; - } - } - - QTreeWidgetItem* zone_id_browser::add_area(int area_id) - { - QTreeWidgetItem* item = create_or_get_tree_widget_item(area_id); - - std::uint32_t parent_area_id = gAreaDB.get_area_parent(area_id); - - if (parent_area_id && parent_area_id != area_id) - { - QTreeWidgetItem* parent_item = add_area(parent_area_id); - parent_item->addChild(item); - } - else - { - _area_tree->addTopLevelItem(item); - } - - return item; - } - } } diff --git a/src/noggit/ui/ZoneIDBrowser.h b/src/noggit/ui/ZoneIDBrowser.h index 1a7aea03..5d26624b 100755 --- a/src/noggit/ui/ZoneIDBrowser.h +++ b/src/noggit/ui/ZoneIDBrowser.h @@ -2,10 +2,21 @@ #pragma once +#include +#include + #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -14,6 +25,78 @@ namespace Noggit { namespace Ui { + + static std::map area_flags_names = { + {0 , "Emit Breath Particles"}, + {1 , "Breath Particles Override Parent"}, + {2 , "On Map Dungeon"}, + {3 , "Allow Trade Channel"}, + {4 , "Enemies PvP Flagged"}, + {5 , "Allow Resting"}, + {6 , "Allow Dueling"}, + {7 , "Free For All PvP"}, + {8 , "Linked Chat (Set in cities)"}, + {9 , "Linked Chat Special Area"}, + {10, "Force this area when on a Dynamic Transport"}, + {11, "No PvP"}, + {12, "No Ghost on Release"}, + {13, "Sub-zone Ambient Multiplier"}, + {14, "Enable Flight Bounds on Map"}, + {15, "PVP POI"}, + {16, "No chat channels"}, + {17, "Area not in use"}, + {18, "Contested"}, + {19, "No Player Summoning"}, + {20, "No Dueling if Tournament Realm"}, + {21, "Players Call Guards"}, + {22, "Horde Resting"}, + {23, "Alliance Resting"}, + {24, "Combat Zone"}, + {25, "Force Indoors"}, + {26, "Force Outdoors"}, + {27, "Allow Hearth-and-Resurrect from Area"}, + {28, "No Local Defense Channel"}, + {29, "Only Evaluate Ghost Bind Once"}, + {30, "Is Subzone"}, + // {31, "Don't Evaluate Graveyard From Client"} + }; + + class AreaEditor : public QWidget + { + Q_OBJECT + public: + AreaEditor(QWidget* parent = nullptr); + + void load_area(int area_id); + private: + QLabel* _area_id_label; + QLabel* _parent_area_label; + int _parent_area_id = 0; + QPushButton* _set_parent_button; + QSpinBox* _flags_value_spinbox; + Tools::MapCreationWizard::Ui::LocaleDBCEntry* _area_name; + QCheckBox* flags_checkboxes[31]{ 0 }; + QSpinBox* _exploration_level_spinbox; + QDoubleSpinBox* _min_elevation_spinbox; + QSlider* _ambiant_multiplier; + QComboBox* _faction_group_combobox; + QComboBox* _sound_provider_preferences_cbbox; + QComboBox* _underwater_sound_provider_preferences_cbbox; + // QComboBox* _liquid_type_water_combobox; + // QComboBox* _liquid_type_ocean_combobox; + // QComboBox* _liquid_type_magma_combobox; + // QComboBox* _liquid_type_slime_combobox; + + QPushButton* _zone_music_button; + QPushButton* _zone_intro_music_button; + QPushButton* _sound_ambiance_day_button; + QPushButton* _sound_ambiance_night_button; + + void save_area(); + + int _areabit = 0; + }; + class zone_id_browser : public QWidget { Q_OBJECT @@ -27,6 +110,10 @@ namespace Noggit float brushRadius() const { return _radius; } + int GetSelectedAreaId(); + void buildAreaList(); + QTreeWidgetItem* create_or_get_tree_widget_item(int area_id); + signals: void selected (int area_id); @@ -36,13 +123,18 @@ namespace Noggit QSlider* _radius_slider; QDoubleSpinBox* _radius_spin; + AreaEditor* _area_editor; + std::map _items; int mapID; float _radius = 15.0f; - void buildAreaList(); - QTreeWidgetItem* create_or_get_tree_widget_item(int area_id); QTreeWidgetItem* add_area(int area_id); + void open_area_editor(); + void add_new_zone(); + void add_new_subzone(); }; + + } } diff --git a/src/noggit/ui/windows/EditorWindows/SoundEntryPickerWindow.cpp b/src/noggit/ui/windows/EditorWindows/SoundEntryPickerWindow.cpp new file mode 100644 index 00000000..f1451c47 --- /dev/null +++ b/src/noggit/ui/windows/EditorWindows/SoundEntryPickerWindow.cpp @@ -0,0 +1,479 @@ +#include "SoundEntryPickerWindow.h" +#include +// #include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +namespace Noggit +{ + namespace Ui + { + SoundEntryPickerWindow::SoundEntryPickerWindow(QPushButton* button, int sound_type_filter, bool allow_none, QWidget* parent) + : QWidget(parent) + { + setWindowTitle("Sound Entry Picker"); + setWindowFlags(Qt::Dialog); + + auto layout = new QHBoxLayout(this); + + auto list_layout = new QVBoxLayout(this); + + auto Editor_layout = new QVBoxLayout(this); + + layout->addLayout(list_layout); + layout->addLayout(Editor_layout); + + _tree_searchbar = new QLineEdit(this); + list_layout->addWidget(_tree_searchbar); + + + _tree_filter_cbbox = new QComboBox(this); + _tree_filter_cbbox->addItem("Show All"); + for (auto sound_types : sound_types_names) + { + _tree_filter_cbbox->addItem(sound_types.second.c_str()); + } + list_layout->addWidget(_tree_filter_cbbox); + + _picker_listview = new QListWidget(this); + _picker_listview->setFixedSize(280, 460); + _picker_listview->setSelectionMode(QListWidget::SingleSelection); + // _picker_listview->setSelectionBehavior(QAbstractItemView::SelectionBehavior::SelectRows); + list_layout->addWidget(_picker_listview); + + if (sound_type_filter == -1) + { + _tree_filter_cbbox->setCurrentIndex(0); + filter_sound_type(sound_type_filter, true); + } + else + { + int row_id = 0; + for (auto sound_type_pair : sound_types_names) + { + if (sound_type_pair.first == sound_type_filter) + { + _tree_filter_cbbox->setCurrentIndex(row_id + 1); + filter_sound_type(sound_type_filter); + break; + } + row_id++; + } + } + + auto select_entry_btn = new QPushButton("Select Entry", this); + auto select_entry_none_btn = new QPushButton("Select -NONE-", this); + auto duplicate_entry_btn = new QPushButton("Duplicate selected Entry (create new)", this); + list_layout->addWidget(duplicate_entry_btn); + list_layout->addWidget(select_entry_btn); + list_layout->addWidget(select_entry_none_btn); + + list_layout->addStretch(); + + // Editor frame + QGroupBox* editor_group = new QGroupBox("Edit Selected Entry", this); + Editor_layout->addWidget(editor_group); + + auto editor_form_layout = new QFormLayout(editor_group); + + _entry_id_lbl = new QLabel(this); + editor_form_layout->addRow("Id:", _entry_id_lbl); + _entry_id_lbl->setEnabled(false); + + _name_ledit = new QLineEdit(this); + editor_form_layout->addRow("Sound Entry Name:", _name_ledit); + + _sound_type_cbbox = new QComboBox(this); + for (auto sound_type : sound_types_names) + { + _sound_type_cbbox->addItem(sound_type.second.c_str(), sound_type.first); + } + editor_form_layout->addRow("Sound Type:", _sound_type_cbbox); + + _volume_slider = new QSlider(Qt::Horizontal, this); + _volume_slider->setMaximum(100); + // ticks should be 1, should bt QT's default ? + editor_form_layout->addRow("Volume:", _volume_slider); + + _min_distance_spinbox = new QSpinBox(this); + _min_distance_spinbox->setMaximum(1000); + editor_form_layout->addRow("Min Distance:", _min_distance_spinbox); + + _max_distance_spinbox = new QSpinBox(this); + _max_distance_spinbox->setMaximum(1000); + editor_form_layout->addRow("Distance Cut off:", _max_distance_spinbox); + + _eax_type_cbbox = new QComboBox(this); + _eax_type_cbbox->addItem("None"); + _eax_type_cbbox->addItem("Effect 1"); + _eax_type_cbbox->addItem("Effect 2"); + editor_form_layout->addRow("EAX definition:", _eax_type_cbbox); + + _flag6_checkbox = new QCheckBox("Use OS sound settings", this); + editor_form_layout->addRow(_flag6_checkbox); + _flag10_checkbox = new QCheckBox("PlaySpellLoopedSound", this); + editor_form_layout->addRow(_flag10_checkbox); + _flag11_checkbox = new QCheckBox("SetFrequencyAndVolume", this); + editor_form_layout->addRow(_flag11_checkbox); + + _directory_ledit = new QLineEdit(this); + editor_form_layout->addRow("Directory Path", _directory_ledit); + + auto filecount_layout = new QHBoxLayout(this); + Editor_layout->addLayout(filecount_layout); + + _filescount_lbl = new QLabel(this); + filecount_layout->addWidget(_filescount_lbl); + auto add_file_button = new QPushButton("Add sound file"); + filecount_layout->addWidget(add_file_button); + + _files_listview = new QListWidget(this); + _files_listview->setFixedHeight(400); + // _files_listview->setFixedSize(280, 460); + _files_listview->setSelectionMode(QListWidget::SingleSelection); + Editor_layout->addWidget(_files_listview); + + + auto save_music_entry_btn = new QPushButton("Save changes", this); + Editor_layout->addWidget(save_music_entry_btn, 0, Qt::AlignRight); + + Editor_layout->addStretch(); + + /// check if needed + select_entry(button->property("id").toInt()); + + connect(_tree_filter_cbbox, qOverload(&QComboBox::currentIndexChanged), [this](int index) { + + if (index == 0) // load all + filter_sound_type(0, true); + else + { + int sound_type_id = 0; + int row_id = 0; + for (auto sound_type : sound_types_names) + { + if (row_id == index - 1) + { + sound_type_id = sound_type.first; + break; + } + row_id++; + } + filter_sound_type(sound_type_id); + } + + }); + + connect(_tree_searchbar, &QLineEdit::textChanged, [=](QString obj) { + if (obj.isEmpty()) + { + // unhide all + } + + // hide all items + for (int i = 0; i < _picker_listview->count(); i++) + { + auto item = _picker_listview->item(i); + item->setHidden(true); + } + // unhide matching items + auto matching_items = _picker_listview->findItems(obj, Qt::MatchContains); + + for (auto item : matching_items) + { + item->setHidden(false); + } + }); + + connect(_picker_listview, &QListWidget::itemClicked, this, [=](QListWidgetItem* item) { + select_entry(item->data(1).toInt()); + }); + + connect(select_entry_btn, &QPushButton::clicked, [=]() { + // auto selection = _picker_listview->selectedItems(); + auto selected_item = _picker_listview->currentItem(); + if (selected_item == nullptr) + return; + + button->setProperty("id", selected_item->data(1).toInt()); + button->setText(selected_item->text()); + this->close(); + }); + + connect(select_entry_none_btn, &QPushButton::clicked, [=]() { + button->setText("-NONE-"); + button->setProperty("id", 0); + this->close(); + }); + + connect(save_music_entry_btn, &QPushButton::clicked, [=]() { + save_entry(_entry_id); + }); + + connect(add_file_button, &QPushButton::clicked, [=]() { + + int new_row_id = _files_listview->count(); + if (new_row_id > 9) + return; // can't have more than 10 + + _filenames_ledits[new_row_id] = new QLineEdit(); // set parent in the widget class + _filenames_ledits[new_row_id]->setText("your_sound_file.mp3"); + auto file_widget = new SoundFileWListWidgetItem(_filenames_ledits[new_row_id], _directory_ledit->text().toStdString()); + + auto item = new QListWidgetItem(_files_listview); + _files_listview->setItemWidget(item, file_widget); + item->setSizeHint(QSize(_files_listview->width(), _files_listview->height() / 10)); + + _files_listview->addItem(item); + + update_files_count(); + + }); + + connect(duplicate_entry_btn, &QPushButton::clicked, [=]() { + auto new_id = gSoundEntriesDB.getEmptyRecordID(SoundEntriesDB::ID); + + auto new_record = gSoundEntriesDB.addRecord(new_id); + + _name_ledit->setText("Noggit Unnamed entry"); + + save_entry(new_id); + + // add new tree item + auto item = new QListWidgetItem(); + item->setData(1, new_id); + std::stringstream ss; + + _picker_listview->addItem(item); + + select_entry(new_id); + + ss << new_id << "-" << _name_ledit->text().toStdString(); + item->setText(ss.str().c_str()); + }); + } + + void SoundEntryPickerWindow::filter_sound_type(int sound_type, bool load_all) + { + _picker_listview->clear(); + for (DBCFile::Iterator i = gSoundEntriesDB.begin(); i != gSoundEntriesDB.end(); ++i) + { + if (!(i->getInt(SoundEntriesDB::SoundType) == sound_type) && !load_all) // it freezes for 2sec if we try to add directly all 13k items + continue; + + auto item = new QListWidgetItem(); + item->setData(1, i->getInt(SoundEntriesDB::ID)); + + std::stringstream ss; + ss << i->getInt(SoundEntriesDB::ID) << "-" << i->getString(SoundEntriesDB::Name); + + if (load_all) + ss << "(" << sound_types_names.at(i->getInt(SoundEntriesDB::SoundType)) << ')'; + item->setText(ss.str().c_str()); + + _picker_listview->addItem(item); + } + } + + void SoundEntryPickerWindow::select_entry(int id) + { + _entry_id = id; + + if (id != 0) + { + // _picker_listview->setCurrentRow(0); + // doesn't work because of the type filter ! :( + // _picker_listview->setCurrentRow(gSoundEntriesDB.getRecordRowId(id)); + } + else + { + _picker_listview->setCurrentRow(0); + return; + } + + _entry_id_lbl->setText(QString(std::to_string(id).c_str())); + + DBCFile::Record record = gSoundEntriesDB.getByID(id); + + _name_ledit->setText(record.getString(SoundEntriesDB::Name)); + + int sound_type_id = record.getInt(SoundEntriesDB::SoundType); + + int row_id = 0; + for (auto sound_type : sound_types_names) + { + if (sound_type.first == sound_type_id) + { + _sound_type_cbbox->setCurrentIndex(row_id); + break; + } + + row_id++; + } + + _eax_type_cbbox->setCurrentIndex(record.getInt(SoundEntriesDB::EAXDef)); + _min_distance_spinbox->setValue(record.getFloat(SoundEntriesDB::minDistance)); + _max_distance_spinbox->setValue(record.getFloat(SoundEntriesDB::distanceCutoff)); + _volume_slider->setValue(record.getFloat(SoundEntriesDB::Volume) * 100); + + int flags = record.getInt(SoundEntriesDB::Flags); + + _flag6_checkbox->setChecked((flags & (1 << (6 - 1))) ? true : false); + _flag10_checkbox->setChecked((flags & (1 << (10 - 1))) ? true : false); + _flag11_checkbox->setChecked((flags & (1 << (11 - 1))) ? true : false); + _flag12 = (flags & (1 << (12 - 1))) ? true : false; + + _directory_ledit->setText(record.getString(SoundEntriesDB::FilePath)); + + _files_listview->clear(); + for (int i = 0; i < 10; i++) + { + std::string filename = record.getString(SoundEntriesDB::Filenames + i); + // auto freq = record.getInt(SoundEntriesDB::Freq + i); + + if (filename.empty()) + continue; + + _filenames_ledits[i] = new QLineEdit(); // set parent in the widget class + _filenames_ledits[i]->setText(filename.c_str()); + auto file_widget = new SoundFileWListWidgetItem(_filenames_ledits[i], _directory_ledit->text().toStdString()); + + auto item = new QListWidgetItem(_files_listview); + _files_listview->setItemWidget(item, file_widget); + item->setSizeHint(QSize(_files_listview->width(), _files_listview->height() / 10) ); + + _files_listview->addItem(item); + } + update_files_count(); + + _sound_advanced_id = record.getInt(SoundEntriesDB::soundEntriesAdvancedID); + } + + void SoundEntryPickerWindow::save_entry(int entry_id) + { + DBCFile::Record record = gSoundEntriesDB.getByID(entry_id); + + + record.write(SoundEntriesDB::ID, entry_id); + + int sound_type_id = 0; + int row_id = 0; + for (auto sound_type : sound_types_names) + { + if (row_id == _sound_type_cbbox->currentIndex()) + { + sound_type_id = sound_type.first; + break; + } + row_id++; + } + record.write(SoundEntriesDB::SoundType, sound_type_id); + + record.writeString(SoundEntriesDB::Name, _name_ledit->text().toStdString()); + + // _files_listview->count() + int i = 0; + for (;i < _files_listview->count(); i++) + { + record.writeString(SoundEntriesDB::Filenames + i, _filenames_ledits[i]->text().toStdString()); + record.write(SoundEntriesDB::Freq + i, 1); // TODO. but in 99.9% 1 is fine + } + for (;i < 10; i++) // clean up unset entries + { + record.writeString(SoundEntriesDB::Filenames + i, ""); + record.write(SoundEntriesDB::Freq + i, 0); + } + + record.writeString(SoundEntriesDB::FilePath, _directory_ledit->text().toStdString()); + record.write(SoundEntriesDB::Volume, _volume_slider->value() / 100.0f); // should be a float + + int flags = 0; + if (_flag6_checkbox->isChecked()) + flags |= (1ULL << (5)); + if (_flag10_checkbox->isChecked()) + flags |= (1ULL << (9)); + if (_flag11_checkbox->isChecked()) + flags |= (1ULL << (10)); + if (_flag12) + flags |= (1ULL << (11)); + record.write(SoundEntriesDB::Flags, flags); + + record.write(SoundEntriesDB::minDistance, static_cast(_min_distance_spinbox->value())); + record.write(SoundEntriesDB::distanceCutoff, static_cast(_max_distance_spinbox->value())); + record.write(SoundEntriesDB::EAXDef, _eax_type_cbbox->currentIndex()); + record.write(SoundEntriesDB::soundEntriesAdvancedID, _sound_advanced_id); + + gSoundEntriesDB.save(); + } + + void SoundEntryPickerWindow::update_files_count() + { + int file_count = _files_listview->count(); + std::stringstream ss; + ss << "Files: " << std::to_string(file_count) << "/10"; + + _filescount_lbl->setText(ss.str().c_str()); + } + + SoundFileWListWidgetItem::SoundFileWListWidgetItem(QLineEdit* filename_ledit, std::string dirpath, QWidget* parent) // std::string filename + : QWidget(parent) + { + auto layout = new QHBoxLayout(this); + layout->addWidget(new QLabel("File:", this)); + + // auto lol = _filenames_ledits[i]; + // auto _filename_ledit = new QLineEdit(filename.c_str(), this); + filename_ledit->setParent(this); + filename_ledit->setFixedHeight(30); + layout->addWidget(filename_ledit); + + auto play_sound_button = new QToolButton(this); + play_sound_button->setIcon(Noggit::Ui::FontAwesomeIcon(FontAwesome::play)); + //play_sound_button->setFixedSize(play_sound_button->size() * 0.5); + play_sound_button->setFixedSize(20, 20); + layout->addWidget(play_sound_button); + + // auto removefile_button = new QToolButton(this); + // removefile_button->setIcon(Noggit::Ui::FontAwesomeIcon(FontAwesome::windowclose)); + //removefile_button->setFixedSize(removefile_button->size() * 0.5); + // removefile_button->setFixedSize(20, 20); + // layout->addWidget(removefile_button); + + + connect(play_sound_button, &QPushButton::clicked, [=]() { + + if (!filename_ledit->text().toStdString().empty() && !dirpath.empty()) + { + auto sound_player = new SoundEntryPlayer(this); + sound_player->PlaySingleSoundFile(filename_ledit->text().toStdString(), dirpath); + sound_player->show(); + } + }); + } + +} +} diff --git a/src/noggit/ui/windows/EditorWindows/SoundEntryPickerWindow.h b/src/noggit/ui/windows/EditorWindows/SoundEntryPickerWindow.h new file mode 100644 index 00000000..88dd8835 --- /dev/null +++ b/src/noggit/ui/windows/EditorWindows/SoundEntryPickerWindow.h @@ -0,0 +1,156 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +namespace Noggit +{ + namespace Ui + { + // struct SoundEntryFilename + // { + // SoundEntryFilename(std::string f, int freq); + // + // std::string filename; + // int freq; + // }; + // }; + + class SoundFileWListWidgetItem : public QWidget + { + Q_OBJECT + public: + SoundFileWListWidgetItem(QLineEdit* filename_ledit, std::string dirpath, QWidget* parent = nullptr); + // QLineEdit* _filename_ledit; + private: + + }; + + class SoundEntryPickerWindow : public QWidget + { + Q_OBJECT + public: + SoundEntryPickerWindow(QPushButton* button, int sound_type_filter = -1, bool allow_none = true, QWidget* parent = nullptr); + + private: + QComboBox* _tree_filter_cbbox; + QLineEdit* _tree_searchbar; + QListWidget* _picker_listview; + + int _entry_id = 0; + QLabel* _entry_id_lbl; + QLineEdit* _name_ledit; + + QComboBox* _sound_type_cbbox; + QComboBox* _eax_type_cbbox; + QSpinBox* _min_distance_spinbox; + QSpinBox* _max_distance_spinbox; + QSlider* _volume_slider; + + QCheckBox* _flag6_checkbox; + QCheckBox* _flag10_checkbox; + QCheckBox* _flag11_checkbox; + + QLineEdit* _directory_ledit; + QLabel* _filescount_lbl; + QListWidget* _files_listview; + QLineEdit* _filenames_ledits[10]{ 0 }; + QSpinBox* _freqs_spinboxes[10]{ 0 }; + + bool _flag12; // 7 users and unknown definition, not adding it to the UI. + + // TODO sound advanced. shouldn't use a picker as it is unique for each sound, just add an optional advanced layout without maybe a checkbox. maybe it is in a separate tab ? + int _sound_advanced_id = 0; + + void filter_sound_type(int sound_type, bool load_all = false); + void select_entry(int id); + void save_entry(int entry_id); + void update_files_count(); + // void duplicate_entry(); + }; + + enum SoundEntryTypes + { + SPELLS = 1, + UI, + FOOTSTEPS, + COMBAT_IMPACTS, + COMBAT_SWINGS = 6, + GREETINGS, + CASTING, + ITEM_USE_SOUNDS, + MONSTER_SOUNDS, + VOCAL_UI_SOUNDS = 12, + POINT_SOUND_EMITTERS, + DOODAD_SOUNDS, + DEATH = 16, + NPC_SOUNDS, + FOLEY_SOUNDS = 19, + FOOTSTEPS_SPLASHES, + CHARACTER_SPLASH_SOUNDS, + WATERVOLUME_SOUNDS, + TRADESKILL, + TERRAIN_EMITER, + GAME_OBJECTS, + SPELL_FIZZLES, + CREATURE_LOOPS, + ZONE_MUSIC_FILES, + EMOTES, + CINEMATIC_MUSIC, + CINEMATIC_VOICE, + ZONE_AMBIENCE = 50, + SOUND_EMITTERS = 52, + VEHICLE_STATES + }; + + static std::map sound_types_names = { + {SPELLS , "Spells"}, + {UI , "UI"}, + {FOOTSTEPS , "Footsteps"}, + {COMBAT_IMPACTS , "Combat Impacts"}, + {COMBAT_SWINGS , "Combat Swings"}, + {GREETINGS, "Greetings"}, + {CASTING, "Casting"}, + {ITEM_USE_SOUNDS, "Item Use Sound"}, + {MONSTER_SOUNDS, "Monster Sound"}, + {VOCAL_UI_SOUNDS, "VocalUISound"}, + {POINT_SOUND_EMITTERS, "Point Sound Emitter"}, + {DOODAD_SOUNDS, "Doodad Sounds"}, + {DEATH, "Death Thud Sounds"}, + {NPC_SOUNDS, "NPC Sounds"}, + {FOLEY_SOUNDS, "Foley Sound"}, + {FOOTSTEPS_SPLASHES, "Footsteps(Splashes)"}, + {CHARACTER_SPLASH_SOUNDS, "CharacterSplashSounds"}, + {WATERVOLUME_SOUNDS, "WaterVolume Sounds"}, + {TRADESKILL, "Tradeskill Sounds"}, + {TERRAIN_EMITER, "Terrain Emitter Sounds"}, + {GAME_OBJECTS, "Game Object Sounds"}, + {SPELL_FIZZLES, "SpellFizzles"}, + {CREATURE_LOOPS, "CreatureLoops"}, + {ZONE_MUSIC_FILES, "Zone Music Files"}, + {EMOTES, "Character Macro Line"}, + {CINEMATIC_MUSIC, "Cinematic Music"}, + {CINEMATIC_VOICE, "Cinematic Voice"}, + {ZONE_AMBIENCE, "Zone Ambience"}, + {SOUND_EMITTERS, "Sound Emitters"}, + {VEHICLE_STATES, "Vehicle States"} + }; + } +} + diff --git a/src/noggit/ui/windows/EditorWindows/ZoneIntroMusicPickerWindow.cpp b/src/noggit/ui/windows/EditorWindows/ZoneIntroMusicPickerWindow.cpp new file mode 100644 index 00000000..b5d77da7 --- /dev/null +++ b/src/noggit/ui/windows/EditorWindows/ZoneIntroMusicPickerWindow.cpp @@ -0,0 +1,250 @@ +#include +#include "ZoneIntroMusicPickerWindow.h" +// #include +#include "SoundEntryPickerWindow.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +namespace Noggit +{ + namespace Ui + { + ZoneIntroMusicPickerWindow::ZoneIntroMusicPickerWindow(QPushButton* button, QWidget* parent) + : QWidget(parent) + { + setWindowTitle("Zone Intro Music Picker"); + setWindowFlags(Qt::Dialog); + + auto layout = new QHBoxLayout(this); + + auto list_layout = new QVBoxLayout(this); + + auto Editor_layout = new QVBoxLayout(this); + + layout->addLayout(list_layout); + layout->addLayout(Editor_layout); + + _tree_searchbar = new QLineEdit(this); + list_layout->addWidget(_tree_searchbar); + + _picker_listview = new QListWidget(this); + _picker_listview->setFixedSize(280, 460); + _picker_listview->setSelectionMode(QListWidget::SingleSelection); + list_layout->addWidget(_picker_listview); + + for (DBCFile::Iterator i = gZoneIntroMusicTableDB.begin(); i != gZoneIntroMusicTableDB.end(); ++i) + { + auto item = new QListWidgetItem(); + item->setData(1, i->getInt(ZoneIntroMusicTableDB::ID)); + + std::stringstream ss; + ss << i->getInt(ZoneIntroMusicTableDB::ID) << "-" << i->getString(ZoneIntroMusicTableDB::Name); + item->setText(ss.str().c_str()); + + _picker_listview->addItem(item); + } + + auto select_entry_btn = new QPushButton("Select Entry", this); + auto select_entry_none_btn = new QPushButton("Select -NONE-", this); + auto duplicate_entry_btn = new QPushButton("Duplicate selected Entry (create new)", this); + list_layout->addWidget(duplicate_entry_btn); + list_layout->addWidget(select_entry_btn); + list_layout->addWidget(select_entry_none_btn); + + // Editor frame + QGroupBox* editor_group = new QGroupBox("Edit Selected Entry", this); + Editor_layout->addWidget(editor_group); + + auto editor_form_layout = new QFormLayout(editor_group); + + _entry_id_lbl = new QLabel(this); + editor_form_layout->addRow("Id:", _entry_id_lbl); + _entry_id_lbl->setEnabled(false); + + _name_ledit = new QLineEdit(this); + editor_form_layout->addRow("Intro Music Name:", _name_ledit); + + + _sound_button = new QPushButton("-NONE-", this); + _sound_button->setProperty("id", 0); + connect(_sound_button, &QPushButton::clicked, [=]() { + auto window = new SoundEntryPickerWindow(_sound_button, SoundEntryTypes::ZONE_MUSIC_FILES, false, this); + window->show(); + }); + auto music_layout = new QHBoxLayout(this); + auto play_music_button = new QToolButton(this); + play_music_button->setIcon(Noggit::Ui::FontAwesomeIcon(FontAwesome::play)); + music_layout->addWidget(new QLabel("Music sound entry:")); + music_layout->addWidget(_sound_button); + music_layout->addWidget(play_music_button); + editor_form_layout->addRow(music_layout); + + _min_delay_spinbox = new QSpinBox(this); + _min_delay_spinbox->setMaximum(300); + editor_form_layout->addRow("Min Delay (minutes):", _min_delay_spinbox); + + auto save_music_entry_btn = new QPushButton("Save changes", this); + Editor_layout->addWidget(save_music_entry_btn, 0, Qt::AlignRight); + + Editor_layout->addStretch(); + + /// check if needed + select_entry(button->property("id").toInt()); + + connect(_tree_searchbar, &QLineEdit::textChanged, [=](QString obj) { + if (obj.isEmpty()) + { + // unhide all + } + + // hide all items + for (int i = 0; i < _picker_listview->count(); i++) + { + auto item = _picker_listview->item(i); + item->setHidden(true); + } + // unhide matching items + auto matching_items = _picker_listview->findItems(obj, Qt::MatchContains); + + for (auto item : matching_items) + { + item->setHidden(false); + } + }); + + connect(_picker_listview, &QListWidget::itemClicked, this, [=](QListWidgetItem* item) { + select_entry(item->data(1).toInt()); + }); + + connect(select_entry_btn, &QPushButton::clicked, [=]() { + // auto selection = _picker_listview->selectedItems(); + auto selected_item = _picker_listview->currentItem(); + if (selected_item == nullptr) + return; + + button->setProperty("id", selected_item->data(1).toInt()); + button->setText(selected_item->text()); + this->close(); + }); + + connect(select_entry_none_btn, &QPushButton::clicked, [=]() { + button->setText("-NONE-"); + button->setProperty("id", 0); + this->close(); + }); + + connect(play_music_button, &QPushButton::clicked, [=]() { + auto sound_entry = _sound_button->property("id").toInt(); + if (sound_entry) + { + auto sound_player = new SoundEntryPlayer(this); + sound_player->LoadSoundsFromSoundEntry(sound_entry); + sound_player->show(); + } + }); + + connect(save_music_entry_btn, &QPushButton::clicked, [=]() { + save_entry(_entry_id); + }); + + connect(duplicate_entry_btn, &QPushButton::clicked, [=]() { + auto new_id = gZoneIntroMusicTableDB.getEmptyRecordID(ZoneIntroMusicTableDB::ID); + + auto new_record = gZoneIntroMusicTableDB.addRecord(new_id); + + _name_ledit->setText("Noggit Unnamed entry"); + + save_entry(new_id); + + // add new tree item + auto item = new QListWidgetItem(); + item->setData(1, new_id); + std::stringstream ss; + + _picker_listview->addItem(item); + + select_entry(new_id); + + ss << new_id << "-" << _name_ledit->text().toStdString(); + item->setText(ss.str().c_str()); + }); + } + + void ZoneIntroMusicPickerWindow::select_entry(int id) + { + _entry_id = id; + + if (id != 0) + _picker_listview->setCurrentRow(gZoneIntroMusicTableDB.getRecordRowId(id)); + else + { + _picker_listview->setCurrentRow(0); + return; + } + + _entry_id_lbl->setText(QString(std::to_string(id).c_str())); + + DBCFile::Record record = gZoneIntroMusicTableDB.getByID(id); + + _name_ledit->setText(record.getString(ZoneIntroMusicTableDB::Name)); + + int sound_entry = record.getInt(ZoneIntroMusicTableDB::SoundId); + + if (sound_entry != 0 && gSoundEntriesDB.CheckIfIdExists(sound_entry)) + { + DBCFile::Record sound_record = gSoundEntriesDB.getByID(sound_entry); + std::stringstream ss; + ss << sound_entry << "-" << sound_record.getString(SoundEntriesDB::Name); + _sound_button->setText(ss.str().c_str()); + _sound_button->setProperty("id", sound_entry); + } + else + { + _sound_button->setText("-NONE-"); + _sound_button->setProperty("id", 0); + } + + _priority = record.getInt(ZoneIntroMusicTableDB::Priority); // always 1 except for 1 test entry + + _min_delay_spinbox->setValue(record.getInt(ZoneIntroMusicTableDB::MinDelayMinutes)); + } + + void ZoneIntroMusicPickerWindow::save_entry(int entry_id) + { + DBCFile::Record record = gZoneIntroMusicTableDB.getByID(entry_id); // is_new_record ? gLightDB.addRecord(Id) : gLightDB.getByID(Id); + + + record.write(ZoneIntroMusicTableDB::ID, entry_id); + record.writeString(ZoneIntroMusicTableDB::Name, _name_ledit->text().toStdString()); + record.write(ZoneIntroMusicTableDB::SoundId, _sound_button->property("id").toInt()); + record.write(ZoneIntroMusicTableDB::Priority, _priority); + record.write(ZoneIntroMusicTableDB::MinDelayMinutes, _min_delay_spinbox->value()); + + gZoneIntroMusicTableDB.save(); + } + } +} diff --git a/src/noggit/ui/windows/EditorWindows/ZoneIntroMusicPickerWindow.h b/src/noggit/ui/windows/EditorWindows/ZoneIntroMusicPickerWindow.h new file mode 100644 index 00000000..442a0248 --- /dev/null +++ b/src/noggit/ui/windows/EditorWindows/ZoneIntroMusicPickerWindow.h @@ -0,0 +1,50 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +namespace Noggit +{ + namespace Ui + { + class ZoneIntroMusicPickerWindow : public QWidget + { + Q_OBJECT + public: + ZoneIntroMusicPickerWindow(QPushButton* button, QWidget* parent = nullptr); + + private: + QLineEdit* _tree_searchbar; + QListWidget* _picker_listview; + + int _entry_id = 0; + int _priority = 1; + QLabel* _entry_id_lbl; + QLineEdit* _name_ledit; + QSpinBox* _min_delay_spinbox; + + QPushButton* _sound_button; + + void select_entry(int id); + void save_entry(int entry_id); + // void duplicate_entry(); + }; + } +} + diff --git a/src/noggit/ui/windows/EditorWindows/ZoneMusicPickerWindow.cpp b/src/noggit/ui/windows/EditorWindows/ZoneMusicPickerWindow.cpp new file mode 100644 index 00000000..57ee61e0 --- /dev/null +++ b/src/noggit/ui/windows/EditorWindows/ZoneMusicPickerWindow.cpp @@ -0,0 +1,326 @@ +#include "ZoneMusicPickerWindow.h" +#include +#include "SoundEntryPickerWindow.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +namespace Noggit +{ + namespace Ui + { + ZoneMusicPickerWindow::ZoneMusicPickerWindow(QPushButton* button, QWidget* parent) + : QWidget(parent) + { + setWindowTitle("Zone Music Picker"); + setWindowFlags(Qt::Dialog); + + auto layout = new QHBoxLayout(this); + + auto list_layout = new QVBoxLayout(this); + + auto Editor_layout = new QVBoxLayout(this); + + layout->addLayout(list_layout); + layout->addLayout(Editor_layout); + + _tree_searchbar = new QLineEdit(this); + list_layout->addWidget(_tree_searchbar); + + _picker_listview = new QListWidget(this); + _picker_listview->setFixedSize(280, 460); + _picker_listview->setSelectionMode(QListWidget::SingleSelection); + list_layout->addWidget(_picker_listview); + + for (DBCFile::Iterator i = gZoneMusicDB.begin(); i != gZoneMusicDB.end(); ++i) + { + auto item = new QListWidgetItem(); + item->setData(1, i->getInt(ZoneMusicDB::ID)); + + std::stringstream ss; + ss << i->getInt(ZoneMusicDB::ID) << "-" << i->getString(ZoneMusicDB::Name); + item->setText(ss.str().c_str()); + + // _picker_listview->addItem(ss.str().c_str()); + _picker_listview->addItem(item); + } + + auto select_entry_btn = new QPushButton("Select Entry", this); + select_entry_btn->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::check)); + auto select_entry_none_btn = new QPushButton("Select -NONE-", this); + select_entry_none_btn->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::check)); + auto duplicate_entry_btn = new QPushButton("Duplicate selected Entry (create new)", this); + duplicate_entry_btn->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::plus)); + list_layout->addWidget(duplicate_entry_btn); + list_layout->addWidget(select_entry_btn); + list_layout->addWidget(select_entry_none_btn); + + // Editor frame + QGroupBox* editor_group = new QGroupBox("Edit Selected Entry", this); + Editor_layout->addWidget(editor_group); + + auto editor_form_layout = new QFormLayout(editor_group); + + _entry_id_lbl = new QLabel(this); + editor_form_layout->addRow("Id:", _entry_id_lbl); + _entry_id_lbl->setEnabled(false); + + _name_ledit = new QLineEdit(this); + editor_form_layout->addRow("Music Set Name:", _name_ledit); + + + _day_music_button = new QPushButton("-NONE-", this); + _day_music_button->setProperty("id", 0); + connect(_day_music_button, &QPushButton::clicked, [=]() { + auto window = new SoundEntryPickerWindow(_day_music_button, SoundEntryTypes::ZONE_MUSIC_FILES, true, this); + window->show(); + }); + + auto day_music_layout = new QHBoxLayout(this); + auto play_day_music_button = new QToolButton(this); + play_day_music_button->setIcon(Noggit::Ui::FontAwesomeIcon(FontAwesome::play)); + day_music_layout->addWidget(new QLabel("Day Music:")); + day_music_layout->addWidget(_day_music_button); + day_music_layout->addWidget(play_day_music_button); + editor_form_layout->addRow(day_music_layout); + + _night_music_button = new QPushButton("-NONE-", this); + _night_music_button->setProperty("id", 0); + connect(_night_music_button, &QPushButton::clicked, [=]() { + auto window = new SoundEntryPickerWindow(_night_music_button, SoundEntryTypes::ZONE_MUSIC_FILES, true, this); + window->show(); + }); + + auto night_music_layout = new QHBoxLayout(this); + auto play_night_music_button = new QToolButton(this); + play_night_music_button->setIcon(Noggit::Ui::FontAwesomeIcon(FontAwesome::play)); + night_music_layout->addWidget(new QLabel("Night Music:")); + night_music_layout->addWidget(_night_music_button); + night_music_layout->addWidget(play_night_music_button); + editor_form_layout->addRow(night_music_layout); + // editor_form_layout->addRow("Night Music:", _night_music_button); + + QGroupBox* silence_intervals_group = new QGroupBox("Silence Intervals", this); + Editor_layout->addWidget(silence_intervals_group); + auto silence_interval_layout = new QVBoxLayout(silence_intervals_group); + + silence_interval_layout->addWidget(new QLabel("Day:")); + auto day_silence_intervals_layout = new QHBoxLayout(this); + silence_interval_layout->addLayout(day_silence_intervals_layout); + day_silence_intervals_layout->addWidget(new QLabel("Min:")); + _day_min_interval_spinbox = new QSpinBox(this); + _day_min_interval_spinbox->setMaximum(600000); + day_silence_intervals_layout->addWidget(_day_min_interval_spinbox); + day_silence_intervals_layout->addWidget(new QLabel("Max:")); + _day_max_interval_spinbox = new QSpinBox(this); + _day_max_interval_spinbox->setMaximum(600000); + day_silence_intervals_layout->addWidget(_day_max_interval_spinbox); + + silence_interval_layout->addWidget(new QLabel("Night:")); + auto night_silence_intervals_layout = new QHBoxLayout(this); + silence_interval_layout->addLayout(night_silence_intervals_layout); + night_silence_intervals_layout->addWidget(new QLabel("Min:")); + _night_min_interval_spinbox = new QSpinBox(this); + _night_min_interval_spinbox->setMaximum(600000); + night_silence_intervals_layout->addWidget(_night_min_interval_spinbox); + night_silence_intervals_layout->addWidget(new QLabel("Max:")); + _night_max_interval_spinbox = new QSpinBox(this); + _night_max_interval_spinbox->setMaximum(600000); + night_silence_intervals_layout->addWidget(_night_max_interval_spinbox); + + auto save_music_entry_btn = new QPushButton("Save changes", this); + Editor_layout->addWidget(save_music_entry_btn, 0, Qt::AlignRight); + + Editor_layout->addStretch(); + + /// check if needed + select_entry(button->property("id").toInt()); + + connect(_tree_searchbar, &QLineEdit::textChanged, [=](QString obj) { + if (obj.isEmpty()) + { + // unhide all + } + + // hide all items + for (int i = 0; i < _picker_listview->count(); i++) + { + auto item = _picker_listview->item(i); + item->setHidden(true); + } + // unhide matching items + auto matching_items = _picker_listview->findItems(obj, Qt::MatchContains); + + for (auto item : matching_items) + { + item->setHidden(false); + } + }); + + connect(_picker_listview, &QListWidget::itemClicked, this, [=](QListWidgetItem* item) { + select_entry(item->data(1).toInt()); + }); + + connect(select_entry_btn, &QPushButton::clicked, [=]() { + // auto selection = _picker_listview->selectedItems(); + auto selected_item = _picker_listview->currentItem(); + if (selected_item == nullptr) + return; + + button->setProperty("id", selected_item->data(1).toInt()); + button->setText(selected_item->text()); + this->close(); + }); + + connect(select_entry_none_btn, &QPushButton::clicked, [=]() { + button->setText("-NONE-"); + button->setProperty("id", 0); + this->close(); + }); + + connect(play_day_music_button, &QPushButton::clicked, [=]() { + auto sound_entry = _day_music_button->property("id").toInt(); + if (sound_entry) + { + auto sound_player = new SoundEntryPlayer(this); + sound_player->LoadSoundsFromSoundEntry(sound_entry); + sound_player->show(); + } + }); + + connect(play_night_music_button, &QPushButton::clicked, [=]() { + auto sound_entry = _night_music_button->property("id").toInt(); + if (sound_entry) + { + auto sound_player = new SoundEntryPlayer(this); + sound_player->LoadSoundsFromSoundEntry(sound_entry); + sound_player->show(); + } + }); + + connect(save_music_entry_btn, &QPushButton::clicked, [=]() { + save_entry(_entry_id); + }); + + connect(duplicate_entry_btn, &QPushButton::clicked, [=]() { + auto new_id = gZoneMusicDB.getEmptyRecordID(ZoneMusicDB::ID); + + auto new_record = gZoneMusicDB.addRecord(new_id); + + _name_ledit->setText("Noggit Unnamed entry"); + + save_entry(new_id); + + // add new tree item + auto item = new QListWidgetItem(); + item->setData(1, new_id); + std::stringstream ss; + + _picker_listview->addItem(item); + + select_entry(new_id); + + ss << new_id << "-" << _name_ledit->text().toStdString(); + item->setText(ss.str().c_str()); + }); + + + } + void ZoneMusicPickerWindow::select_entry(int id) + { + _entry_id = id; + + if (id != 0) + _picker_listview->setCurrentRow(gZoneMusicDB.getRecordRowId(id)); + else + { + _picker_listview->setCurrentRow(0); + return; + } + + _entry_id_lbl->setText(QString(std::to_string(id).c_str())); + + DBCFile::Record record = gZoneMusicDB.getByID(id); + + _name_ledit->setText(record.getString(ZoneMusicDB::Name)); + + int day_sound_entry = record.getInt(ZoneMusicDB::DayMusic); + int night_sound_entry = record.getInt(ZoneMusicDB::NightMusic); + + if (day_sound_entry != 0 && gSoundEntriesDB.CheckIfIdExists(day_sound_entry)) // some entries reference sound entries that don't exist + { + DBCFile::Record day_sound_record = gSoundEntriesDB.getByID(day_sound_entry); + std::stringstream ss_day; + ss_day << day_sound_entry << "-" << day_sound_record.getString(SoundEntriesDB::Name); + _day_music_button->setText(ss_day.str().c_str()); + _day_music_button->setProperty("id", day_sound_entry); + } + else + { + _day_music_button->setText("-NONE-"); + _day_music_button->setProperty("id", 0); + } + + if (night_sound_entry != 0 && gSoundEntriesDB.CheckIfIdExists(night_sound_entry)) + { + DBCFile::Record night_sound_record = gSoundEntriesDB.getByID(night_sound_entry); + std::stringstream ss_night; + ss_night << night_sound_entry << "-" << night_sound_record.getString(SoundEntriesDB::Name); + _night_music_button->setText(ss_night.str().c_str()); + _night_music_button->setProperty("id", night_sound_entry); + } + else + { + _night_music_button->setText("-NONE-"); + _night_music_button->setProperty("id", 0); + } + + _day_min_interval_spinbox->setValue(record.getInt(ZoneMusicDB::SilenceIntervalMinDay)); + _day_max_interval_spinbox->setValue(record.getInt(ZoneMusicDB::SilenceIntervalMaxDay)); + _night_min_interval_spinbox->setValue(record.getInt(ZoneMusicDB::SilenceIntervalMinNight)); + _night_max_interval_spinbox->setValue(record.getInt(ZoneMusicDB::SilenceIntervalMaxNight)); + + + } + + void ZoneMusicPickerWindow::save_entry(int entry_id) + { + DBCFile::Record record = gZoneMusicDB.getByID(entry_id); // is_new_record ? gLightDB.addRecord(Id) : gLightDB.getByID(Id); + + + record.write(ZoneMusicDB::ID, entry_id); + record.writeString(ZoneMusicDB::Name, _name_ledit->text().toStdString()); + record.write(ZoneMusicDB::SilenceIntervalMinDay, _day_min_interval_spinbox->value()); + record.write(ZoneMusicDB::SilenceIntervalMaxDay, _day_max_interval_spinbox->value()); + record.write(ZoneMusicDB::SilenceIntervalMinNight, _night_min_interval_spinbox->value()); + record.write(ZoneMusicDB::SilenceIntervalMaxNight, _night_max_interval_spinbox->value()); + record.write(ZoneMusicDB::DayMusic, _day_music_button->property("id").toInt()); + record.write(ZoneMusicDB::NightMusic, _night_music_button->property("id").toInt()); + + gZoneMusicDB.save(); + } + } +} diff --git a/src/noggit/ui/windows/EditorWindows/ZoneMusicPickerWindow.h b/src/noggit/ui/windows/EditorWindows/ZoneMusicPickerWindow.h new file mode 100644 index 00000000..38a231c3 --- /dev/null +++ b/src/noggit/ui/windows/EditorWindows/ZoneMusicPickerWindow.h @@ -0,0 +1,53 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +namespace Noggit +{ + namespace Ui + { + class ZoneMusicPickerWindow : public QWidget + { + Q_OBJECT + public: + ZoneMusicPickerWindow(QPushButton* button, QWidget* parent = nullptr); + + private: + QLineEdit* _tree_searchbar; + QListWidget* _picker_listview; + + int _entry_id = 0; + QLabel* _entry_id_lbl; + QLineEdit* _name_ledit; + QSpinBox* _day_min_interval_spinbox; + QSpinBox* _day_max_interval_spinbox; + QSpinBox* _night_min_interval_spinbox; + QSpinBox* _night_max_interval_spinbox; + + QPushButton* _day_music_button; + QPushButton* _night_music_button; + + void select_entry(int id); + void save_entry(int entry_id); + // void duplicate_entry(); + }; + } +} + diff --git a/src/noggit/ui/windows/SoundPlayer/SoundEntryPlayer.cpp b/src/noggit/ui/windows/SoundPlayer/SoundEntryPlayer.cpp new file mode 100644 index 00000000..071fb4c7 --- /dev/null +++ b/src/noggit/ui/windows/SoundPlayer/SoundEntryPlayer.cpp @@ -0,0 +1,213 @@ +#include "SoundEntryPlayer.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +namespace Noggit +{ + namespace Ui + { + SoundEntryPlayer::SoundEntryPlayer(QWidget* parent) + : QWidget(parent) + { + setWindowTitle("Sound entry player"); + setWindowFlags(Qt::Tool); + + auto layout = new QVBoxLayout(this); + + // auto sound_id_lbl = new QLabel(this); + // sound_id_lbl->setText("Sound Entry : " + sound_entry_id); + // layout->addWidget(sound_id_lbl); + + auto dir_layout = new QHBoxLayout(this); + layout->addLayout(dir_layout); + + dir_layout->addWidget(new QLabel("Directory:")); + _directory_lbl = new QLabel(this); + dir_layout->addWidget(_directory_lbl); + + auto controls_layout = new QHBoxLayout(this); + layout->addLayout(controls_layout); + + _media_player = new QMediaPlayer(this); + + auto btn_play = new QToolButton(this); + controls_layout->addWidget(btn_play); + connect(btn_play, &QToolButton::clicked, _media_player, &QMediaPlayer::play); + btn_play->setIcon(Noggit::Ui::FontAwesomeIcon(FontAwesome::play)); + + auto btn_pause = new QToolButton(this); + controls_layout->addWidget(btn_pause); + connect(btn_pause, &QToolButton::clicked, _media_player, &QMediaPlayer::pause); + btn_pause->setIcon(Noggit::Ui::FontAwesomeIcon(FontAwesome::pause)); + + auto btn_stop = new QToolButton(this); + controls_layout->addWidget(btn_stop); + connect(btn_stop, &QToolButton::clicked, _media_player, &QMediaPlayer::stop); + btn_stop->setIcon(Noggit::Ui::FontAwesomeIcon(FontAwesome::stop)); + + _position_slider = new QSlider(Qt::Horizontal, this); + _position_slider->setTickInterval(100); + _position_slider->setSingleStep(100); + controls_layout->addWidget(_position_slider); + + _volume_slider = new QSlider(Qt::Horizontal, this); + _volume_slider->setRange(0, 100); + _volume_slider->setValue(80); + _media_player->setVolume(80); + + + // controls_layout->addWidget(new QLabel("Volume:")); + auto btn_volume = new QToolButton(this); + controls_layout->addWidget(btn_volume); + // connect(btn_volume, &QToolButton::clicked, _media_player, &QMediaPlayer::stop); + btn_volume->setIcon(Noggit::Ui::FontAwesomeIcon(FontAwesome::volumeup)); + controls_layout->addWidget(btn_volume); + controls_layout->addWidget(_volume_slider); + + _files_listview = new QListWidget(); + _files_listview->setSelectionMode(QListWidget::SingleSelection); + layout->addWidget(_files_listview); + + connect(_files_listview, &QListWidget::itemClicked, this, [=](QListWidgetItem* item) { + play_selected_sound(); + }); + + // connect volume + connect(_volume_slider, &QSlider::valueChanged, [&](int v) { + _media_player->setVolume(v); + }); + + // media doesn't start playnig imemdiatly when called, need to use this signal + connect(_media_player, &QMediaPlayer::durationChanged, this, [&](qint64 dur) { + _position_slider->setMaximum(dur); + }); + + // connect(_media_player, SIGNAL(positionChanged(qint64)), this, SLOT(positionChanged(qint64))); + connect(_media_player, &QMediaPlayer::positionChanged, [&](qint64 v) { + auto testmax = _position_slider->maximum(); + QSignalBlocker const blocker(_position_slider); + _position_slider->setSliderPosition(v); + }); + // position bar + connect(_position_slider, &QSlider::valueChanged, [&](int v) { + // _media_player->currentMedia().canonicalResource().dataSize(); + _media_player->setPosition(v); + }); + // _media_player->setPosition(); + } + + void SoundEntryPlayer::LoadSoundsFromSoundEntry(int sound_entry_id) + { + if (sound_entry_id == 0) + { + this->close(); + this->destroy(); + return; + } + + // get files list + DBCFile::Record sound_entry_record = gSoundEntriesDB.getByID(sound_entry_id); + + _directory_lbl->setText(sound_entry_record.getString(SoundEntriesDB::FilePath)); + + _volume_slider->setValue(sound_entry_record.getFloat(SoundEntriesDB::Volume) * 100); + _media_player->setVolume(sound_entry_record.getFloat(SoundEntriesDB::Volume) * 100); + + for (int fileid = 0; fileid < 10; fileid++) + { + std::string filename = sound_entry_record.getString(SoundEntriesDB::Filenames + fileid); + if (!filename.empty()) + { + // std::stringstream ss_filepah; + // ss_filepath << directory << "\\" << filename; + // music_files.push_back(ss_filepah.str()); + // music_files.push_back(filename); + _files_listview->addItem(filename.c_str()); + } + } + _files_listview->setCurrentRow(0); + play_selected_sound(); + } + + void SoundEntryPlayer::PlaySingleSoundFile(std::string filepath, std::string dir_path) + { + _directory_lbl->setText(dir_path.c_str()); + + _files_listview->clear(); + _files_listview->addItem(filepath.c_str()); + + _files_listview->setCurrentRow(0); + play_selected_sound(); + } + + void SoundEntryPlayer::play_selected_sound() + { + std::stringstream filename; + auto item = _files_listview->selectedItems().back(); + filename << _directory_lbl->text().toStdString() << "\\" << item->text().toStdString(); + + if (!Noggit::Application::NoggitApplication::instance()->clientData()->exists(filename.str())) + { + LogError << "The requested sound file \"" << filename.str() << "\" does not exist! Oo" << std::endl; + QMessageBox not_found_messagebox; + not_found_messagebox.setIcon(QMessageBox::Warning); + not_found_messagebox.setWindowIcon(QIcon(":/icon")); + not_found_messagebox.setWindowTitle("File not found"); + std::stringstream ss; + ss << "The requested sound file \"" << filename.str() << "\" was not found in the client." << std::endl; + not_found_messagebox.setText(ss.str().c_str()); + not_found_messagebox.exec(); + return; + } + + BlizzardArchive::ClientFile file(filename.str(), Noggit::Application::NoggitApplication::instance()->clientData()); + + auto temp_file = new QTemporaryFile(this); // must parent for the object to be destroyed properly(and file deleted) + + temp_file->open(); + temp_file->write(file.getBuffer(), file.getSize()); + temp_file->close(); + // default tempname is like User\AppData\Local\Temp\Noggit.qrRfsy ...We need to add back the file extension or it won't be read by the player! + // must rename after closing or it doesn't write correctly + temp_file->rename(temp_file->fileName() + item->text()); + // file.save(); // saves file to project folder + // auto save_path = file.getPath().string(); + + auto testlol = temp_file->fileName().toStdString(); + + _media_player->setMedia(QUrl::fromLocalFile(temp_file->fileName())); // QUrl::fromLocalFile("/Users/me/Music/coolsong.mp3") + _media_player->play(); + } + + void SoundEntryPlayer::closeEvent(QCloseEvent* event) + { + // makes the music stop when closing + _media_player->stop(); + event->accept(); + } + } +} diff --git a/src/noggit/ui/windows/SoundPlayer/SoundEntryPlayer.h b/src/noggit/ui/windows/SoundPlayer/SoundEntryPlayer.h new file mode 100644 index 00000000..eb5270e1 --- /dev/null +++ b/src/noggit/ui/windows/SoundPlayer/SoundEntryPlayer.h @@ -0,0 +1,49 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +namespace Noggit +{ + namespace Ui + { + class SoundEntryPlayer : public QWidget + { + Q_OBJECT + public: + SoundEntryPlayer(QWidget* parent = nullptr); + void LoadSoundsFromSoundEntry(int sound_entry_id); + void PlaySingleSoundFile(std::string filepath, std::string dir_path); + + private: + QMediaPlayer* _media_player; + + // QLabel* sound_id_lbl; + QLabel* _directory_lbl; + QListWidget* _files_listview; + QSlider* _volume_slider; + QSlider* _position_slider; + + void play_selected_sound(); + + protected: + void closeEvent(QCloseEvent* event) override; + }; + } +} \ No newline at end of file