You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
872 lines
36 KiB
C++
872 lines
36 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
|
|
#include <ATLControlsPanel.h>
|
|
|
|
#include <AzCore/StringFunc/StringFunc.h>
|
|
#include <AzQtComponents/Components/Style.h>
|
|
|
|
#include <ACEEnums.h>
|
|
#include <ATLControlsModel.h>
|
|
#include <AudioControl.h>
|
|
#include <AudioControlsEditorPlugin.h>
|
|
#include <IAudioSystemControl.h>
|
|
#include <IAudioSystemEditor.h>
|
|
#include <QAudioControlEditorIcons.h>
|
|
|
|
#include <QWidgetAction>
|
|
#include <QPushButton>
|
|
#include <QPaintEvent>
|
|
#include <QPainter>
|
|
#include <QMessageBox>
|
|
#include <QMimeData>
|
|
#include <QStandardItemModel>
|
|
#include <QStandardItem>
|
|
#include <QKeyEvent>
|
|
#include <QSortFilterProxyModel>
|
|
#include <QModelIndex>
|
|
#include <QCoreApplication>
|
|
#include <QWidgetAction>
|
|
#include <QIcon>
|
|
|
|
namespace AudioControls
|
|
{
|
|
//-------------------------------------------------------------------------------------------//
|
|
|
|
QFilterButton::QFilterButton(const QIcon& icon, [[maybe_unused]] const QString& text, QWidget* parent)
|
|
: QWidget(parent)
|
|
{
|
|
QHBoxLayout* mainLayout = new QHBoxLayout(this);
|
|
mainLayout->setSpacing(0);
|
|
mainLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
// Add the sub widgets to a parent so that the correct area is highlighted on mouseover.
|
|
m_background = new QWidget(this);
|
|
m_background->show();
|
|
|
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
|
|
const QMargins margin = QMargins(5, 2, 5, 2);
|
|
// Add class to fix hover state styling for WidgetAction
|
|
AzQtComponents::Style::addClass(this, "WidgetAction");
|
|
|
|
QHBoxLayout* layout = new QHBoxLayout(m_background);
|
|
layout->setSpacing(1);
|
|
QIcon* checkMarkI = new QIcon(":/stylesheet/img/UI20/checkmark-menu.svg");
|
|
m_checkIcon.setPixmap(checkMarkI->pixmap(16));
|
|
QSizePolicy sp = m_checkIcon.sizePolicy();
|
|
sp.setRetainSizeWhenHidden(true);
|
|
m_checkIcon.setSizePolicy(sp);
|
|
layout->addWidget(&m_checkIcon);
|
|
m_filterIcon.setPixmap(icon.pixmap(16, 16));
|
|
layout->addWidget(&m_filterIcon);
|
|
layout->addWidget(&m_actionText);
|
|
layout->addStretch();
|
|
layout->setContentsMargins(margin);
|
|
m_background->setLayout(layout);
|
|
mainLayout->addWidget(m_background);
|
|
|
|
setLayout(mainLayout);
|
|
}
|
|
|
|
void QFilterButton::mousePressEvent(QMouseEvent* event)
|
|
{
|
|
QWidget::mousePressEvent(event);
|
|
SetChecked(!m_checked);
|
|
emit clicked(m_checked);
|
|
}
|
|
|
|
void QFilterButton::enterEvent(QEvent* /*event*/)
|
|
{
|
|
setStyleSheet("background-color: #444444;");
|
|
}
|
|
|
|
void QFilterButton::leaveEvent(QEvent* /*event*/)
|
|
{
|
|
setStyleSheet("background-color: transparent;");
|
|
}
|
|
|
|
void QFilterButton::SetChecked(bool checked)
|
|
{
|
|
m_checked = checked;
|
|
m_checkIcon.setVisible(checked);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
CATLControlsPanel::CATLControlsPanel(CATLControlsModel* pATLModel, QATLTreeModel* pATLControlsModel)
|
|
: m_pATLModel(pATLModel)
|
|
, m_pTreeModel(pATLControlsModel)
|
|
, m_showUnassignedControls(false)
|
|
{
|
|
setupUi(this);
|
|
|
|
m_pATLControlsTree->installEventFilter(this);
|
|
m_pATLControlsTree->viewport()->installEventFilter(this);
|
|
|
|
// ************ Context Menu ************
|
|
m_addItemMenu.addAction(GetControlTypeIcon(eACET_TRIGGER), tr("Trigger"), this, SLOT(CreateTriggerControl()));
|
|
m_addItemMenu.addAction(GetControlTypeIcon(eACET_RTPC), tr("RTPC"), this, SLOT(CreateRTPCControl()));
|
|
m_addItemMenu.addAction(GetControlTypeIcon(eACET_SWITCH), tr("Switch"), this, SLOT(CreateSwitchControl()));
|
|
m_addItemMenu.addAction(GetControlTypeIcon(eACET_ENVIRONMENT), tr("Environment"), this, SLOT(CreateEnvironmentsControl()));
|
|
m_addItemMenu.addAction(GetControlTypeIcon(eACET_PRELOAD), tr("Preload"), this, SLOT(CreatePreloadControl()));
|
|
m_addItemMenu.addSeparator();
|
|
m_addItemMenu.addAction(GetFolderIcon(), tr("Folder"), this, SLOT(CreateFolder()));
|
|
m_pAddButton->setMenu(&m_addItemMenu);
|
|
m_pATLControlsTree->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
connect(m_pATLControlsTree, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(ShowControlsContextMenu(const QPoint&)));
|
|
// *********************************
|
|
|
|
// ************ Filtering ************
|
|
for (int i = 0; i < eACET_NUM_TYPES; ++i)
|
|
{
|
|
EACEControlType type = ( EACEControlType )i;
|
|
QWidgetAction* pWidgetAction = new QWidgetAction(this);
|
|
|
|
m_pControlTypeFilterButtons[type] = new QFilterButton(GetControlTypeIcon(type), "", this);
|
|
m_pControlTypeFilterButtons[type]->SetChecked(true);
|
|
if (type != eACET_SWITCH_STATE)
|
|
{
|
|
pWidgetAction->setDefaultWidget(m_pControlTypeFilterButtons[type]);
|
|
m_filterMenu.addAction(pWidgetAction);
|
|
}
|
|
}
|
|
|
|
QWidgetAction* pWidgetAction = new QWidgetAction(this);
|
|
|
|
m_unassignedFilterButton = new QFilterButton(QIcon(":/Icons/Unassigned.svg"), "", this);
|
|
m_unassignedFilterButton->SetText("Unassigned");
|
|
m_unassignedFilterButton->SetChecked(m_showUnassignedControls);
|
|
pWidgetAction->setDefaultWidget(m_unassignedFilterButton);
|
|
m_filterMenu.addAction(pWidgetAction);
|
|
|
|
m_pFiltersButton->setMenu(&m_filterMenu);
|
|
m_pControlTypeFilterButtons[eACET_TRIGGER]->SetText("Triggers");
|
|
m_pControlTypeFilterButtons[eACET_RTPC]->SetText("RTPCs");
|
|
m_pControlTypeFilterButtons[eACET_SWITCH]->SetText("Switches");
|
|
m_pControlTypeFilterButtons[eACET_SWITCH_STATE]->hide();
|
|
m_pControlTypeFilterButtons[eACET_ENVIRONMENT]->SetText("Environments");
|
|
m_pControlTypeFilterButtons[eACET_PRELOAD]->SetText("Preloads");
|
|
connect(m_pControlTypeFilterButtons[eACET_TRIGGER], SIGNAL(clicked(bool)), this, SLOT(ShowTriggers(bool)));
|
|
connect(m_pControlTypeFilterButtons[eACET_RTPC], SIGNAL(clicked(bool)), this, SLOT(ShowRTPCs(bool)));
|
|
connect(m_pControlTypeFilterButtons[eACET_SWITCH], SIGNAL(clicked(bool)), this, SLOT(ShowSwitches(bool)));
|
|
connect(m_pControlTypeFilterButtons[eACET_ENVIRONMENT], SIGNAL(clicked(bool)), this, SLOT(ShowEnvironments(bool)));
|
|
connect(m_pControlTypeFilterButtons[eACET_PRELOAD], SIGNAL(clicked(bool)), this, SLOT(ShowPreloads(bool)));
|
|
connect(m_unassignedFilterButton, SIGNAL(clicked(bool)), this, SLOT(ShowUnassigned(bool)));
|
|
connect(m_pTextFilter, SIGNAL(textChanged(QString)), this, SLOT(SetFilterString(QString)));
|
|
// *********************************
|
|
|
|
m_pATLModel->AddListener(this);
|
|
|
|
// Load data into tree control
|
|
QAudioControlSortProxy* pProxyModel = new QAudioControlSortProxy(this);
|
|
pProxyModel->setSourceModel(m_pTreeModel);
|
|
m_pATLControlsTree->setModel(pProxyModel);
|
|
m_pProxyModel = pProxyModel;
|
|
|
|
connect(m_pATLControlsTree->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SIGNAL(SelectedControlChanged()));
|
|
connect(m_pATLControlsTree->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(StopControlExecution()));
|
|
connect(m_pTreeModel, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(ItemModified(QStandardItem*)));
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::ApplyFilter()
|
|
{
|
|
QModelIndex index = m_pProxyModel->index(0, 0);
|
|
for (int i = 0; index.isValid(); ++i)
|
|
{
|
|
ApplyFilter(index);
|
|
index = index.sibling(i, 0);
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::SetFilterString(const QString& sFilterText)
|
|
{
|
|
m_sFilter = sFilterText;
|
|
ApplyFilter();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
bool CATLControlsPanel::ApplyFilter(const QModelIndex parent)
|
|
{
|
|
if (parent.isValid())
|
|
{
|
|
bool bIsValid = false;
|
|
bool bHasChildren = false;
|
|
QModelIndex child = parent.model()->index(0, 0, parent);
|
|
for (int i = 1; child.isValid(); ++i)
|
|
{
|
|
bHasChildren = true;
|
|
if (ApplyFilter(child))
|
|
{
|
|
bIsValid = true;
|
|
}
|
|
child = parent.model()->index(i, 0, parent);
|
|
}
|
|
|
|
if (!bIsValid && IsValid(parent))
|
|
{
|
|
if (!bHasChildren || parent.data(eDR_TYPE) != eIT_FOLDER)
|
|
{
|
|
// we want to hide empty folders, but show controls (ie. switches) even
|
|
// if their children are hidden
|
|
bIsValid = true;
|
|
}
|
|
}
|
|
|
|
m_pATLControlsTree->setRowHidden(parent.row(), parent.parent(), !bIsValid);
|
|
return bIsValid;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
bool CATLControlsPanel::IsValid(const QModelIndex index)
|
|
{
|
|
const QString sName = index.data(Qt::DisplayRole).toString();
|
|
if (m_sFilter.isEmpty() || sName.contains(m_sFilter, Qt::CaseInsensitive))
|
|
{
|
|
if (index.data(eDR_TYPE) == eIT_AUDIO_CONTROL)
|
|
{
|
|
const CATLControl* pControl = m_pATLModel->GetControlByID(index.data(eDR_ID).toUInt());
|
|
if (pControl)
|
|
{
|
|
// This treats switches and switchstates the same so the ATL controls panel filters work.
|
|
EACEControlType eType = pControl->GetType();
|
|
if (eType == eACET_SWITCH_STATE)
|
|
{
|
|
eType = eACET_SWITCH;
|
|
}
|
|
|
|
if (m_visibleTypes[eType])
|
|
{
|
|
if (m_showUnassignedControls)
|
|
{
|
|
return !pControl->IsFullyConnected();
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
CATLControlsPanel::~CATLControlsPanel()
|
|
{
|
|
StopControlExecution();
|
|
m_pATLModel->RemoveListener(this);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
bool CATLControlsPanel::eventFilter(QObject* pObject, QEvent* pEvent)
|
|
{
|
|
if (pEvent->type() == QEvent::KeyRelease)
|
|
{
|
|
QKeyEvent* pKeyEvent = static_cast<QKeyEvent*>(pEvent);
|
|
if (pKeyEvent && !m_pATLControlsTree->IsEditing())
|
|
{
|
|
if (pKeyEvent->key() == Qt::Key_Delete)
|
|
{
|
|
DeleteSelectedControl();
|
|
}
|
|
else if (pKeyEvent->key() == Qt::Key_Space)
|
|
{
|
|
ExecuteControl();
|
|
}
|
|
else if (pKeyEvent->key() == Qt::Key_Escape)
|
|
{
|
|
DeselectAll();
|
|
}
|
|
}
|
|
}
|
|
else if (pEvent->type() == QEvent::MouseButtonRelease)
|
|
{
|
|
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(pEvent);
|
|
if (mouseEvent && mouseEvent->button() == Qt::LeftButton)
|
|
{
|
|
QModelIndex index = m_pATLControlsTree->indexAt(mouseEvent->pos());
|
|
if (!index.isValid())
|
|
{
|
|
DeselectAll();
|
|
}
|
|
}
|
|
}
|
|
else if (pEvent->type() == QEvent::Drop)
|
|
{
|
|
QDropEvent* pDropEvent = static_cast<QDropEvent*>(pEvent);
|
|
if (pDropEvent)
|
|
{
|
|
if (pDropEvent->source() != m_pATLControlsTree)
|
|
{
|
|
// External Drop
|
|
HandleExternalDropEvent(pDropEvent);
|
|
pDropEvent->accept();
|
|
}
|
|
}
|
|
}
|
|
return QWidget::eventFilter(pObject, pEvent);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
ControlList CATLControlsPanel::GetSelectedControls()
|
|
{
|
|
ControlList controls;
|
|
QModelIndexList indexes = m_pATLControlsTree->selectionModel()->selectedIndexes();
|
|
const int size = indexes.size();
|
|
for (int i = 0; i < size; ++i)
|
|
{
|
|
if (indexes[i].isValid())
|
|
{
|
|
CID nID = indexes[i].data(eDR_ID).toUInt();
|
|
if (nID != ACE_INVALID_CID)
|
|
{
|
|
controls.push_back(nID);
|
|
}
|
|
}
|
|
}
|
|
return controls;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::Reload()
|
|
{
|
|
ResetFilters();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::ShowControlType(EACEControlType type, bool bShow, bool bExclusive)
|
|
{
|
|
if (bExclusive)
|
|
{
|
|
for (int i = 0; i < eACET_NUM_TYPES; ++i)
|
|
{
|
|
EACEControlType controlType = (EACEControlType)i;
|
|
m_visibleTypes[controlType] = !bShow;
|
|
ControlTypeFiltered(controlType, !bShow);
|
|
m_pControlTypeFilterButtons[controlType]->SetChecked(!bShow);
|
|
}
|
|
}
|
|
m_visibleTypes[type] = bShow;
|
|
ControlTypeFiltered(type, bShow);
|
|
m_pControlTypeFilterButtons[type]->SetChecked(bShow);
|
|
ApplyFilter();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::ShowTriggers(bool bShow)
|
|
{
|
|
ShowControlType(eACET_TRIGGER, bShow, QGuiApplication::keyboardModifiers() & Qt::ControlModifier);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::ShowRTPCs(bool bShow)
|
|
{
|
|
ShowControlType(eACET_RTPC, bShow, QGuiApplication::keyboardModifiers() & Qt::ControlModifier);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::ShowEnvironments(bool bShow)
|
|
{
|
|
ShowControlType(eACET_ENVIRONMENT, bShow, QGuiApplication::keyboardModifiers() & Qt::ControlModifier);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::ShowSwitches(bool bShow)
|
|
{
|
|
ShowControlType(eACET_SWITCH, bShow, QGuiApplication::keyboardModifiers() & Qt::ControlModifier);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::ShowPreloads(bool bShow)
|
|
{
|
|
ShowControlType(eACET_PRELOAD, bShow, QGuiApplication::keyboardModifiers() & Qt::ControlModifier);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::ShowUnassigned(bool bShow)
|
|
{
|
|
m_showUnassignedControls = bShow;
|
|
ApplyFilter();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::CreateRTPCControl()
|
|
{
|
|
CATLControl* pControl = m_pTreeModel->CreateControl(eACET_RTPC, "rtpc");
|
|
if (pControl)
|
|
{
|
|
SelectItem(AddControl(pControl));
|
|
m_pATLControlsTree->setFocus();
|
|
m_pATLControlsTree->edit(m_pATLControlsTree->currentIndex());
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::CreateSwitchControl()
|
|
{
|
|
CATLControl* pControl = m_pTreeModel->CreateControl(eACET_SWITCH, "switch");
|
|
if (pControl)
|
|
{
|
|
SelectItem(AddControl(pControl));
|
|
m_pATLControlsTree->setFocus();
|
|
m_pATLControlsTree->edit(m_pATLControlsTree->currentIndex());
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::CreateStateControl()
|
|
{
|
|
QStandardItem* pSelectedItem = GetCurrentItem();
|
|
if (pSelectedItem && IsValidParent(pSelectedItem, eACET_SWITCH_STATE))
|
|
{
|
|
CATLControl* pControl = m_pTreeModel->CreateControl(eACET_SWITCH_STATE, "state", GetControlFromItem(pSelectedItem));
|
|
if (pControl)
|
|
{
|
|
SelectItem(AddControl(pControl));
|
|
m_pATLControlsTree->setFocus();
|
|
m_pATLControlsTree->edit(m_pATLControlsTree->currentIndex());
|
|
}
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::CreateTriggerControl()
|
|
{
|
|
CATLControl* pControl = m_pTreeModel->CreateControl(eACET_TRIGGER, "trigger");
|
|
if (pControl)
|
|
{
|
|
SelectItem(AddControl(pControl));
|
|
m_pATLControlsTree->setFocus();
|
|
m_pATLControlsTree->edit(m_pATLControlsTree->currentIndex());
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::CreateEnvironmentsControl()
|
|
{
|
|
CATLControl* pControl = m_pTreeModel->CreateControl(eACET_ENVIRONMENT, "environment");
|
|
if (pControl)
|
|
{
|
|
SelectItem(AddControl(pControl));
|
|
m_pATLControlsTree->setFocus();
|
|
m_pATLControlsTree->edit(m_pATLControlsTree->currentIndex());
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::CreatePreloadControl()
|
|
{
|
|
CATLControl* pControl = m_pTreeModel->CreateControl(eACET_PRELOAD, "preload");
|
|
if (pControl)
|
|
{
|
|
SelectItem(AddControl(pControl));
|
|
m_pATLControlsTree->setFocus();
|
|
m_pATLControlsTree->edit(m_pATLControlsTree->currentIndex());
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
QStandardItem* CATLControlsPanel::CreateFolder()
|
|
{
|
|
QModelIndex parent = m_pATLControlsTree->currentIndex();
|
|
while (parent.isValid() && (parent.data(eDR_TYPE) != eIT_FOLDER))
|
|
{
|
|
parent = parent.parent();
|
|
}
|
|
|
|
QStandardItem* pParentItem = nullptr;
|
|
QModelIndexList indexes = m_pATLControlsTree->selectionModel()->selectedIndexes();
|
|
|
|
if (parent.isValid() && indexes.size() > 0)
|
|
{
|
|
pParentItem = m_pTreeModel->itemFromIndex(m_pProxyModel->mapToSource(parent));
|
|
if (parent.isValid() && m_pATLControlsTree->isRowHidden(parent.row(), parent.parent()))
|
|
{
|
|
ResetFilters();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pParentItem = m_pTreeModel->invisibleRootItem();
|
|
}
|
|
|
|
QStandardItem* pFolder = m_pTreeModel->CreateFolder(pParentItem, "new_folder");
|
|
SelectItem(pFolder);
|
|
m_pATLControlsTree->setFocus();
|
|
m_pATLControlsTree->edit(m_pATLControlsTree->currentIndex());
|
|
return pFolder;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
bool CATLControlsPanel::IsValidParent(QStandardItem* pParent, const EACEControlType eControlType)
|
|
{
|
|
if (pParent->data(eDR_TYPE) == eIT_FOLDER)
|
|
{
|
|
return eControlType != eACET_SWITCH_STATE;
|
|
}
|
|
else if (eControlType == eACET_SWITCH_STATE)
|
|
{
|
|
CATLControl* pControl = GetControlFromItem(pParent);
|
|
if (pControl)
|
|
{
|
|
return pControl->GetType() == eACET_SWITCH;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
QStandardItem* CATLControlsPanel::AddControl(CATLControl* pControl)
|
|
{
|
|
if (pControl)
|
|
{
|
|
// Find a suitable parent for the new control starting from the one currently selected
|
|
QStandardItem* pParent = GetCurrentItem();
|
|
if (pParent)
|
|
{
|
|
while (pParent && !IsValidParent(pParent, pControl->GetType()))
|
|
{
|
|
pParent = pParent->parent();
|
|
}
|
|
}
|
|
|
|
if (!pParent)
|
|
{
|
|
AZ_Assert(pControl->GetType() != eACET_SWITCH_STATE, "AddControl - SwitchState control being added needs to be placed under a suitable parent (Switch)");
|
|
pParent = CreateFolder();
|
|
}
|
|
|
|
return m_pTreeModel->AddControl(pControl, pParent);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::ShowControlsContextMenu(const QPoint& pos)
|
|
{
|
|
QMenu contextMenu(tr("Context menu"), this);
|
|
QMenu addMenu(tr("Add"));
|
|
|
|
CATLControl* pControl = GetControlFromIndex(m_pATLControlsTree->currentIndex());
|
|
if (pControl)
|
|
{
|
|
switch (pControl->GetType())
|
|
{
|
|
case eACET_TRIGGER:
|
|
contextMenu.addAction(tr("Execute Trigger"), this, SLOT(ExecuteControl()));
|
|
contextMenu.addSeparator();
|
|
break;
|
|
case eACET_SWITCH:
|
|
case eACET_SWITCH_STATE:
|
|
addMenu.addAction(GetControlTypeIcon(eACET_SWITCH_STATE), tr("State"), this, SLOT(CreateStateControl()));
|
|
addMenu.addSeparator();
|
|
break;
|
|
}
|
|
}
|
|
|
|
addMenu.addAction(GetControlTypeIcon(eACET_TRIGGER), tr("Trigger"), this, SLOT(CreateTriggerControl()));
|
|
addMenu.addAction(GetControlTypeIcon(eACET_RTPC), tr("RTPC"), this, SLOT(CreateRTPCControl()));
|
|
addMenu.addAction(GetControlTypeIcon(eACET_SWITCH), tr("Switch"), this, SLOT(CreateSwitchControl()));
|
|
addMenu.addAction(GetControlTypeIcon(eACET_ENVIRONMENT), tr("Environment"), this, SLOT(CreateEnvironmentsControl()));
|
|
addMenu.addAction(GetControlTypeIcon(eACET_PRELOAD), tr("Preload"), this, SLOT(CreatePreloadControl()));
|
|
addMenu.addSeparator();
|
|
addMenu.addAction(GetFolderIcon(), tr("Folder"), this, SLOT(CreateFolder()));
|
|
contextMenu.addMenu(&addMenu);
|
|
|
|
QAction* pAction = new QAction(tr("Rename"), this);
|
|
connect(pAction, &QAction::triggered, m_pATLControlsTree,
|
|
[&]()
|
|
{
|
|
m_pATLControlsTree->edit(m_pATLControlsTree->currentIndex());
|
|
}
|
|
);
|
|
contextMenu.addAction(pAction);
|
|
|
|
pAction = new QAction(tr("Delete"), this);
|
|
connect(pAction, SIGNAL(triggered()), this, SLOT(DeleteSelectedControl()));
|
|
contextMenu.addAction(pAction);
|
|
|
|
contextMenu.addSeparator();
|
|
pAction = new QAction(tr("Expand All"), this);
|
|
connect(pAction, SIGNAL(triggered()), m_pATLControlsTree, SLOT(expandAll()));
|
|
contextMenu.addAction(pAction);
|
|
pAction = new QAction(tr("Collapse All"), this);
|
|
connect(pAction, SIGNAL(triggered()), m_pATLControlsTree, SLOT(collapseAll()));
|
|
contextMenu.addAction(pAction);
|
|
|
|
contextMenu.exec(m_pATLControlsTree->mapToGlobal(pos));
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::DeleteSelectedControl()
|
|
{
|
|
QMessageBox messageBox(this);
|
|
QModelIndexList indexList = m_pATLControlsTree->selectionModel()->selectedIndexes();
|
|
const int size = indexList.length();
|
|
if (size > 0)
|
|
{
|
|
if (size == 1)
|
|
{
|
|
QModelIndex index = m_pProxyModel->mapToSource(indexList[0]);
|
|
QStandardItem* pItem = m_pTreeModel->itemFromIndex(index);
|
|
if (pItem)
|
|
{
|
|
messageBox.setText("Are you sure you want to delete \"" + pItem->text() + "\"?");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
messageBox.setText("Are you sure you want to delete the selected controls and folders?");
|
|
}
|
|
messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
|
messageBox.setDefaultButton(QMessageBox::Yes);
|
|
messageBox.setWindowTitle("Audio Controls Editor");
|
|
if (messageBox.exec() == QMessageBox::Yes)
|
|
{
|
|
CUndo undo("Audio Control Removed");
|
|
|
|
QModelIndexList sourceIndexList;
|
|
for (int i = 0; i < size; ++i)
|
|
{
|
|
sourceIndexList.push_back(m_pProxyModel->mapToSource(indexList[i]));
|
|
}
|
|
m_pTreeModel->RemoveItems(sourceIndexList);
|
|
}
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::OnControlAdded(CATLControl* pControl)
|
|
{
|
|
// Remove filters if the control added is hidden
|
|
EACEControlType controlType = pControl->GetType();
|
|
if (!m_visibleTypes[controlType])
|
|
{
|
|
m_visibleTypes[controlType] = true;
|
|
m_pControlTypeFilterButtons[controlType]->SetChecked(true);
|
|
}
|
|
m_pTextFilter->setText("");
|
|
ApplyFilter();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::ExecuteControl()
|
|
{
|
|
const CATLControl* const pControl = GetControlFromIndex(m_pATLControlsTree->currentIndex());
|
|
if (pControl)
|
|
{
|
|
CAudioControlsEditorPlugin::ExecuteTrigger(pControl->GetName());
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::StopControlExecution()
|
|
{
|
|
CAudioControlsEditorPlugin::StopTriggerExecution();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
CATLControl* CATLControlsPanel::GetControlFromItem(QStandardItem* pItem)
|
|
{
|
|
if (pItem && (pItem->data(eDR_TYPE) == eIT_AUDIO_CONTROL))
|
|
{
|
|
return m_pATLModel->GetControlByID(pItem->data(eDR_ID).toUInt());
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
CATLControl* CATLControlsPanel::GetControlFromIndex(QModelIndex index)
|
|
{
|
|
if (index.isValid() && (index.data(eDR_TYPE) == eIT_AUDIO_CONTROL))
|
|
{
|
|
return m_pATLModel->GetControlByID(index.data(eDR_ID).toUInt());
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::SelectItem(QStandardItem* pItem)
|
|
{
|
|
// Expand and scroll to the new item
|
|
if (pItem)
|
|
{
|
|
QModelIndex index = m_pTreeModel->indexFromItem(pItem);
|
|
if (index.isValid())
|
|
{
|
|
m_pATLControlsTree->selectionModel()->setCurrentIndex(m_pProxyModel->mapFromSource(index), QItemSelectionModel::ClearAndSelect);
|
|
}
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::DeselectAll()
|
|
{
|
|
m_pATLControlsTree->selectionModel()->clear();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::HandleExternalDropEvent(QDropEvent* pDropEvent)
|
|
{
|
|
AudioControls::IAudioSystemEditor* pAudioSystemEditorImpl = CAudioControlsEditorPlugin::GetAudioSystemEditorImpl();
|
|
if (pAudioSystemEditorImpl)
|
|
{
|
|
const QMimeData* pData = pDropEvent->mimeData();
|
|
const QString format = "application/x-qabstractitemmodeldatalist";
|
|
if (pData->hasFormat(format))
|
|
{
|
|
QByteArray encoded = pData->data(format);
|
|
QDataStream stream(&encoded, QIODevice::ReadOnly);
|
|
while (!stream.atEnd())
|
|
{
|
|
int row, col;
|
|
QMap<int, QVariant> roleDataMap;
|
|
stream >> row >> col >> roleDataMap;
|
|
if (!roleDataMap.isEmpty())
|
|
{
|
|
// Dropped item mime data
|
|
IAudioSystemControl* pAudioSystemControl = pAudioSystemEditorImpl->GetControl(roleDataMap[eMDR_ID].toUInt());
|
|
if (pAudioSystemControl)
|
|
{
|
|
const EACEControlType eControlType = pAudioSystemEditorImpl->ImplTypeToATLType(pAudioSystemControl->GetType());
|
|
|
|
// If dropped outside any folder, create a folder at the root to contain the new control
|
|
const QModelIndex index = m_pProxyModel->mapToSource(m_pATLControlsTree->indexAt(pDropEvent->pos()));
|
|
QStandardItem* pTargetItem = m_pTreeModel->itemFromIndex(index);
|
|
if (!pTargetItem)
|
|
{
|
|
pTargetItem = m_pTreeModel->CreateFolder(m_pTreeModel->invisibleRootItem(), "new_folder");
|
|
}
|
|
|
|
// Find a suitable parent for the dropped control
|
|
CATLControl* pATLParent = nullptr;
|
|
CATLControl* pTargetControl = GetControlFromItem(pTargetItem);
|
|
if (pTargetControl && pTargetControl->GetType() == eControlType)
|
|
{
|
|
// If dropped in a control of the same type, we can assume the parent is valid, so we select it
|
|
pTargetItem = pTargetItem->parent();
|
|
pATLParent = GetControlFromItem(pTargetItem);
|
|
}
|
|
else
|
|
{
|
|
// If the dragged control has a parent, need to find a suitable parent on the ATL side first
|
|
const IAudioSystemControl* pAudioControlParent = pAudioSystemControl->GetParent();
|
|
if (pAudioControlParent && pAudioControlParent->GetType() != AUDIO_IMPL_INVALID_TYPE)
|
|
{
|
|
// Is the place where item was dropped compatible with the parent we are looking for
|
|
if (IsValidParent(pTargetItem, eControlType))
|
|
{
|
|
pATLParent = GetControlFromItem(pTargetItem);
|
|
}
|
|
else
|
|
{
|
|
// If place where item was dropped is not valid as a parent, we have to look for a valid control where to create one that is
|
|
const EACEControlType eParentType = pAudioSystemEditorImpl->ImplTypeToATLType(pAudioControlParent->GetType());
|
|
QStandardItem* pParent = pTargetItem;
|
|
while (pParent && !IsValidParent(pParent, eParentType))
|
|
{
|
|
pParent = pParent->parent();
|
|
}
|
|
|
|
if (pParent)
|
|
{
|
|
pATLParent = m_pTreeModel->CreateControl(eParentType, pAudioControlParent->GetName());
|
|
pTargetItem = m_pTreeModel->AddControl(pATLParent, pParent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pTargetItem)
|
|
{
|
|
while (pTargetItem && !IsValidParent(pTargetItem, eControlType))
|
|
{
|
|
pTargetItem = pTargetItem->parent();
|
|
}
|
|
|
|
// Create the new control and connect it to the one dragged in externally
|
|
AZStd::string sControlName(roleDataMap[Qt::DisplayRole].toString().toUtf8().data());
|
|
if (eControlType == eACET_PRELOAD)
|
|
{
|
|
AZ::StringFunc::Path::StripExtension(sControlName);
|
|
}
|
|
CATLControl* pTargetControl2 = m_pTreeModel->CreateControl(eControlType, sControlName, pATLParent);
|
|
if (pTargetControl2)
|
|
{
|
|
TConnectionPtr pAudioConnection = pAudioSystemEditorImpl->CreateConnectionToControl(pTargetControl2->GetType(), pAudioSystemControl);
|
|
if (pAudioConnection)
|
|
{
|
|
pTargetControl2->AddConnection(pAudioConnection);
|
|
}
|
|
|
|
pTargetItem = m_pTreeModel->AddControl(pTargetControl2, pTargetItem);
|
|
SelectItem(pTargetItem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
QStandardItem* CATLControlsPanel::GetCurrentItem()
|
|
{
|
|
return m_pTreeModel->itemFromIndex(m_pProxyModel->mapToSource(m_pATLControlsTree->currentIndex()));
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::ResetFilters()
|
|
{
|
|
// Remove filters
|
|
for (int i = 0; i < eACET_NUM_TYPES; ++i)
|
|
{
|
|
EACEControlType controlType = (EACEControlType)i;
|
|
m_visibleTypes[controlType] = true;
|
|
m_pControlTypeFilterButtons[controlType]->SetChecked(true);
|
|
}
|
|
m_pTextFilter->setText("");
|
|
ApplyFilter();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------//
|
|
void CATLControlsPanel::ItemModified(QStandardItem* pItem)
|
|
{
|
|
if (pItem)
|
|
{
|
|
AZStd::string sName(pItem->text().toUtf8().data());
|
|
if (pItem->data(eDR_TYPE) == eIT_AUDIO_CONTROL)
|
|
{
|
|
CATLControl* pControl = m_pATLModel->GetControlByID(pItem->data(eDR_ID).toUInt());
|
|
if (pControl)
|
|
{
|
|
if (pControl->GetName().compare(pItem->text().toUtf8().data()) != 0)
|
|
{
|
|
sName = m_pATLModel->GenerateUniqueName(sName, pControl->GetType(), pControl->GetScope(), pControl->GetParent());
|
|
pControl->SetName(sName);
|
|
}
|
|
}
|
|
m_pTreeModel->blockSignals(true);
|
|
pItem->setText(QString(sName.c_str()));
|
|
m_pTreeModel->blockSignals(false);
|
|
}
|
|
m_pTreeModel->SetItemAsDirty(pItem);
|
|
}
|
|
}
|
|
} // namespace AudioControls
|
|
|
|
#include <Source/Editor/moc_ATLControlsPanel.cpp>
|