Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

+28
View File
@@ -0,0 +1,28 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Filip Biedziak, NLE, 2020-07-29
#
ADD_SUBDIRECTORY(Data)
ADD_SUBDIRECTORY(Gui)
#
# Gui Plugin Interface
#
ADD_INTERFACE_LIBRARY(EfmGuiPluginInterface
${CMAKE_CURRENT_SOURCE_DIR}/efm_gui_plugin_interface.h
${CMAKE_CURRENT_SOURCE_DIR}/..
GuiPluginInterface
)
#
# Data Plugin Interface
#
ADD_INTERFACE_LIBRARY(EfmDataPluginInterface
${CMAKE_CURRENT_SOURCE_DIR}/efm_data_plugin_interface.h
${CMAKE_CURRENT_SOURCE_DIR}/..
DataPluginInterface
svcSomCommon
)
+24
View File
@@ -0,0 +1,24 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Filip Biedziak, SLSE, 2020-07-29
#
#
# Data Plugin
#
SET(efm_data_SRCS
efm_data_plugin.cpp
efm_data_plugin.h
)
NGL_ADD_LIBRARY(WS EfmDataPlugin MODULE ${efm_data_SRCS})
NGL_TARGET_LINK_LIBRARIES(EfmDataPlugin
Qt5::Core
EfmDataPluginInterface
svcSomClient
NGLLogger
LtsSessionDataDds
)
NGL_INSTALL_TARGET(EfmDataPlugin)
+40
View File
@@ -0,0 +1,40 @@
/**
* @RDE_HEADER@
* Data Plugin for effect management.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, SLSE, 2020-07-29
*/
#include "efm_data_plugin.h"
#include <DDS/DDSConnector/dds_connector.h>
#include <LtsSession/lts_session_data_dds.h>
#include <PluginInterfaces/data_plugin_interface.h>
namespace EffectManagement
{
std::shared_ptr<DataPluginBase::Interface> DataPlugin::createDataInterface(LtsSession::LtsSessionDataDds *session)
{
std::shared_ptr<SoundManagement::Interface::Dtc> dtc;
std::shared_ptr<SoundManagement::Interface::Ftc> ftc;
if (!session->createTopicClient(dtc, ftc, true, true))
return std::shared_ptr<DataPluginBase::Interface>();
return std::make_shared<DataInterfaceImpl>(dtc, ftc);
}
DataInterfaceImpl::DataInterfaceImpl(const std::shared_ptr<SoundManagement::Interface::Dtc> &dtc,
const std::shared_ptr<SoundManagement::Interface::Ftc> &ftc)
: DataInterface()
, m_dtc(dtc)
, m_ftc(ftc)
{
}
} // namespace EffectManagement
+57
View File
@@ -0,0 +1,57 @@
/**
* @RDE_HEADER@
* Data Plugin for effect management.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, SLSE, 2020-07-29
*/
#pragma once
#include <PluginInterfaces/data_plugin_interface.h>
#include <Plugins/EffectManagement/efm_data_plugin_interface.h>
namespace EffectManagement
{
class DataPlugin final : public QObject, public DataPluginBase::Plugin
{
Q_PLUGIN_METADATA(IID "data:3:efm.cevapcici")
Q_INTERFACES(DataPluginBase::Plugin)
Q_OBJECT
public:
DataPlugin() = default;
~DataPlugin() = default;
QString pluginName() const override { return QStringLiteral("EffectManagementDataPlugin"); }
std::shared_ptr<DataPluginBase::Interface> createDataInterface(LtsSession::LtsSessionDataDds *session) override;
bool availableInPartition(IDL::PartitionType partition) const override
{
return (partition == IDL::PartitionType::Exercise) ||
(partition == IDL::PartitionType::Global);
}
};
class DataInterfaceImpl final : public DataInterface
{
public:
DataInterfaceImpl(const std::shared_ptr<SoundManagement::Interface::Dtc> &dtc,
const std::shared_ptr<SoundManagement::Interface::Ftc> &ftc);
std::shared_ptr<SoundManagement::Interface::Dtc> getDtc() override { return m_dtc; }
std::shared_ptr<SoundManagement::Interface::Ftc> getFtc() override { return m_ftc; }
private:
std::shared_ptr<SoundManagement::Interface::Dtc> m_dtc;
std::shared_ptr<SoundManagement::Interface::Ftc> m_ftc;
};
} // namespace EffectManagement
+8
View File
@@ -0,0 +1,8 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Filip Biedziak, NLE, 2020-07-29
#
ADD_SUBDIRECTORY(SoundArea)
+56
View File
@@ -0,0 +1,56 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Filip Biedziak, NLE, 2020-08-14
#
SET(efm_sound_area_gui_SRCS
efm_sound_area_gui_plugin.cpp
efm_sound_area_gui_plugin.h
efm_sound_area.h
efm_sound_state.cpp
efm_sound_state.h
efm_sound_area_select_dialog.cpp
efm_sound_area_select_dialog.h
efm_sound_area_edit_dialog.cpp
efm_sound_area_edit_dialog.h
efm_sound_area_select_model.cpp
efm_sound_area_select_model.h
efm_sound_area_edit_model_playlist.cpp
efm_sound_area_edit_model_playlist.h
efm_sound_area_edit_model_tree.cpp
efm_sound_area_edit_model_tree.h
efm_sound_area_helper.cpp
efm_sound_area_helper.h
efm_switch_item_delegate.cpp
efm_switch_item_delegate.h
../logger.cpp
../logger.h
)
NGL_WRAP_UI(efm_sound_area_gui_SRCS
efm_sound_area_select_dialog.ui
efm_sound_area_edit_dialog.ui
#efm_sound_area_add_sound_process_dialog.ui
)
NGL_ADD_LIBRARY(WS EfmSoundAreaGuiPlugin MODULE ${efm_sound_area_gui_SRCS})
NGL_TARGET_LINK_LIBRARIES(EfmSoundAreaGuiPlugin
ngltools
LtsSession
LtsWidgets
IsmDataPluginInterface
EfmDataPluginInterface
EfmGuiPluginInterface
Qt5::Widgets
LtsUtilsGuiDds
)
NGL_INSTALL_TARGET(EfmSoundAreaGuiPlugin)
+109
View File
@@ -0,0 +1,109 @@
/**
* @RDE_HEADER@
* SoundArea class.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, NLE, 2020-08-10
*/
#pragma once
#include <InfrastructureManagement/ism.hpp>
#include <SoundManagement/som.hpp>
#include <QHash>
#include <QVector>
namespace EffectManagement
{
using SoundKey = QPair<int32_t, int32_t>;
struct SoundArea
{
SoundArea() = default;
explicit SoundArea(const InfrastructureManagement::EffectArea &effectArea)
: id(effectArea.id())
, areaEgcuId(effectArea.areaEgcuId())
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
, egcuIds(QVector<int>(effectArea.egcuIds().begin(), effectArea.egcuIds().end()))
#else
, egcuIds(QVector<int>::fromStdVector(effectArea.egcuIds()))
#endif
, displayName(QString::fromStdString(effectArea.name()))
{
}
bool addActiveSound(const SoundManagement::SoundState &soundState)
{
if (activeSounds.contains(soundState.id()))
return false;
activeSounds.insert(soundState.id(), soundState);
return true;
}
bool removeActiveSound(const SoundManagement::SoundState &soundState)
{
return removeActiveSound(soundState.id());
}
bool removeActiveSound(const int &id)
{
return activeSounds.remove(id) == 1;
}
bool hasActiveSound(const SoundManagement::SoundCategory &category, const int &id) const
{
for (const auto &sound : qAsConst(activeSounds))
if ( (sound.category() == category) && (sound.soundId() == id) )
return true;
return false;
}
bool hasActiveSound(const int32_t &category, const int32_t &id) const
{
for (const auto &sound : qAsConst(activeSounds))
if ( (static_cast<int32_t>(sound.category().underlying()) == category) && (sound.soundId() == id) )
return true;
return false;
}
bool hasActiveSound(const SoundKey &key) const
{
for (const auto &sound : qAsConst(activeSounds))
if ( (static_cast<int32_t>(sound.category().underlying()) == key.first) && (sound.soundId() == key.second) )
return true;
return false;
}
QString toString() const
{
QString str;
str += QStringLiteral("SoundArea ") + QString::number(id);
str += QStringLiteral(" displayName: ") + displayName;
str += QStringLiteral(" areaEgcuId: ") + QString::number(areaEgcuId);
return str;
}
std::ostream& operator << (std::ostream& os) const
{
os << toString().toStdString();
return os;
}
bool operator == (const SoundArea &other) const
{
return id == other.id;
}
bool operator != (const SoundArea &other) const
{
return id != other.id;
}
int id{-1};
int32_t areaEgcuId{-1};
QVector<int32_t> egcuIds;
QString displayName;
QHash<int32_t, SoundManagement::SoundState> activeSounds;
};
} // namespace EffectManagement
@@ -0,0 +1,257 @@
/**
* @RDE_HEADER@
* Plugin to manage effects.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, NLE, 2020-07-29
*/
#include "efm_sound_area_edit_dialog.h"
#include "ui_efm_sound_area_edit_dialog.h"
#include "efm_sound_area.h"
#include "efm_sound_area_helper.h"
#include "efm_sound_area_edit_model_playlist.h"
#include "efm_sound_area_edit_model_tree.h"
#include "efm_switch_item_delegate.h"
#include "../logger.h"
#include <EffectManagement/efm_data_plugin_interface.h>
#include <LtsSession/lts_session.h>
#include <LtsUtilsGuiDds/request_helper.h>
#include <InfrastructureManagement/ism_dtc.h>
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
#include <LtsWidgets/lts_global_wait_dialog.h>
#include <QtWidgets/QGridLayout>
#include <QDialogButtonBox>
using namespace SoundManagement;
namespace EffectManagement
{
//=============================================================================================================================
// SOUNDTREEMODEL
//=============================================================================================================================
SoundAreaEditDialog::SoundAreaEditDialog(const SoundArea &soundArea, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
, m_soundArea(new SoundArea(soundArea))
, m_ui(new Ui::SoundAreaEditDialog)
, m_logger(getLogger("Plugins.Gui.SoundArea.EditDialog"))
{
m_ui->setupUi(this);
m_buttonBox->getButton(LtsWidgets::DialogButton::Hide)->setIcon(QIcon(QStringLiteral("icon:avm_stop.svg")));
setOnlineHelpFilename(QStringLiteral("Sound-Area_Edit_Dialog"));
}
SoundAreaEditDialog::~SoundAreaEditDialog()
{
delete m_ui;
}
void SoundAreaEditDialog::retranslate()
{
translate(m_ui, tr("Manage Sound Area #%1").arg(m_soundArea->id));
m_buttonBox->getButton(LtsWidgets::DialogButton::Hide)->setText(tr("Stop All Sounds"));
}
//-----------------------------------------------------------------------------------------------------------------------------
// PRIVATE SLOTS
//-----------------------------------------------------------------------------------------------------------------------------
void SoundAreaEditDialog::onPlaySound(SoundManagement::SoundCategory category, int soundId, bool inLoop, int volume)
{
qWarning() << "onPlaySound" << volume;
SoundManagement::PlayControl control = inLoop ? SoundManagement::PlayControl_def::PlayLoop : SoundManagement::PlayControl_def::PlaySingle;
for (const auto &egcuId : qAsConst(m_soundArea->egcuIds))
{
if (!m_egcuCheckBoxes.value(egcuId)->isChecked())
continue;
SoundManagement::ControlSoundRequest req(
egcuId,
soundId,
category,
volume,
control
);
auto *reqHandler = new ControlSoundRequester;
// FIXME: reqHandler leaks if controlSoundRequest fails
if (!m_somFtc->controlSoundRequest(req, reqHandler))
return;
connect(reqHandler, &ControlSoundRequester::finished,
this, [this, reqHandler/*, category, soundId, inLoop, volume, egcuId*/](const QString &msg)
{
if (!msg.isEmpty())
{
LtsWidgets::LtsMessageDialogNew(this, msg);//tr("Playing sound failed: %1").arg(msg));
return;
}
reqHandler->deleteLater();
});
}
}
void SoundAreaEditDialog::onStopAllSounds()
{
DEBUG_LOG(m_logger) << "onStopAllSounds";
QList<int32_t> egcuIds; // search for active EGCUs only to reduce DDS load
for (const auto &egcu : qAsConst(m_soundArea->egcuIds))
{
if (!m_egcuCheckBoxes.value(egcu)->isChecked())
continue;
DEBUG_LOG(m_logger) << "onStopAllSounds add egcu=" << egcu;
egcuIds.append(egcu);
}
for (const auto &egcu : qAsConst(egcuIds))
{
DEBUG_LOG(m_logger) << "onStopAllSounds egcu=" << egcu;
SoundManagement::StopAllSoundsRequest req(egcu);
/* m_requestHelper->startSingleRequest([this, req]()
{
return */m_somFtc->stopAllSoundsRequest(req, nullptr);/*this);
});*/
}
}
//-----------------------------------------------------------------------------------------------------------------------------
// PUBLIC MEMBER FUNCTIONS
//-----------------------------------------------------------------------------------------------------------------------------
bool SoundAreaEditDialog::init(LtsSession::LtsSessionDataDds *session)
{
DEBUG_LOG(m_logger) << "init";
m_session = session;
// connect to DDS
std::shared_ptr<InfrastructureManagement::Interface::Dtc> ismDtc;
if (!m_session->getDtc<InfrastructureManagement::DataInterface>(ismDtc))
{
ERROR_LOG(m_logger) << "connection to ISM-DTC failed";
return false;
}
if (!m_session->getDtc<EffectManagement::DataInterface>(m_somDtc))
{
ERROR_LOG(m_logger) << "connection to SOM-DTC failed";
return false;
}
if (!m_session->getFtc<EffectManagement::DataInterface>(m_somFtc))
{
ERROR_LOG(m_logger) << "connection to SOM-FTC failed";
return false;
}
m_helper = std::make_shared<SoundAreaHelper>(new SoundAreaHelper(ismDtc, m_somDtc));
// add checkboxes for EGCU and label them with their respective names from ISM
QGridLayout *layout = new QGridLayout();
int i = 0;
for (const auto &egcu : qAsConst(m_soundArea->egcuIds))
{
QCheckBox *chBox = new QCheckBox(m_helper->egcuName(egcu));
chBox->setChecked(true);
m_egcuCheckBoxes.insert(egcu, chBox);
layout->addWidget(m_egcuCheckBoxes.value(egcu), int(i / 2), i % 2);
++i;
} // for
m_ui->wEgcu->setLayout(layout);
// model initialization
delete m_treeModel;
m_treeModel = new SoundAreaTreeModel(m_soundArea->egcuIds, m_helper, this);
m_treeModel->init(m_somDtc);
m_ui->tvSounds->setModel(m_treeModel);
m_ui->tvSounds->expandAll();
m_ui->tvSounds->header()->resizeSection(SoundAreaTreeModel::Column::Loop, 50);
m_ui->tvSounds->header()->setSectionResizeMode(SoundAreaTreeModel::Column::Category, QHeaderView::Interactive);
m_ui->tvSounds->header()->setSectionResizeMode(SoundAreaTreeModel::Column::Sound, QHeaderView::Stretch);
m_ui->tvSounds->header()->setSectionResizeMode(SoundAreaTreeModel::Column::Loop, QHeaderView::Fixed);
delete m_playlistModel;
m_playlistModel = new SoundAreaPlaylistModel(m_soundArea->egcuIds, m_helper, this);
m_playlistModel->init(m_somDtc);
m_ui->tvPlaylist->setModel(m_playlistModel);
m_ui->tvPlaylist->horizontalHeader()->resizeSection(SoundAreaPlaylistModel::Column::Duration, 100);
m_ui->tvPlaylist->horizontalHeader()->resizeSection(SoundAreaPlaylistModel::Column::Option, 50);
// m_ui->tvPlaylist->horizontalHeader()->setSectionResizeMode(SoundAreaPlaylistModel::Column::Category, QHeaderView::Interactive);
m_ui->tvPlaylist->horizontalHeader()->setSectionResizeMode(SoundAreaPlaylistModel::Column::Sound, QHeaderView::Stretch);
// m_ui->tvPlaylist->horizontalHeader()->setSectionResizeMode(SoundAreaPlaylistModel::Column::Egcu, QHeaderView::Interactive);
//m_ui->tvPlaylist->horizontalHeader()->setSectionResizeMode(SoundAreaPlaylistModel::Column::Duration, QHeaderView::Fixed);
m_ui->tvPlaylist->horizontalHeader()->setSectionResizeMode(SoundAreaPlaylistModel::Column::Option, QHeaderView::Fixed);
m_ui->tvSounds->setItemDelegateForColumn(SoundAreaTreeModel::Column::Loop, new SwitchItemDelegate(m_treeModel));
m_ui->tvSounds->setItemDelegateForColumn(SoundAreaTreeModel::Column::Volume, new SpinBoxDelegate(m_treeModel));
m_ui->tvPlaylist->setItemDelegate(new SoundAreaEditPlaylistDelegate(m_playlistModel));
// connects
connect(m_treeModel, &SoundAreaTreeModel::playSound, this, &SoundAreaEditDialog::onPlaySound);
connect(m_ui->tvSounds, &QTreeView::clicked, m_treeModel, &SoundAreaTreeModel::onSoundTreeItemActivated);
connect(m_ui->tvPlaylist, &QTableView::clicked, this, [this](const QModelIndex &index)
{
if (index.column() != SoundAreaPlaylistModel::Column::Option)
return;
// ControlSoundRequester *csr = new ControlSoundRequester;
const SoundState ss(m_playlistModel->getRowData(index.row()));
// connect(csr, &ControlSoundRequester::finished,
// this, [this, ss](const QString &msg)
// {
// //LtsWidgets::LtsGlobalWaitDialog::getInstance()->done();
// if (!msg.isEmpty())
// return;
// m_playlistModel->removeRow(m_playlistModel->indexOf(ss));
// });
auto *reqHandler = new ControlSoundRequester;
// FIXME: reqHandler leaks if controlSoundRequest fails
if (!m_somFtc->controlSoundRequest(ControlSoundRequest(ss.egcuId(), ss.soundId(), ss.category(), 0, PlayControl::StopSound), reqHandler))
{
new LtsWidgets::LtsMessageDialogNew(this, tr("Stopping sound failed with unknown error"));
return;
}
connect(reqHandler, &ControlSoundRequester::finished,
this, [this, reqHandler](const QString &msg)
{
if (!msg.isEmpty())
{
new LtsWidgets::LtsMessageDialogNew(this, msg);//tr("Stopping sound failed: %1").arg(msg));
return;
}
reqHandler->deleteLater();
});
// {
// LtsWidgets::LtsGlobalWaitDialog::getInstance()->wait();
// }
});
m_buttonBox->connectButton(LtsWidgets::DialogButton::Hide, this, &SoundAreaEditDialog::onStopAllSounds);
DEBUG_LOG(m_logger) << "init successful";
return true;
}
} // namespace EffectManagement
@@ -0,0 +1,165 @@
/**
* @RDE_HEADER@
* Plugin to manage effects.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, NLE, 2020-07-29
*/
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <LtsUtilsGuiDds/request_helper.h>
#include <SoundManagement/som_dtc.h>
#include <SoundManagement/som_ftc.h>
namespace NGL
{
class INGLLogger;
}
namespace LtsSession
{
class LtsSessionDataDds;
}
namespace LtsUtils
{
class RequestHelper;
}
namespace Ui
{
class SoundAreaEditDialog;
class AddSoundProcessDialog;
}
namespace EffectManagement
{
struct SoundArea;
class SoundAreaHelper;
class SoundAreaTreeModel;
class SoundAreaPlaylistModel;
class SoundAreaEditDialog;
///// AddSoundProcessDialog
//class AddSoundProcessDialog : public QWidget
//{
// Q_OBJECT
//public:
// AddSoundProcessDialog(QWidget *parent);
//signals:
// void accepted();
// void rejected();
//private:
// Ui::AddSoundProcessDialog *m_ui;
//};
///// AddSoundProcess
//class AddSoundProcess : public QObject
//{
// Q_OBJECT
//public:
// friend class SoundAreaEditDialog;
// AddSoundProcess(const SoundManagement::SoundCategory category, const int soundId, const bool inLoop, SoundAreaEditDialog *parent);
//private:
// const SoundManagement::SoundCategory m_category;
// const int m_soundId;
// const bool m_inLoop;
// SoundAreaEditDialog *m_dialog;
// std::unique_ptr<AddSoundProcessDialog> m_overlay;
//};
/// ControlSoundRequester
class ControlSoundRequester
: public QObject
, public SoundManagement::Interface::Ftc::ControlSoundReplyHandler
{
Q_OBJECT
public:
void onControlSoundReply(const Core::FunctionReplyObject &reply) override final
{
m_reply = reply;
emit finished(m_reply.translated());
deleteLater();
}
signals:
void finished(const QString &msg);
private:
Core::FunctionReplyObject m_reply;
};
/**
* @brief The SoundAreaEditDialog class implements the ability to activate and deactivate Sounds
* inside a specified SoundArea. Sounds can be played either once or in a loop.
*/
class SoundAreaEditDialog
: public LtsWidgets::LtsDialog
{
Q_OBJECT
public:
explicit SoundAreaEditDialog(const SoundArea &soundArea, QWidget *parent = nullptr);
~SoundAreaEditDialog();
private slots:
/**
* @brief onPlaySound adds a Sound selected in the TreeView to the playlist.
* @param category SoundCategory
* @param soundId ID of the Sound within its category
* @param inLoop whether to play the Sound in a loop
*/
void onPlaySound(SoundManagement::SoundCategory category, int soundId, bool inLoop, int volume);
/**
* @brief onStopAllSounds stops all active Sounds.
*/
void onStopAllSounds();
public:
bool init(LtsSession::LtsSessionDataDds *session);
private:
void retranslate() override;
std::shared_ptr<SoundManagement::Interface::Dtc> m_somDtc{nullptr};
std::shared_ptr<SoundManagement::Interface::Ftc> m_somFtc{nullptr};
std::shared_ptr<SoundAreaHelper> m_helper{nullptr};
QString m_menuGroup;
SoundArea *m_soundArea;
SoundAreaTreeModel *m_treeModel{nullptr};
SoundAreaPlaylistModel *m_playlistModel{nullptr};
QHash<int32_t, QCheckBox *> m_egcuCheckBoxes;
LtsSession::LtsSessionDataDds *m_session{nullptr};
Ui::SoundAreaEditDialog *m_ui{nullptr};
NGL::INGLLogger &m_logger;
}; // class EffectManagementDialog
} // namespace EffectManagement
@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SoundAreaEditDialog</class>
<widget class="QWidget" name="SoundAreaEditDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1056</width>
<height>525</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="2">
<widget class="QLabel" name="lbxPlaylist">
<property name="text">
<string>Playlist</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lbxEgcu">
<property name="text">
<string>EGCU:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lbxSounds">
<property name="text">
<string>Sounds</string>
</property>
</widget>
</item>
<item row="1" column="2" colspan="2">
<widget class="QTableView" name="tvPlaylist">
<attribute name="horizontalHeaderStretchLastSection">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QTreeView" name="tvSounds">
<attribute name="headerStretchLastSection">
<bool>false</bool>
</attribute>
</widget>
</item>
<item row="3" column="1" colspan="3">
<widget class="QWidget" name="wEgcu" native="true"/>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,275 @@
/**
* @RDE_HEADER@
* Playlist model for SoundAreas.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, NLE, 2020-08-10
*/
#include "efm_sound_area_edit_model_playlist.h"
#include "efm_sound_area_helper.h"
#include "../logger.h"
#include <QMouseEvent>
#include <QApplication>
#include <QTimer>
#include <QTime>
#include <QSpinBox>
#include <QDebug>
namespace EffectManagement
{
//=============================================================================================================================
// SOUNDPLAYLISTDELEGATE
//=============================================================================================================================
QIcon SoundAreaEditPlaylistDelegate::s_iconInf = QIcon(QStringLiteral("icon:infinity.svg"));
SoundAreaEditPlaylistDelegate::SoundAreaEditPlaylistDelegate(QObject *parent)
: QStyledItemDelegate(parent)
{
}
//-----------------------------------------------------------------------------------------------------------------------------
// PUBLIC MEMBER FUNCTIONS
//-----------------------------------------------------------------------------------------------------------------------------
void SoundAreaEditPlaylistDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
const QVariant data(index.data(Qt::DisplayRole));
if ((index.column() == SoundAreaPlaylistModel::Column::Duration) && (data.toString().isEmpty()))
{
s_iconInf.paint(painter, option.rect, Qt::AlignCenter);
return;
}
if (index.column() != SoundAreaPlaylistModel::Column::Option)
{
QStyledItemDelegate::paint(painter, option, index);
return;
}
QStyleOptionButton button;
button.rect = option.rect;
button.state = QStyle::State_Enabled;
button.iconSize = QSize(25, 25);
button.icon = QIcon(QStringLiteral("icon:delete.svg"));
QApplication::style()->drawControl(QStyle::CE_PushButton, &button, painter);
}
//=============================================================================================================================
// SOUNDPLAYLISTMODEL
//=============================================================================================================================
SoundAreaPlaylistModel::SoundAreaPlaylistModel(const QVector<int32_t> &egcuIds, std::shared_ptr<SoundAreaHelper> &helper, QWidget *parent)
: LtsAbstractTableModel<SoundState>({tr("Category"),
tr("Sound"),
tr("EGCU"),
tr("Duration"),
tr("Option")},
parent)
, m_helper(helper)
, m_egcuIds(egcuIds)
, m_logger(getLogger("Plugins.Gui.SoundArea.EditModelPlaylist"))
{
}
//-----------------------------------------------------------------------------------------------------------------------------
// PUBLIC SLOTS
//-----------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------
// PRIVATE SLOTS
//-----------------------------------------------------------------------------------------------------------------------------
void SoundAreaPlaylistModel::onTimeout()
{
for (int i = 0; i < m_vecData.count(); ++i)
m_vecData[i].duration(std::max(0, m_vecData[i].duration() - 1000));
emit dataChanged({}, {});
}
//-----------------------------------------------------------------------------------------------------------------------------
// PUBLIC MEMBER FUNCTIONS
//-----------------------------------------------------------------------------------------------------------------------------
bool SoundAreaPlaylistModel::init(std::shared_ptr<SoundManagement::Interface::Dtc> &somDtc)
{
DEBUG_LOG(m_logger) << "init";
const QMap<int32_t, SoundManagement::SoundState> soundStates = somDtc->soundStates();
for (const auto &data : qAsConst(soundStates))
{
if (!m_egcuIds.contains(data.egcuId()))
continue;
addActiveSound(SoundState(data));
}
somDtc->enableSoundState(true);
connect(somDtc.get(), &SoundManagement::Interface::Dtc::soundStateChanged, this,
[this](const SoundManagement::SoundState &data, DataModification modType)
{
onDataChanged(SoundState(data), modType);
});
m_timer = new QTimer(this);
connect(m_timer, &QTimer::timeout, this, &SoundAreaPlaylistModel::onTimeout);
m_timer->start(1000);
DEBUG_LOG(m_logger) << "init successful";
return true;
}
int SoundAreaPlaylistModel::indexOf(const SoundState &data) const
{
int idx = 0;
for (const auto &item : qAsConst(m_vecData))
{
if ( (item.category() == data.category()) &&
(item.soundId() == data.soundId()) &&
(item.egcuId() == data.egcuId()) )
return idx;
++idx;
} // for
return -1;
}
bool SoundAreaPlaylistModel::addActiveSound(SoundState data)
{
data.duration(m_helper->soundDuration(data.category(), data.soundId()));
const int row = indexOf(data);
const QString name(m_helper->soundName(data.category(), data.soundId()));
if (row != -1)
{
ERROR_LOG(m_logger) << "'" << name << "' is already active";
return false;
}
data.status(SoundState::Status::Active);
insertRow(data);
DEBUG_LOG(m_logger) << "adding '" << name << "' to active Sounds";
return true;
}
bool SoundAreaPlaylistModel::removeActiveSound(const QModelIndex &index)
{
if (!index.isValid())
return false;
return removeRow(index.row());
}
QVariant SoundAreaPlaylistModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
const SoundState &soundState = m_vecData.at(index.row());
switch (role)
{
case Qt::DisplayRole:
case Qt::EditRole:
switch (index.column())
{
case Column::Category:
return m_helper->categoryName(soundState.category());
case Column::Sound:
return m_helper->soundName(soundState.category(), soundState.soundId());
case Column::Egcu:
return m_helper->egcuName(soundState.egcuId());
case Column::Duration:
return soundState.inLoop() ? QString() : QTime(0, 0).addMSecs(soundState.duration()).toString(QStringLiteral("hh:mm:ss.zzz"));
case Column::Option:
default:
return soundState.status();
} // switch
case Qt::BackgroundColorRole:
if ( (index.column() != Column::Category) && (index.column() != Column::Sound))
return QVariant();
return m_helper->soundCategoryBackgroundColor(static_cast<int32_t>(soundState.category().underlying()));
case Qt::TextColorRole:
if ( (index.column() != Column::Category) && (index.column() != Column::Sound))
return QVariant();
return m_helper->soundCategoryTextColor(static_cast<int32_t>(soundState.category().underlying()));
case Qt::TextAlignmentRole:
return index.column() == Column::Duration ? Qt::AlignCenter : Qt::AlignVCenter;
default:
return QVariant();
} // switch
}
bool SoundAreaPlaylistModel::onDataChanged(const SoundState &data, DataModification modType)
{
if (!m_egcuIds.contains(data.egcuId())) // not inside the SoundArea
return false;
int row;
QModelIndex idx;
switch (modType)
{
case DataModification::eAdded:
return addActiveSound(data);
case DataModification::eModified:
WARNING_LOG(m_logger) << "handling eModified for sound states not implemented yet";
return false;
case DataModification::eRemoved:
row = indexOf(data);
idx = SoundAreaPlaylistModel::index(m_vecData.indexOf(data), 0);
if (row == -1)
{
ERROR_LOG(m_logger) << "'" << m_helper->soundName(data.category(), data.soundId()) << "' is neither scheduled nor active";
return false;
} // if
return removeActiveSound(idx);
default:
Q_UNREACHABLE();
return false;
} // switch
}
bool SoundAreaPlaylistModel::insertRow(const SoundState &item)
{
beginInsertRows(QModelIndex(), m_vecData.size(), m_vecData.size());
m_vecData.push_back(item);
endInsertRows();
return true;
}
bool SoundAreaPlaylistModel::removeRow(int row)
{
return removeRows(row, 1);
}
//-----------------------------------------------------------------------------------------------------------------------------
// PRIVATE MEMBER FUNCTIONS
//-----------------------------------------------------------------------------------------------------------------------------
} // namespace EffectManagement
@@ -0,0 +1,125 @@
/**
* @RDE_HEADER@
* Playlist model for SoundAreas.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, NLE, 2020-08-10
*/
#pragma once
#include "efm_sound_state.h"
#include <LtsWidgets/lts_abstract_table_model.h>
#include <SoundManagement/som_dtc.h>
#include <QStyledItemDelegate>
class QTimer;
namespace NGL
{
class INGLLogger;
}
namespace EffectManagement
{
using SoundKey = QPair<int32_t, int32_t>;
class SoundAreaHelper;
/**
* @brief The SoundPlaylistDelegate class inherits from QItemDelegate and is used to draw specific
* elements inside the SoundPlayListModel.
*/
class SoundAreaEditPlaylistDelegate
: public QStyledItemDelegate
{
Q_OBJECT
public:
SoundAreaEditPlaylistDelegate(QObject *parent = nullptr);
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
private:
static QIcon s_iconInf;
}; // SoundAreaEditPlaylistDelegate
/**
* @brief The SoundPlaylistModel class implements a model to organize active SoundStates of a given
* SoundArea.
* @details The purpose of this class is to plan changes to the active Sounds of a SoundArea. It
* inherits LtsAbstractTableModel with SoundState (s. efm_sound_state.h) as template argument. This
* class does NOT send any requests to DDS whatsoever. Its only connection to DDS is a connection to
* the soundStateChanged signal from the Sound Management. An implicit conversion from
* SoundManagement::SoundState to a SoundState is provided. A distinction is made between active
* Sounds and scheduled / planned Sounds. Active Sounds are currently being played inside the
* SoundArea while scheduled / planned Sounds are not. In order to play a scheduled Sound you need
* to obtain all scheduled Sounds from this model, e.g. by getRowData(int). The returned object does
* contain all information required to send a request to the Sound Management.
*/
class SoundAreaPlaylistModel
: public LtsWidgets::LtsAbstractTableModel<SoundState>
{
Q_OBJECT
public:
enum Column { Category, Sound, Egcu, Duration, Option };
explicit SoundAreaPlaylistModel(const QVector<int32_t> &egcuIds, std::shared_ptr<SoundAreaHelper> &helper, QWidget *parent = nullptr);
private slots:
/**
* @brief onTimeout updates the time left for each active Sound.
*/
void onTimeout();
public:
bool init(std::shared_ptr<SoundManagement::Interface::Dtc> &somDtc);
/**
* @brief indexOf returns the index/row of a SoundState in the model.
* @param data a SoundState
* @return index in m_vecData, -1 if not found
*/
int indexOf(const SoundState &data) const;
/**
* @brief addActiveSound adds an active Sound to the model by inserting it at the end of all
* active Sounds (before scheduled Sounds).
* @param data a SoundState object
* @return true for success, false otherwise
*/
bool addActiveSound(SoundState data);
/**
* @brief removeActiveSound removes an active Sound from the model.
* @param index QModelIndex of a selected element
* @return true for success, false otherwise
*/
bool removeActiveSound(const QModelIndex &index);
protected:
QVariant data(const QModelIndex &index, int role) const override;
bool onDataChanged(const SoundState &data, DataModification modType) override;
bool insertRow(const SoundState &item) override;
bool removeRow(int row) override;
private:
std::shared_ptr<SoundAreaHelper> m_helper{nullptr};
QVector<int32_t> m_egcuIds;
QTimer *m_timer{nullptr};
NGL::INGLLogger &m_logger;
}; // class SoundPlaylistModel
} // namespace EffectManagement
@@ -0,0 +1,408 @@
/**
* @RDE_HEADER@
* Model for Sound selection.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, NLE, 2020-08-10
*/
#include "efm_sound_area_edit_model_tree.h"
#include "efm_sound_area.h"
#include "efm_sound_area_helper.h"
#include "../logger.h"
#include <QSpinBox>
#include <QApplication>
#include <algorithm>
#include <QDebug>
namespace EffectManagement
{
/// SpinBoxDelegate
SpinBoxDelegate::SpinBoxDelegate(QObject *parent)
: QStyledItemDelegate(parent)
{}
QWidget *SpinBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if (index.column() != SoundAreaTreeModel::Column::Volume)
return QStyledItemDelegate::createEditor(parent, option, index);
auto *sb = new QSpinBox(parent);
sb->setFrame(false);
sb->setSuffix(QStringLiteral(" %"));
sb->setRange(0, 100);
return sb;
}
void SpinBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
if (index.column() != SoundAreaTreeModel::Column::Volume)
{
QStyledItemDelegate::setEditorData(editor, index);
return;
}
qWarning() << index << index.data();
const int val = index.data(Qt::EditRole).toInt();
auto *sb = qobject_cast<QSpinBox *>(editor);
sb->setValue(val);
return;
}
void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
if (index.column() != SoundAreaTreeModel::Column::Volume)
{
QStyledItemDelegate::setModelData(editor, model, index);
return;
}
auto *sb = qobject_cast<QSpinBox *>(editor);
const int val = sb->value();
model->setData(index, val, Qt::EditRole);
}
void SpinBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/*index*/) const
{
editor->setGeometry(option.rect);
}
//=============================================================================================================================
// SOUNDTREEITEM
//=============================================================================================================================
SoundTreeItem::SoundTreeItem(const QVector<QVariant> &data, const SoundKey &key, SoundTreeItem *parent)
: m_parent(parent)
, m_data(data)
, m_soundKey(key)
{
}
SoundTreeItem::~SoundTreeItem()
{
qDeleteAll(m_children);
}
//-----------------------------------------------------------------------------------------------------------------------------
// PUBLIC MEMBER FUNCTIONS
//-----------------------------------------------------------------------------------------------------------------------------
void SoundTreeItem::appendChild(SoundTreeItem *item)
{
m_children.append(item);
}
void SoundTreeItem::toogleLoop()
{
if (isRepeatable())
m_data[SoundAreaTreeModel::Column::Loop] = -1 * m_data[SoundAreaTreeModel::Column::Loop].toInt();
}
void SoundTreeItem::toggleLoop(int inLoop)
{
if (isRepeatable())
{
if ( (inLoop != -1) && (inLoop != 1) )
return;
m_data[SoundAreaTreeModel::Column::Loop] = inLoop;
} // if
}
QString SoundTreeItem::toString() const
{
return QStringLiteral("SoundTreeItem( category : ") + QString::number(m_soundKey.first) + QStringLiteral(" | id : ") +
QString::number(m_soundKey.second) + QStringLiteral(" )");
}
//=============================================================================================================================
// SOUNDTREEMODEL
//=============================================================================================================================
SoundAreaTreeModel::SoundAreaTreeModel(const QVector<int> &egcuIds, std::shared_ptr<SoundAreaHelper> &helper, QWidget *parent)
: QAbstractItemModel(parent)
, m_helper(helper)
, m_root(new SoundTreeItem({tr("Category"), tr("Sound"), tr("Loop"), tr("Volume")}, SoundKey(0, 0)))
, m_egcuIds(egcuIds)
, m_logger(getLogger("Plugins.Gui.SoundArea.EditModelTree"))
{
}
SoundAreaTreeModel::~SoundAreaTreeModel()
{
delete m_root;
}
//-----------------------------------------------------------------------------------------------------------------------------
// PUBLIC SLOTS
//-----------------------------------------------------------------------------------------------------------------------------
void SoundAreaTreeModel::onSoundTreeItemActivated(const QModelIndex &index)
{
if (!index.isValid())
return;
switch (index.column())
{
case Column::Loop:
{
onToggleLoop(index);
break;
}
case Column::Volume:
break;
default:
{
onPlaySound(index);
break;
}
}
}
//-----------------------------------------------------------------------------------------------------------------------------
// PRIVATE SLOTS
//-----------------------------------------------------------------------------------------------------------------------------
bool SoundAreaTreeModel::onPlaySound(const QModelIndex &index)
{
SoundTreeItem *item = static_cast<SoundTreeItem *>(index.internalPointer());
emit playSound(m_helper->soundCategory(item->soundKey().first), item->soundKey().second, item->inLoop(), item->volume());
// => onAddSoundToPlaylist(SoundManagement::SoundCategory category, int soundId, bool inLoop, int volume)
return true;
}
bool SoundAreaTreeModel::onToggleLoop(const QModelIndex &index)
{
SoundTreeItem *item = static_cast<SoundTreeItem *>(index.internalPointer());
item->toogleLoop();
emit dataChanged(index, index);
return true;
}
//-----------------------------------------------------------------------------------------------------------------------------
// PUBLIC MEMBER FUNCTIONS
//-----------------------------------------------------------------------------------------------------------------------------
bool SoundAreaTreeModel::init(const std::shared_ptr<SoundManagement::Interface::Dtc> &somDtc)
{
DEBUG_LOG(m_logger) << "init";
// add sound categories
SoundKey key;
QVector<SoundManagement::SoundCategory> categories = m_helper->soundCategories();
for (const auto &category : qAsConst(categories))
{
QString name{m_helper->categoryName(category)};
QVector<QVariant> data{QVector<QVariant>{name, QVariant(), 0, 100}};
key.first = static_cast<int32_t>(category.underlying());
key.second = 0; // invalid sound index for category
m_root->appendChild(new SoundTreeItem(data, key, m_root));
} // for
// add sounds
SoundManagement::Sounds sounds = somDtc->sounds(); // undefined behaviour for somDtc->sounds().sounds()
for (const auto &sound : qAsConst(sounds.sounds()))
{
for (auto &category : m_root->children())
{
if (category->soundKey().first == static_cast<int32_t>(sound.category().underlying()))
{
QString displayName = m_helper->soundName(sound.category(), sound.soundId());
QVector<QVariant> data{QVector<QVariant>{category->data(0).toString(), displayName, sound.isRepeatable() ? 1 : 0, 100}};
key.first = static_cast<int32_t>(sound.category().underlying());
key.second = sound.soundId();
category->appendChild(new SoundTreeItem(data, key, category));
break;
} // if
} // for
} // for
return true;
}
bool SoundAreaTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (index.column() != SoundAreaTreeModel::Column::Volume
|| role != Qt::EditRole)
return QAbstractItemModel::setData(index, value, role);
bool k;
int val = value.toInt(&k);
if (!k)
return false;
static_cast<SoundTreeItem *>(index.internalPointer())->setVolume(val);
emit dataChanged(index, index);
return true;
}
SoundTreeItem * SoundAreaTreeModel::find(const SoundKey &key)
{
QVector<SoundTreeItem *> categories = m_root->children();
for (auto category : qAsConst(categories))
{
if (category->soundKey() == key)
return category;
QVector<SoundTreeItem *> sounds = category->children();
for (auto sound : qAsConst(sounds))
if (sound->soundKey() == key)
return sound;
} // for
return nullptr;
}
Qt::ItemFlags SoundAreaTreeModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::NoItemFlags;
if (index.column() != SoundAreaTreeModel::Column::Volume)
return QAbstractItemModel::flags(index);
return QAbstractItemModel::flags(index).setFlag(Qt::ItemFlag::ItemIsEditable);
}
QVariant SoundAreaTreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if ( (role != Qt::DisplayRole) && (role != Qt::ToolTipRole) &&
(role != Qt::BackgroundColorRole) && (role != Qt::TextColorRole) &&
(role != Qt::EditRole))
return QVariant();
SoundTreeItem *item = static_cast<SoundTreeItem *>(index.internalPointer());
switch (role)
{
case Qt::EditRole:
switch (index.column())
{
case Column::Volume: return item->volume();
default:
Q_UNREACHABLE();
return QVariant();
}
case Qt::DisplayRole:
if (item->soundKey().second == 0)
return index.column() == Column::Category ? item->data(index.column()) : QVariant();
switch (index.column())
{
case Column::Category: return QVariant();
case Column::Sound: return item->data(index.column());
case Column::Loop: return item->isRepeatable() ? item->data(index.column()) : QVariant();
case Column::Volume: return QStringLiteral("%1 %").arg(item->volume());
default:
Q_UNREACHABLE();
return QVariant();
} // switch
case Qt::ToolTipRole:
if ( (item->soundKey().second == 0) && (index.column() != Column::Category) )
return QVariant();
switch (index.column())
{
case Column::Category: return item->data(Column::Category).toString();
case Column::Sound: return item->data(Column::Sound).toString();
case Column::Loop: return item->inLoop() ? tr("play in loop") : tr("play once");
case Column::Volume: return tr("Volume: %1 %").arg(item->volume());
default:
Q_UNREACHABLE();
return QVariant();
} // switch
case Qt::BackgroundRole:
if ( (index.column() == Column::Category) ||
( (index.column() == Column::Sound) && (item->soundKey().second != 0) ) )
return m_helper->soundCategoryBackgroundColor(item->soundKey().first);
return QVariant();
case Qt::TextColorRole:
if ((index.column() == Column::Category) || (index.column() == Column::Sound))
return m_helper->soundCategoryTextColor(item->soundKey().first);
return QVariant();
default: // unreachable
Q_UNREACHABLE();
return QVariant();
}
}
QVariant SoundAreaTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
{
return ( (orientation == Qt::Horizontal) && (role == Qt::DisplayRole) ) ? m_root->data(section) : QVariant();
}
QModelIndex SoundAreaTreeModel::index(int row, int column, const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent))
return {};
SoundTreeItem *item;
if(!parent.isValid())
item = m_root;
else
item = static_cast<SoundTreeItem *>(parent.internalPointer());
SoundTreeItem *child = item->child(row);
return child ? createIndex(row, column, child) : QModelIndex();
}
QModelIndex SoundAreaTreeModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return {};
SoundTreeItem *parent = static_cast<SoundTreeItem *>(index.internalPointer())->parent(); // parent of the item at index
return parent == m_root ? QModelIndex() : createIndex(parent->row(), 0, parent);
}
int SoundAreaTreeModel::rowCount(const QModelIndex &index) const
{
if (index.column() > 0)
return 0;
SoundTreeItem *parent;
if (!index.isValid())
parent = m_root;
else
parent = static_cast<SoundTreeItem *>(index.internalPointer());
return parent->childCount();
}
int SoundAreaTreeModel::columnCount(const QModelIndex &index) const
{
return index.isValid() ? static_cast<SoundTreeItem *>(index.internalPointer())->columnCount() : m_root->columnCount();
}
} // namespace EffectManagement
@@ -0,0 +1,180 @@
/**
* @RDE_HEADER@
* Model for Sound selection.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, NLE, 2020-08-10
*/
#pragma once
#include <LtsWidgets/lts_abstract_table_model.h>
#include <SoundManagement/som_dtc.h>
#include <QAbstractItemModel>
#include <QStyledItemDelegate>
namespace NGL
{
class INGLLogger;
}
namespace EffectManagement
{
using SoundKey = QPair<int32_t, int32_t>;
struct SoundArea;
class SoundAreaHelper;
/**
* @brief The SoundTreeItem class represents an item in a QTreeView with a parent and children.
*/
class SoundTreeItem
{
public:
enum Column { Category, Sound, Loop, Volume };
explicit SoundTreeItem(const QVector<QVariant> &data, const SoundKey &key, SoundTreeItem *parent = nullptr);
~SoundTreeItem();
/**
* @brief appendChild adds a child to the list of children.
* @param item a SoundTreeItem
*/
void appendChild(SoundTreeItem *item);
/**
* @brief toogleLoop changes the setting to play a Sound in a loop or only once.
*/
void toogleLoop();
/**
* @brief toggleLoop sets the setting to play a Sound in a loop or only once.
* @param inLoop 1 for playing a Sound in a loop, -1 to play it only once
*/
void toggleLoop(int inLoop);
QVariant data(const int &column) const { return (column < 0 || column >= m_data.size()) ? QVariant() : m_data.at(column); }
SoundKey soundKey() const { return m_soundKey; }
bool isRepeatable() const { return m_data[Column::Loop] != 0; }
bool inLoop() const { return m_data[Column::Loop] == 1; }
int volume() const { return m_data[Column::Volume].toInt(); }
void setVolume(int volume) { m_data[Column::Volume] = volume; }
SoundTreeItem *parent() { return m_parent; }
SoundTreeItem *child(int row) { return (row < 0 || row >= m_children.size()) ? nullptr : m_children.at(row); }
QVector<SoundTreeItem *> children() const { return m_children; }
int row() const { return m_parent ? m_parent->m_children.indexOf(const_cast<SoundTreeItem *>(this)) : 0; }
int columnCount() const { return m_data.count(); }
int childCount() const { return m_children.count(); }
QString toString() const;
private:
QVector<SoundTreeItem *> m_children;
SoundTreeItem *m_parent{nullptr};
QVector<QVariant> m_data;
SoundKey m_soundKey;
}; // class SoundTreeItem
/// SpinBoxDelegate
class SpinBoxDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
SpinBoxDelegate(QObject *parent = nullptr);
protected:
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
};
/**
* @brief The SoundTreeModel class provides a hierarchical model for SoundCategory and Sound to
* visualize in a QTreeView.
*/
class SoundAreaTreeModel
: public QAbstractItemModel
{
Q_OBJECT
public:
enum Column { Category, Sound, Loop, Volume };
explicit SoundAreaTreeModel(const QVector<int> &egcuIds, std::shared_ptr<SoundAreaHelper> &helper, QWidget *parent = nullptr);
~SoundAreaTreeModel();
signals:
/**
* @brief playSound can be used to connect to the FTC in order to play a Sound.
*/
void playSound(const SoundManagement::SoundCategory, const int, const bool, const int);
public slots:
/**
* @brief onSoundTreeItemActivated delegates to onPlaySound or onToggleLoop when the TreeView is clicked.
* @param index QModelIndex of the Sound.
*/
void onSoundTreeItemActivated(const QModelIndex &index);
private slots:
/**
* @brief onPlaySound emits the playSound signal that can be connected to start a request.
* @param index QModelIndex of the selected Sound
* @return true for success, false otherwise
*/
bool onPlaySound(const QModelIndex &index);
/**
* @brief onToggleLoop flips the setting to play a Sound in a loop or only once.
* @param index QModelIndex of the Sound
* @return true for success, false otherwise
*/
bool onToggleLoop(const QModelIndex &index);
public:
bool init(const std::shared_ptr<SoundManagement::Interface::Dtc> &somDtc);
/**
* @brief find returns the SoundTreeItem defined by its SoundKey.
* @param key a SoundKey with the SoundCategory and Sound ID as integers
* @return corresponding SoundTreeItem
*/
SoundTreeItem * find(const SoundKey &key);
protected:
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
QModelIndex parent(const QModelIndex &index) const override;
int rowCount(const QModelIndex &index) const override;
int columnCount(const QModelIndex &index) const override;
private:
std::shared_ptr<SoundAreaHelper> m_helper{nullptr};
SoundTreeItem *m_root{nullptr};
QVector<int32_t> m_egcuIds;
NGL::INGLLogger &m_logger;
}; // class SoundModel
} // namespace EffectManagement
@@ -0,0 +1,79 @@
/**
* @RDE_HEADER@
* SoundArea Plugin for effect management.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, NLE, 2020-07-29
*/
#include "efm_sound_area_gui_plugin.h"
#include "efm_sound_area_edit_dialog.h"
#include "efm_sound_area_select_dialog.h"
#include "../logger.h"
#include <LtsSession/lts_session.h>
namespace EffectManagement
{
std::shared_ptr<GuiPluginBase::Interface> GuiPlugin::createGuiInterface(LtsSession::LtsSession *session)
{
return std::make_shared<InterfaceImpl>(session);
}
InterfaceImpl::InterfaceImpl(LtsSession::LtsSession *session)
: GuiPluginBase::Interface(session, getLogger("Plugins.Gui.SoundArea"))
{
}
bool InterfaceImpl::fetchInterfaces()
{
return true;
}
void InterfaceImpl::clearInterfaces()
{
}
QString InterfaceImpl::menuGroup() const
{
return tr("Effect Management");
}
QVector<LtsWidgets::PluginData> InterfaceImpl::getActions()
{
QVector<LtsWidgets::PluginData> ret;
{
LtsWidgets::PluginData plData;
plData.menuGroup = menuGroup();
plData.menuText = tr("Sound Area Selection");
plData.menuIcon = QIcon(QStringLiteral("icon:sound_area.svg"));
plData.identifier = QStringLiteral("efmSoundAreaSelect");
// plData.operatorRight = OperatorRights::ScreenRecording::RecordScreen;
plData.exercisePart = LtsWidgets::ExercisePart::eExecution;
plData.createWidgetFunc = [this](QWidget *parent)
{
return onSoundAreaSelectSlot(parent);
};
ret.append(plData);
}
return ret;
}
LtsWidgets::LtsDialog *InterfaceImpl::onSoundAreaSelectSlot(QWidget *parent)
{
DEBUG_LOG(m_logger) << "Starting Sound Area Select";
SoundAreaSelectDialog *dialog = new SoundAreaSelectDialog(parent);
dialog->init(m_session, menuGroup());
return dialog;
}
} // namespace EffectManagement
@@ -0,0 +1,69 @@
/**
* @RDE_HEADER@
* SoundArea Plugin for effect management.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, NLE, 2020-07-29
*/
#pragma once
#include <PluginInterfaces/gui_plugin_interface.h>
#include <Plugins/EffectManagement/efm_gui_plugin_interface.h>
namespace EffectManagement
{
class GuiPlugin final : public QObject, public GuiPluginBase::Plugin
{
Q_PLUGIN_METADATA(IID "gui:3:efm.sound_areas")
Q_INTERFACES(GuiPluginBase::Plugin)
Q_OBJECT
public:
explicit GuiPlugin() = default;
~GuiPlugin() = default;
QString pluginName() override { return QStringLiteral("EffectManagementSoundAreaGuiPlugin"); }
std::shared_ptr<GuiPluginBase::Interface> createGuiInterface(LtsSession::LtsSession *session) override;
bool availableInPartition(IDL::PartitionType partition) const override
{
return (partition == IDL::PartitionType::Exercise) ||
(partition == IDL::PartitionType::Global);
}
};
class InterfaceImpl final : public QObject, public GuiPluginBase::Interface
{
Q_OBJECT
public:
explicit InterfaceImpl(LtsSession::LtsSession *session);
bool fetchInterfaces() override;
void clearInterfaces() override;
QString menuGroup() const override;
QVector<LtsWidgets::PluginData> getActions() override;
bool availableInPartition(IDL::PartitionType partition) const override
{
return (partition == IDL::PartitionType::Exercise) ||
(partition == IDL::PartitionType::Global);
}
private slots:
/**
* @brief onSoundAreaSelectSlot creates a SoundAreaSelectDialog.
* @param parent pointer to the parent
* @return SoundAreaSelectDialog instance
*/
LtsWidgets::LtsDialog *onSoundAreaSelectSlot(QWidget *parent);
private:
};
} // namespace EffectManagement
@@ -0,0 +1,287 @@
/**
* @RDE_HEADER@
* Helper class for SoundAreas.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, NLE, 2020-08-10
*/
#include "efm_sound_area_helper.h"
#include "../logger.h"
#include <QVector>
#include <QColor>
namespace EffectManagement
{
//=============================================================================================================================
// SOUNDMANAGEMENTHELPER
//=============================================================================================================================
SoundAreaHelper::SoundAreaHelper(SoundAreaHelper *helper)
: m_ismDtc(helper->ismDtc())
, m_somDtc(helper->somDtc())
, m_logger(getLogger("Plugins.Gui.SoundArea.Helper"))
{
QMap<int32_t, InfrastructureManagement::InstrumentationAsset> assets = m_ismDtc->instrumentationAssets();
for (const auto &asset : qAsConst(assets))
if (asset.mountingPointTypeId() == InfrastructureManagement::MountingPointType_def::EffectGenerationControlUnit)
m_egcuNames.insert(asset.id(), QString::fromStdString(asset.name()));
SoundManagement::Sounds sounds = m_somDtc->sounds();
for (const auto &sound : qAsConst(sounds.sounds()))
m_soundDuration.insert(SoundKey(sound.category().underlying(), sound.soundId()), sound.duration());
}
SoundAreaHelper::SoundAreaHelper(std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
std::shared_ptr<SoundManagement::Interface::Dtc> &somDtc)
: m_ismDtc(ismDtc)
, m_somDtc(somDtc)
, m_logger(getLogger("Plugins.Gui.SoundArea.Helper"))
{
QMap<int32_t, InfrastructureManagement::InstrumentationAsset> assets = m_ismDtc->instrumentationAssets();
for (const auto &asset : qAsConst(assets))
if (asset.mountingPointTypeId() == InfrastructureManagement::MountingPointType_def::EffectGenerationControlUnit)
m_egcuNames.insert(asset.id(), QString::fromStdString(asset.name()));
SoundManagement::Sounds sounds = m_somDtc->sounds();
for (const auto &sound : qAsConst(sounds.sounds()))
m_soundDuration.insert(SoundKey(sound.category().underlying(), sound.soundId()), sound.duration());
}
//-----------------------------------------------------------------------------------------------------------------------------
// PUBLIC MEMBER FUNCTIONS
//-----------------------------------------------------------------------------------------------------------------------------
QVector<SoundManagement::SoundCategory> SoundAreaHelper::soundCategories()
{
QVector<SoundManagement::SoundCategory> categories = QVector<SoundManagement::SoundCategory>
{
SoundManagement::SoundCategory_def::Aircraft,
SoundManagement::SoundCategory_def::Battlefield,
SoundManagement::SoundCategory_def::Boat,
SoundManagement::SoundCategory_def::Explosion,
SoundManagement::SoundCategory_def::Helicopter,
SoundManagement::SoundCategory_def::MotorsAndUrbanTraffic,
SoundManagement::SoundCategory_def::Vehicle,
SoundManagement::SoundCategory_def::InsideBuilding
};
return categories;
}
QString SoundAreaHelper::categoryName(SoundManagement::SoundCategory category)
{
switch (category.underlying())
{
case SoundManagement::SoundCategory_def::Aircraft: return QStringLiteral("Aircraft");
case SoundManagement::SoundCategory_def::Battlefield: return QStringLiteral("Battlefield");
case SoundManagement::SoundCategory_def::Boat: return QStringLiteral("Boat");
case SoundManagement::SoundCategory_def::Explosion: return QStringLiteral("Explosion");
case SoundManagement::SoundCategory_def::Helicopter: return QStringLiteral("Helicopter");
case SoundManagement::SoundCategory_def::MotorsAndUrbanTraffic: return QStringLiteral("MotorsAndUrbanTraffic");
case SoundManagement::SoundCategory_def::Vehicle: return QStringLiteral("Vehicle");
case SoundManagement::SoundCategory_def::InsideBuilding: return QStringLiteral("InsideBuilding");
case SoundManagement::SoundCategory_def::Unknown: return QStringLiteral("Unknown");
default:
return QString();
} // switch
}
QString SoundAreaHelper::categoryName(const int32_t &category)
{
return categoryName(soundCategory(category));
}
QString SoundAreaHelper::soundName(SoundManagement::SoundCategory category, const int &id)
{
switch (category.underlying())
{
case SoundManagement::SoundCategory_def::Aircraft:
switch (id)
{
case 1: return QStringLiteral("Jet_Pass_by_Military");
case 2: return QStringLiteral("Military_Aircraft_Fires");
case 3: return QStringLiteral("Military_Aircraft_Fly_By");
case 4: return QStringLiteral("Military_Airplane_Drops");
default:
return QStringLiteral("Error");
} // switch
case SoundManagement::SoundCategory_def::Battlefield:
switch (id)
{
case 1: return QStringLiteral("Battlefield_Ambience_Noise");
case 2: return QStringLiteral("Battlefield_Ambience_Tank");
case 3: return QStringLiteral("Battlefield_Ambience_War");
case 4: return QStringLiteral("Explosions_Battlefield");
case 5: return QStringLiteral("Explosions_Battlefield_1");
case 6: return QStringLiteral("Ground_Battle_with_Machine_Guns");
case 7: return QStringLiteral("Modern_Battlefield");
default:
return QStringLiteral("Error");
} // switch
case SoundManagement::SoundCategory_def::Boat:
switch (id)
{
default:
return QStringLiteral("Error");
} // switch
case SoundManagement::SoundCategory_def::Explosion:
switch (id)
{
case 1: return QStringLiteral("Explosion_Building_Crash");
default:
return QStringLiteral("Error");
} // switch
case SoundManagement::SoundCategory_def::Helicopter:
switch (id)
{
case 1: return QStringLiteral("Helicopter_Crash");
case 2: return QStringLiteral("Helicopter_Fly_Overhead");
case 3: return QStringLiteral("Helicopter_Landing");
case 4: return QStringLiteral("Helicopter_Pass_by_Military");
case 5: return QStringLiteral("Helicopter_Take_off");
default:
return QStringLiteral("Error");
} // switch
case SoundManagement::SoundCategory_def::MotorsAndUrbanTraffic:
switch (id)
{
case 1: return QStringLiteral("Big_City_Street_Traffic");
case 2: return QStringLiteral("City_Crossroads_Traffic");
case 3: return QStringLiteral("City_Street_Heavy_Traffic");
case 4: return QStringLiteral("City_Street_Noisy_Walking");
case 5: return QStringLiteral("Construction_Building_Ambient");
case 6: return QStringLiteral("Demonstration_and_Rioting");
case 7: return QStringLiteral("Noisy_City_Street");
case 8: return QStringLiteral("Stadium_Crowd_Ambient");
case 9: return QStringLiteral("Stadium_Crowd_Applause");
case 10: return QStringLiteral("Traffic_from_Car");
case 11: return QStringLiteral("Muezzincalling");
default:
return QStringLiteral("Error");
} // switch
case SoundManagement::SoundCategory_def::Vehicle:
switch (id)
{
case 1: return QStringLiteral("Tank_Starting_and_Stopping");
default:
return QStringLiteral("Error");
} // switch
case SoundManagement::SoundCategory_def::InsideBuilding:
switch (id)
{
case 1: return QStringLiteral("Fire_quietly");
case 2: return QStringLiteral("Fire_a_little_louder");
case 3: return QStringLiteral("Fire_louder");
case 4: return QStringLiteral("Fire_loud");
case 5: return QStringLiteral("Extinguishing_Noise");
case 7: return QStringLiteral("This_Room_is_Destroyed");
case 8: return QStringLiteral("This_Building_is_Destroyed");
default:
return QStringLiteral("Error");
} // switch
case SoundManagement::SoundCategory_def::Unknown:
switch(id)
{
default:
return QStringLiteral("Error");
} // switch
default:
return QStringLiteral("Error");
} // switch
}
QString SoundAreaHelper::soundName(const int &category, const int &id)
{
return soundName(soundCategory(category), id);
}
int SoundAreaHelper::soundDuration(SoundManagement::SoundCategory category, const int &id) const
{
return soundDuration(static_cast<int>(category.underlying()), id);
}
int SoundAreaHelper::soundDuration(const int &category, const int &id) const
{
SoundKey key{category, id};
return m_soundDuration.contains(key) ? m_soundDuration.value(key) : 0;
}
QString SoundAreaHelper::egcuName(const int &id) const
{
return m_egcuNames.contains(id) ? m_egcuNames.value(id) : QString();
}
QColor SoundAreaHelper::soundCategoryTextColor(const int32_t &category)
{
switch (category)
{
case SoundManagement::SoundCategory_def::Aircraft: return {Qt::white};
case SoundManagement::SoundCategory_def::Battlefield: return {Qt::white};
case SoundManagement::SoundCategory_def::Boat: return {Qt::black};
case SoundManagement::SoundCategory_def::Explosion: return {Qt::white};
case SoundManagement::SoundCategory_def::Helicopter: return {Qt::white};
case SoundManagement::SoundCategory_def::MotorsAndUrbanTraffic: return {Qt::white};
case SoundManagement::SoundCategory_def::Vehicle: return {Qt::black};
case SoundManagement::SoundCategory_def::InsideBuilding: return {Qt::black};
case SoundManagement::SoundCategory_def::Unknown: return {Qt::white};
default:
return {Qt::black};
} // switch
}
QColor SoundAreaHelper::soundCategoryBackgroundColor(const int32_t &category)
{
switch (category)
{
case SoundManagement::SoundCategory_def::Aircraft: return QColor::fromRgb( 25, 25, 112);
case SoundManagement::SoundCategory_def::Battlefield: return QColor::fromRgb(160, 82, 45);
case SoundManagement::SoundCategory_def::Boat: return QColor::fromRgb(127, 255, 212);
case SoundManagement::SoundCategory_def::Explosion: return QColor::fromRgb(255, 0, 0);
case SoundManagement::SoundCategory_def::Helicopter: return QColor::fromRgb(153, 50, 204);
case SoundManagement::SoundCategory_def::MotorsAndUrbanTraffic: return QColor::fromRgb( 85, 107, 47);
case SoundManagement::SoundCategory_def::Vehicle: return QColor::fromRgb(255, 255, 0);
case SoundManagement::SoundCategory_def::InsideBuilding: return QColor::fromRgb(255, 160, 122);
case SoundManagement::SoundCategory_def::Unknown: return QColor::fromRgb(119, 136, 153);
default:
return {Qt::white};
} // switch
}
SoundManagement::SoundCategory SoundAreaHelper::soundCategory(const int &i)
{
switch (i)
{
case 1: return SoundManagement::SoundCategory_def::Aircraft;
case 2: return SoundManagement::SoundCategory_def::Battlefield;
case 3: return SoundManagement::SoundCategory_def::Boat;
case 4: return SoundManagement::SoundCategory_def::Explosion;
case 5: return SoundManagement::SoundCategory_def::Helicopter;
case 6: return SoundManagement::SoundCategory_def::MotorsAndUrbanTraffic;
case 7: return SoundManagement::SoundCategory_def::Vehicle;
case 8: return SoundManagement::SoundCategory_def::InsideBuilding;
case 9:
default:
return SoundManagement::SoundCategory_def::Unknown;
} // switch
}
} // namespace EffectManagement
@@ -0,0 +1,136 @@
/**
* @RDE_HEADER@
* Helper class for SoundAreas.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, NLE, 2020-08-10
*/
#pragma once
#include <SoundManagement/som_dtc.h>
#include <InfrastructureManagement/ism_dtc.h>
namespace NGL
{
class INGLLogger;
}
namespace EffectManagement
{
using SoundKey = QPair<int32_t, int32_t>;
/**
* @brief The SoundAreaHelper class provides utility functions for Infrastructure and Sound
* Management. Connections to the ISM-DTC and SOM-DTC are used.
*/
class SoundAreaHelper
{
public:
explicit SoundAreaHelper(SoundAreaHelper *helper);
explicit SoundAreaHelper(std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
std::shared_ptr<SoundManagement::Interface::Dtc> &somDtc);
public:
std::shared_ptr<InfrastructureManagement::Interface::Dtc> ismDtc() const { return m_ismDtc; }
std::shared_ptr<SoundManagement::Interface::Dtc> somDtc() const { return m_somDtc; }
/**
* @brief soundCategories returns a list with the SoundCategory enum from the Sound Management.
* @return a vector with all SoundCategory
*/
static QVector<SoundManagement::SoundCategory> soundCategories();
/**
* @brief categoryName returns the display name of a SoundCategory.
* @param category element of SoundCategory enum from Sound Management
* @return name of the SoundCategory
*/
static QString categoryName(SoundManagement::SoundCategory category);
/**
* @brief categoryName returns the display name of a SoundCategory.
* @param category integer corresponding to a SoundCategory enum element from Sound Management
* @return name of the SoundCategory
*/
static QString categoryName(const int32_t &category);
/**
* @brief soundName returns the display name of a Sound.
* @param category SoundCategory of the Sound
* @param id index of the Sound
* @return name of the Sound
*/
static QString soundName(SoundManagement::SoundCategory category, const int &id);
/**
* @brief soundName returns the display name of a Sound.
* @param category integer corresponding to a SoundCategory enum element from Sound Management
* @param id index of the Sound
* @return name of the Sound
*/
static QString soundName(const int &category, const int &id);
/**
* @brief soundDuration returns the duration of a Sound when played once.
* @param category SoundCategory of the Sound
* @param id ID of the Sound within its category
* @return duration of the Sound
*/
int soundDuration(SoundManagement::SoundCategory category, const int &id) const;
/**
* @brief soundDuraiton returns the duration of a Sound when played once.
* @param category SoundCategory of the Sound
* @param id ID of the Sound within its category
* @return duration of the Sound
*/
int soundDuration(const int &category, const int &id) const;
/**
* @brief egcuName returns the display name of an EGCU.
* @param id index of the EGCU
* @return name of the EGCU
*/
QString egcuName(const int &id) const;
/**
* @brief soundCategoryTextColor returns a QColor as background color of a SoundCategory.
* @param category integer corresponding to the SoundCategory enum value
* @return color of the SoundCategory background
*/
static QColor soundCategoryTextColor(const int32_t &category);
/**
* @brief soundCategoryTextColor returns a QColor as text color of a SoundCategory.
* @param category integer corresponding to the SoundCategory enum value
* @return color of the SoundCategory text
*/
static QColor soundCategoryBackgroundColor(const int32_t &category);
/**
* @brief soundCategory returns the index of a SoundCategory as a SoundCategory enum value.
* @param i integer index of a SoundCategory
* @return corresponding SoundCategory enum value
*/
static SoundManagement::SoundCategory soundCategory(const int &i);
private:
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
std::shared_ptr<SoundManagement::Interface::Dtc> m_somDtc;
QMap<int32_t, QString> m_egcuNames;
QMap<SoundKey, int> m_soundDuration;
NGL::INGLLogger &m_logger;
}; // class SoundManagementHelper
} // namespace EffectManagement
@@ -0,0 +1,173 @@
/**
* @RDE_HEADER@
* Plugin to watch the currently active sounds.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, NLE, 2020-07-29
*/
#include "efm_sound_area_select_dialog.h"
#include "ui_efm_sound_area_select_dialog.h"
#include "efm_sound_area_select_model.h"
#include "efm_sound_area_edit_dialog.h"
#include "../logger.h"
#include <LtsSession/lts_session.h>
#include <LtsUtilsGuiDds/request_helper.h>
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
#include <Plugins/EffectManagement/efm_data_plugin_interface.h>
namespace EffectManagement
{
//=============================================================================================================================
// SOUNDAREASELECTDIALOG
//=============================================================================================================================
SoundAreaSelectDialog::SoundAreaSelectDialog(QWidget *parent)
: LtsWidgets::LtsDialog(parent)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_model(new SoundAreaSelectModel(this))
, m_ui(new Ui::SoundAreasDialog)
, m_logger(getLogger("Plugins.Gui.SoundArea.SelectDialog"))
{
m_ui->setupUi(this);
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setText(tr("Stop All Sounds"));
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setIcon(QIcon(QStringLiteral("icon:avm_stop.svg")));
}
SoundAreaSelectDialog::~SoundAreaSelectDialog()
{
delete m_ui;
}
//-----------------------------------------------------------------------------------------------------------------------------
// PRIVATE SLOTS
//-----------------------------------------------------------------------------------------------------------------------------
void SoundAreaSelectDialog::onSelectSoundArea(const QModelIndex &index)
{
if (!index.isValid())
return;
if (index.column() == SoundAreaSelectModel::Column::Stop)
{
onStopSounds(index);
return;
} // if
SoundArea soundArea = m_model->getRowData(index.row());
SoundAreaEditDialog *dialog = new SoundAreaEditDialog(soundArea);
dialog->init(m_session);
addDialog(dialog, menuGroup(), soundArea.displayName, LtsWidgets::LayoutArea::eDialogTab);
}
void SoundAreaSelectDialog::onStopSounds(const QModelIndex &index)
{
SoundArea soundArea = m_model->getRowData(index.row());
if ( soundArea.egcuIds.isEmpty())
return;
const QVector<int> &egcuIds = soundArea.egcuIds;
for (const auto &egcu : qAsConst(egcuIds))
{
SoundManagement::StopAllSoundsRequest req(egcu);
m_requestHelper->startSingleRequest([this, req]()
{
return m_somFtc->stopAllSoundsRequest(req, this);
});
} // for
}
void SoundAreaSelectDialog::onStopAllSounds()
{
const QVector<SoundArea> &soundAreas = m_model->soundAreas();
for (const auto &soundArea : qAsConst(soundAreas))
{
const QVector<int> &egcuIds = soundArea.egcuIds;
for (const auto &egcu : qAsConst(egcuIds))
{
SoundManagement::StopAllSoundsRequest req(egcu);
m_requestHelper->startSingleRequest([this, req]() {
return m_somFtc->stopAllSoundsRequest(req, this);
});
}
} // for
}
//-----------------------------------------------------------------------------------------------------------------------------
// PUBLIC MEMBER FUNCTIONS
//-----------------------------------------------------------------------------------------------------------------------------
bool SoundAreaSelectDialog::init(LtsSession::LtsSessionDataDds *session, const QString &menuGroup)
{
DEBUG_LOG(m_logger) << "init";
m_session = session;
setMenuGroup(menuGroup);
std::shared_ptr<InfrastructureManagement::Interface::Dtc> ismDtc;
std::shared_ptr<SoundManagement::Interface::Dtc> somDtc;
if (!m_session->getDtc<InfrastructureManagement::DataInterface>(ismDtc))
{
ERROR_LOG(m_logger) << "connection to ISM-DTC failed";
return false;
} // if
if (!m_session->getDtc<EffectManagement::DataInterface>(somDtc))
{
ERROR_LOG(m_logger) << "connection to SOM-DTC failed";
return false;
} // if
if (!m_session->getFtc<EffectManagement::DataInterface>(m_somFtc))
{
ERROR_LOG(m_logger) << "connection to SOM-FTC failed";
return false;
} // if
if (!m_model->init(ismDtc, somDtc))
{
ERROR_LOG(m_logger) << "sound area select model initialization failed";
return false;
} // if
m_ui->tvSoundlist->setModel(m_model);
SoundAreaSelectDelegate *delegate = new SoundAreaSelectDelegate(m_model);
m_ui->tvSoundlist->setItemDelegate(delegate);
m_ui->tvSoundlist->horizontalHeader()->resizeSection(SoundAreaSelectModel::Column::Id, 50);
m_ui->tvSoundlist->horizontalHeader()->resizeSection(SoundAreaSelectModel::Column::Stop, 100);
m_ui->tvSoundlist->horizontalHeader()->setSectionResizeMode(SoundAreaSelectModel::Column::Id, QHeaderView::Fixed);
m_ui->tvSoundlist->horizontalHeader()->setSectionResizeMode(SoundAreaSelectModel::Column::Name, QHeaderView::ResizeToContents);
m_ui->tvSoundlist->horizontalHeader()->setSectionResizeMode(SoundAreaSelectModel::Column::AreaEgcu, QHeaderView::ResizeToContents);
m_ui->tvSoundlist->horizontalHeader()->setSectionResizeMode(SoundAreaSelectModel::Column::Egcus, QHeaderView::Stretch);
m_ui->tvSoundlist->horizontalHeader()->setSectionResizeMode(SoundAreaSelectModel::Column::ActiveSounds, QHeaderView::ResizeToContents);
m_ui->tvSoundlist->horizontalHeader()->setSectionResizeMode(SoundAreaSelectModel::Column::Stop, QHeaderView::Fixed);
connect(m_ui->tvSoundlist, &QTableView::clicked, this, &SoundAreaSelectDialog::onSelectSoundArea);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, this, &SoundAreaSelectDialog::onStopAllSounds);
DEBUG_LOG(m_logger) << "init successful";
return true;
}
void SoundAreaSelectDialog::retranslate()
{
translate(m_ui, tr("Sound Area Select"));
}
void SoundAreaSelectDialog::onStopAllSoundsReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
}
} // namespace EffectManagement
@@ -0,0 +1,95 @@
/**
* @RDE_HEADER@
* Plugin to watch the currently active sounds.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, NLE, 2020-07-29
*/
#pragma once
#include <SoundManagement/som_ftc.h>
#include <LtsWidgets/lts_dialog.h>
namespace NGL
{
class INGLLogger;
}
namespace LtsSession
{
class LtsSessionDataDds;
}
namespace LtsUtils
{
class RequestHelper;
}
namespace Ui
{
class SoundAreasDialog;
}
namespace EffectManagement
{
class SoundAreaSelectModel;
/**
* @brief The SoundAreaSelectDialog class implements the dialog used to choose a SoundArea from a
* list of all SoundAreas, instead of picking one via the SituationMap.
*/
class SoundAreaSelectDialog
: public LtsWidgets::LtsDialog
, protected SoundManagement::Interface::Ftc::StopAllSoundsReplyHandler
{
Q_OBJECT
public:
explicit SoundAreaSelectDialog(QWidget *parent = nullptr);
~SoundAreaSelectDialog();
private slots:
/**
* @brief onSelectSoundArea opens a SoundAreaEditDialog for the selected SoundArea or redirects
* to onStopSounds if the index' column corresponds to the stop button.
* @param index the selected SoundArea's model index
*/
void onSelectSoundArea(const QModelIndex &index);
/**
* @brief onStopSounds stops all currently playing sounds of the SoundArea.
* @param index the selected SoundAreas's model index
*/
void onStopSounds(const QModelIndex &index);
/**
* @brief onStopAllSounds stops all Sounds in all SoundAreas.
*/
void onStopAllSounds();
public:
bool init(LtsSession::LtsSessionDataDds *session, const QString &menuGroup);
private:
void retranslate() override;
void onStopAllSoundsReply(const Core::FunctionReplyObject &replyObject) override final;
std::shared_ptr<SoundManagement::Interface::Ftc> m_somFtc{nullptr};
LtsUtils::RequestHelper *m_requestHelper{nullptr};
SoundAreaSelectModel *m_model{nullptr};
LtsSession::LtsSessionDataDds *m_session{nullptr};
Ui::SoundAreasDialog *m_ui{nullptr};
NGL::INGLLogger &m_logger;
}; // class SoundAreasDialog
} // namespace EffectManagement
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SoundAreasDialog</class>
<widget class="QWidget" name="SoundAreasDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1065</width>
<height>486</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="lbxSoundlist">
<property name="text">
<string>Soundlist</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QTableView" name="tvSoundlist">
<property name="alternatingRowColors">
<bool>false</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="horizontalHeaderCascadingSectionResizes">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,290 @@
/**
* @RDE_HEADER@
* Model for the overall sound area table.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, NLE, 2020-07-29
*/
#include "efm_sound_area_select_model.h"
#include "efm_sound_area_helper.h"
#include "../logger.h"
#include <algorithm>
#include <QApplication>
#include <QTime>
namespace EffectManagement
{
//=============================================================================================================================
// SOUNDSELECTDELEGATE
//=============================================================================================================================
SoundAreaSelectDelegate::SoundAreaSelectDelegate(QObject *parent)
: QItemDelegate(parent)
{
}
//-----------------------------------------------------------------------------------------------------------------------------
// PUBLIC MEMBER FUNCTIONS
//-----------------------------------------------------------------------------------------------------------------------------
void SoundAreaSelectDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if (index.column() != SoundAreaSelectModel::Column::Stop)
{
QItemDelegate::paint(painter, option, index);
return;
} // if
QStyleOptionButton button;
button.rect = option.rect;
button.state = index.data().toBool() ? QStyle::State_Enabled : QStyle::State_ReadOnly;
button.iconSize = QSize(25, 25);
button.icon = QIcon(QStringLiteral("icon:avm_stop.svg"));
QApplication::style()->drawControl(QStyle::CE_PushButton, &button, painter);
}
//=============================================================================================================================
// SOUNDAREASELECTMODEL
//=============================================================================================================================
SoundAreaSelectModel::SoundAreaSelectModel(QWidget *parent)
: LtsWidgets::LtsAbstractTableModel<SoundArea>(
{
tr("ID"),
tr("Name"),
tr("Main EGCU"),
tr("Sound Area EGCUs"),
tr("Active Sounds"),
tr("Stop")
}, parent)
, m_logger(getLogger("Plugins.Gui.SoundArea.SelectModel"))
{
}
//-----------------------------------------------------------------------------------------------------------------------------
// PRIVATE SLOTS
//-----------------------------------------------------------------------------------------------------------------------------
bool SoundAreaSelectModel::onSoundStateChanged(const SoundManagement::SoundState &data, DataModification modType)
{
for (auto &soundArea : m_vecData) // search SoundAreas
{
if (soundArea.egcuIds.contains(data.egcuId())) // found SoundArea with corresponding EGCU
{
QHash<int32_t, SoundManagement::SoundState>::iterator it = soundArea.activeSounds.find(data.id());
switch (modType)
{
case DataModification::eAdded:
if (it != soundArea.activeSounds.end()) // prevent duplicates
{
DEBUG_LOG(m_logger) << "'" << m_helper->soundName(data.category(), data.soundId()) << "' is already active";
return false;
} // if
else
{
soundArea.activeSounds.insert(data.id(), data);
emit dataChanged(
SoundAreaSelectModel::index(0, Column::ActiveSounds),
SoundAreaSelectModel::index(m_vecData.size(), Column::ActiveSounds)
);
return true;
} // else
case DataModification::eRemoved:
if (it == soundArea.activeSounds.end()) // this should not happen
{
DEBUG_LOG(m_logger) << "'" << m_helper->soundName(data.category(), data.soundId()) << "' is not active";
return false;
} // if
else
{
soundArea.activeSounds.remove(it.key());
emit dataChanged(
SoundAreaSelectModel::index(0, Column::ActiveSounds),
SoundAreaSelectModel::index(m_vecData.size(), Column::ActiveSounds)
);
return true;
} // else
case DataModification::eModified:
default:
return false;
} // switch
} // if
} // for
return false;
}
//-----------------------------------------------------------------------------------------------------------------------------
// PUBLIC MEMBER FUNCTIONS
//-----------------------------------------------------------------------------------------------------------------------------
bool SoundAreaSelectModel::init(const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
const std::shared_ptr<SoundManagement::Interface::Dtc> &somDtc)
{
DEBUG_LOG(m_logger) << "init";
m_ismDtc = ismDtc;
m_somDtc = somDtc;
m_helper = std::make_shared<SoundAreaHelper>(new SoundAreaHelper(m_ismDtc, m_somDtc));
// SoundAreas
connect(m_ismDtc.get(), &InfrastructureManagement::Interface::Dtc::effectAreaChanged, this,
[this](const InfrastructureManagement::EffectArea &data, DataModification modType)
{
return onDataChanged(SoundArea(data), modType);
});
m_ismDtc->effectAreas([this](const InfrastructureManagement::EffectArea &effectArea)
{
insertRow(SoundArea(effectArea));
});
// active Sounds
connect(m_somDtc.get(), &SoundManagement::Interface::Dtc::soundStateChanged, this,
[this](const SoundManagement::SoundState &data, DataModification modType)
{
return onSoundStateChanged(data, modType);
});
m_somDtc->soundStates([this](const SoundManagement::SoundState &soundState)
{
onSoundStateChanged(soundState, DataModification::eAdded);
});
DEBUG_LOG(m_logger) << "init successful";
return true;
}
bool SoundAreaSelectModel::insertRow(const SoundArea &item)
{
beginInsertRows(QModelIndex(), m_vecData.size(), m_vecData.size());
m_vecData.push_back(item);
endInsertRows();
return true;
}
bool SoundAreaSelectModel::removeRow(int row)
{
removeRows(row, 1);
return true;
}
QVariant SoundAreaSelectModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if ( (role != Qt::DisplayRole) && (role != Qt::ToolTipRole) )
return QVariant{};
const SoundArea &soundArea = m_vecData.at(index.row());
std::string str = "";
switch (role)
{
case Qt::DisplayRole:
switch (index.column())
{
case Column::Id: return soundArea.id;
case Column::Name: return soundArea.displayName;
case Column::AreaEgcu: return m_helper->egcuName(soundArea.areaEgcuId);
case Column::Egcus:
for (const auto &egcu : soundArea.egcuIds)
str += m_helper->egcuName(egcu).toStdString() + ", ";
if (str.size() > 1)
str = str.substr(0, str.length() - 2); // remove ", "
return QString::fromStdString(str);
case Column::ActiveSounds:
if (soundArea.activeSounds.size() > 0)
{
SoundManagement::SoundState sound = soundArea.activeSounds.begin().value();
return m_helper->soundName(sound.category(), sound.soundId());
} // if
return QString();
case Column::Stop:
return soundArea.activeSounds.size() > 0;
default:
Q_UNREACHABLE();
return QVariant{};
} // switch
case Qt::ToolTipRole:
switch (index.column())
{
case Column::Id:
case Column::Name:
case Column::AreaEgcu:
return data(index, Qt::DisplayRole);
case Column::Egcus:
for (const auto &egcu : soundArea.egcuIds)
str += m_helper->egcuName(egcu).toStdString() + "\n";
if (str.size() > 1)
str = str.substr(0, str.length() - 1);
return QString::fromStdString(str);
case Column::ActiveSounds:
for (const auto &sound : soundArea.activeSounds)
str += m_helper->soundName(sound.category(), sound.soundId()).toStdString() + "\n";
if (str.size() > 1)
str = str.substr(0, str.length() - 1);
return QString::fromStdString(str);
case Column::Stop:
return QStringLiteral("Stop all Sounds");
default:
Q_UNREACHABLE();
return QVariant();
} // switch
default:
Q_UNREACHABLE();
return QVariant();
} // switch
}
//-----------------------------------------------------------------------------------------------------------------------------
// PROTECTED MEMBER FUNCTIONS
//-----------------------------------------------------------------------------------------------------------------------------
bool SoundAreaSelectModel::onDataChanged(const SoundArea &data, DataModification modType)
{
if (modType == DataModification::eAdded)
return insertRow(data);
int row = indexOf(data);
if (modType == DataModification::eRemoved)
return removeRow(row);
return setRowData(row, data);
}
//-----------------------------------------------------------------------------------------------------------------------------
// PRIVATE MEMBER FUNCTIONS
//-----------------------------------------------------------------------------------------------------------------------------
int SoundAreaSelectModel::indexOf(const SoundArea &data) const
{
return m_vecData.indexOf(data);
}
} // namespace EffectManagement
@@ -0,0 +1,112 @@
/**
* @RDE_HEADER@
* Model for the overall sound area table.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, NLE, 2020-07-29
*/
#pragma once
#include "efm_sound_area.h"
#include <LtsWidgets/lts_abstract_table_model.h>
#include <LtsUtilsGuiDds/request_helper.h>
#include <InfrastructureManagement/ism_dtc.h>
#include <SoundManagement/som_dtc.h>
#include <SoundManagement/som_ftc.h>
#include <QItemDelegate>
namespace NGL
{
class INGLLogger;
}
namespace EffectManagement
{
using SoundKey = QPair<int32_t, int32_t>;
class SoundAreaHelper;
class SoundAreaSelectDelegate
: public QItemDelegate
{
Q_OBJECT
public:
SoundAreaSelectDelegate(QObject *parent = nullptr);
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
}; // SoundAreaSelectDelegate
/**
* @brief The SoundAreasDialogModel class provides a model for an overview over all SoundAreas.
* @details It inherits LtsAbstractTableModel and has SoundArea (declared in efm_sound_area.h) as
* its template type. 7 columns will be displayed with the SoundArea ID, name, its main EGCU's ID, a
* list of all its EGCUs' IDs (including the main EGCU), a list of all active sounds, the remaining
* time until all sounds stop playing and the last column showing a stop button that lets the user
* stop all sound inside the SoundArea.
*/
class SoundAreaSelectModel final
: public LtsWidgets::LtsAbstractTableModel<SoundArea>
{
Q_OBJECT
public:
enum Column { Id, Name, AreaEgcu, Egcus, ActiveSounds, Stop };
explicit SoundAreaSelectModel(QWidget *parent = nullptr);
private slots:
/**
* @brief onSoundStateChanged updates all active sounds by catching the soundStateChanged signal
* from the Sound Management.
* @param soundState SoundState from Sound Management
* @param modType data modification type (eAdded, eModified or eRemoved)
* @return true for success, false otherwise
*/
bool onSoundStateChanged(const SoundManagement::SoundState &data, DataModification modType);
public:
bool init(const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
const std::shared_ptr<SoundManagement::Interface::Dtc> &somDtc);
QVector<SoundArea> soundAreas() const { return m_vecData; }
bool insertRow(const SoundArea &item) override;
bool removeRow(int row) override;
QVariant data(const QModelIndex &index, int role) const override;
protected:
bool onDataChanged(const SoundArea &data, DataModification modType) override;
private:
/**
* @brief indexOf returns the index of a given SoundArea.
* @param data the SoundArea
* @return index of the SoundArea
*/
int indexOf(const SoundArea &data) const;
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc{nullptr};
std::shared_ptr<SoundManagement::Interface::Dtc> m_somDtc{nullptr};
std::shared_ptr<SoundAreaHelper> m_helper{nullptr};
NGL::INGLLogger &m_logger;
}; // class SoundAreaSelectModel
} // namespace EffectManagement
@@ -0,0 +1,60 @@
/**
* @RDE_HEADER@
* SoundState class derivation for custom purposes.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, NLE, 2020-08-26
*/
#include "efm_sound_state.h"
namespace EffectManagement
{
//=============================================================================================================================
// SOUNDSTATE
//=============================================================================================================================
SoundState::SoundState(const SoundManagement::SoundState &soundState)
: SoundManagement::SoundState(soundState)
{
}
//-----------------------------------------------------------------------------------------------------------------------------
// PUBLIC MEMBER FUNCTIONS
//-----------------------------------------------------------------------------------------------------------------------------
void SoundState::status(Status stat)
{
m_status = stat;
}
void SoundState::duration(int secs)
{
if (secs > 0)
m_duration = std::max(0, secs);
}
void SoundState::timeLeft(int secs)
{
if (secs >= 0)
m_timeLeft = secs;
}
void SoundState::volume(int vol)
{
if (vol >= 0)
m_volume = vol;
}
QString SoundState::statusToString() const
{
if (m_status == Status::Active)
return QStringLiteral("Active");
return m_status == Status::Stop ? QStringLiteral("Stop") : QStringLiteral("Scheduled");
}
} // namespace EffectManagement
@@ -0,0 +1,52 @@
/**
* @RDE_HEADER@
* SoundState class derivation for custom purposes.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, NLE, 2020-08-10
*/
#pragma once
#include <SoundManagement/som.hpp>
#include <QString>
namespace EffectManagement
{
class SoundState
: public SoundManagement::SoundState
{
public:
enum Status { Active, Stop, Scheduled };
SoundState() = default;
explicit SoundState(const SoundManagement::SoundState &soundState);
public:
Status status() const { return m_status; }
int duration() const { return m_duration; }
int timeLeft() const { return m_timeLeft; }
int volume() const { return m_volume; }
void status(Status stat);
void duration(int secs);
void timeLeft(int secs);
void volume(int vol);
QString statusToString() const;
private:
Status m_status{Status::Scheduled};
int m_volume{100};
int m_duration{0};
int m_timeLeft{0};
}; // class SoundState
} // namespace EffectManagement
@@ -0,0 +1,37 @@
/**
* @RDE_HEADER@
* Item Delegate class to show On/Off switch buttons.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, NLE, 2020-08-10
*/
#include "efm_switch_item_delegate.h"
#include "../logger.h"
#include <QDebug>
namespace EffectManagement
{
const QIcon SwitchItemDelegate::s_iconOn = QIcon(QStringLiteral("icon:switch_on.svg"));
const QIcon SwitchItemDelegate::s_iconOff = QIcon(QStringLiteral("icon:switch_off.svg"));
SwitchItemDelegate::SwitchItemDelegate(QObject *parent)
: QStyledItemDelegate(parent)
, m_logger(getLogger("Plugins.Gui.SoundArea.SwitchItemDelegate"))
{
}
void SwitchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if (index.data().toInt() == 1)
s_iconOn.paint(painter, option.rect, Qt::AlignCenter);
else if (index.data().toInt() == -1)
s_iconOff.paint(painter, option.rect, Qt::AlignCenter);
}
} // namespace EffectManagement
@@ -0,0 +1,42 @@
/**
* @RDE_HEADER@
* Item Delegate class to show On/Off switch buttons.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, NLE, 2020-08-10
*/
#pragma once
#include <QStyledItemDelegate>
namespace NGL
{
class INGLLogger;
}
namespace EffectManagement
{
class SwitchItemDelegate
: public QStyledItemDelegate
{
Q_OBJECT
public:
SwitchItemDelegate(QObject *parent = nullptr);
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
private:
static const QIcon s_iconOn;
static const QIcon s_iconOff;
NGL::INGLLogger &m_logger;
}; // SwitchItemDelegate
} // namespace EffectManagement
@@ -0,0 +1,91 @@
/**
* @RDE_HEADER@
* Plugin to manage effects.
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, NLE, 2020-07-29
*/
#pragma once
#include "efm_effect_area.h"
#include "efm_sound_helper.h"
#include <LtsWidgets/lts_dialog.h>
#include <LtsUtilsGuiDds/request_helper.h>
#include <SoundManagement/som_dtc.h>
#include <SoundManagement/som_ftc.h>
namespace NGL
{
class INGLLogger;
}
namespace LtsSession
{
class LtsSessionDataDds;
}
namespace LtsUtils
{
class RequestHelper;
}
namespace Ui
{
class SoundManagementDialog;
}
namespace EffectManagement
{
class SoundTreeModel;
class SoundPlaylistModel;
class SoundManagementDialog
: public LtsWidgets::LtsDialog
, protected SoundManagement::Interface::Ftc::ControlSoundReplyHandler
{
Q_OBJECT
public:
explicit SoundManagementDialog(const EffectAreaData &data, QWidget *parent = nullptr);
~SoundManagementDialog();
private slots:
void onAddSoundToPlaylist(const SoundKey &key);
void onStopAllSounds();
public:
bool init(LtsSession::LtsSessionDataDds *session, const QString &menuGroup);
private:
void onControlSoundReply(const Core::FunctionReplyObject &replyObject) override final;
void retranslate() override;
bool apply() override;
std::shared_ptr<SoundManagement::Interface::Dtc> m_somDtc{nullptr};
std::shared_ptr<SoundManagement::Interface::Ftc> m_somFtc{nullptr};
std::shared_ptr<SoundManagementHelper> m_helper{nullptr};
LtsUtils::RequestHelper *m_requestHelper{nullptr};
LtsSession::LtsSessionDataDds *m_session{nullptr};
EffectAreaData *m_data{nullptr};
SoundTreeModel *m_treeModel{nullptr};
SoundPlaylistModel *m_playlistModel{nullptr};
QHash<int32_t, QCheckBox *> m_egcuCheckBoxes;
QString m_menuGroup;
Ui::SoundManagementDialog *m_ui{nullptr};
NGL::INGLLogger &m_logger;
}; // class EffectManagementDialog
} // namespace EffectManagement
+38
View File
@@ -0,0 +1,38 @@
/**
* @RDE_HEADER@
* Logging for EffectManagement Plugin
* $Id$
* $HeadURL$
* $Author$
*/
#include "logger.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
namespace EffectManagement
{
LOGGER_T getLogger(const char *name)
{
static const char ns[] = "EFM.";
std::string loggerName;
const size_t len = strlen(name);
loggerName.reserve(sizeof(ns) + len);
loggerName.append(ns, sizeof(ns) - 1);
loggerName.append(name, len);
try
{
return NGL::NGLLoggerBootstrap::getNGLRootLogger().
getNGLLogger(loggerName);
}
catch (const std::exception &ex)
{
fprintf(stderr, "Error retrieving logger: %s", ex.what());
abort();
}
}
} // namespace EffectManagement
+26
View File
@@ -0,0 +1,26 @@
/**
* @RDE_HEADER@
* Logging for EffectManagement Plugin
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <NGLLogger/INGLLogger.h>
namespace EffectManagement
{
using LOGGER_T = NGL::INGLLogger &;
LOGGER_T getLogger(const char *name);
inline LOGGER_T getLogger(const QString &loggerName)
{
return getLogger(loggerName.toUtf8().constData());
}
} // namespace EffectManagement
+52
View File
@@ -0,0 +1,52 @@
/**
* @RDE_HEADER@
* HMI Plugin for effect management (Interface for access from other Plugins)
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, SLSE, 2020-07-29
*/
#pragma once
#include <PluginInterfaces/data_plugin_interface.h>
#include <SoundManagement/som_dtc.h>
#include <SoundManagement/som_ftc.h>
namespace EffectManagement
{
/**
* @brief The DataInterface class provides the Topics Clients only for the GUI Plugins
*/
class DataInterface : public DataPluginBase::Interface
{
public:
using DataPluginBase::Interface::Interface;
virtual std::shared_ptr<SoundManagement::Interface::Dtc> getDtc() = 0;
virtual std::shared_ptr<SoundManagement::Interface::Ftc> getFtc() = 0;
};
} // namespace EffectManagement
//namespace SoundManagement
//{
///**
// * @brief The DataInterface class provides the Topics Clients only for the GUI Plugins
// */
//class DataInterface : public DataPluginBase::Interface
//{
//public:
// using DataPluginBase::Interface::Interface;
// virtual std::shared_ptr<SoundManagement::Interface::Dtc> getDtc() = 0;
// virtual std::shared_ptr<SoundManagement::Interface::Ftc> getFtc() = 0;
//};
//} // namespace SoundManagement
+24
View File
@@ -0,0 +1,24 @@
/**
* @RDE_HEADER@
* HMI Plugin for effect managemt (Interface for access from other Plugins)
* $Id$
* $HeadURL$
* $Author$
* Created by Filip Biedziak, NLE, 2020-07-29
*/
#pragma once
namespace EffectManagement
{
class ForeignGuiInterface
{
public:
ForeignGuiInterface() = default;
virtual ~ForeignGuiInterface() = default;
};
} // namespace ExerciseManagement