Files
2026-08-13 18:33:10 +02:00

244 lines
6.7 KiB
C++
Executable File

/**
* @RDE_HEADER@
* RtState
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Fröbel, NLE, 2018-12-16
*/
#include "rt_state.h"
#include <QString>
#include <QtGlobal>
#include <utility>
#include <algorithm>
#include <sstream>
#include <QDebug>
namespace AudioVideoManagement
{
namespace
{
int toIndex(AvaRtPos p)
{
return p - AvaRtPos::min();
}
} // anonymous namespace
RtState::Key RtState::Key::createFrom(const RtState::RadioCircuit &radioCircuit)
{
return {radioCircuit.radioSystem, radioCircuit.id};
}
bool RtState::Key::operator==(const RtState::Key &other) const
{
return std::make_pair(radioSystem, id) == std::make_pair(other.radioSystem, other.id);
}
bool RtState::Key::operator<(const Key &other) const
{
return std::make_pair(radioSystem, id) < std::make_pair(other.radioSystem, other.id);
}
void RtState::setRadioCircuits(const QVector<RadioCircuit> &radioCircuits)
{
std::map<Key, CircuitState> newCircuits;
for (const auto &radioCircuit: radioCircuits)
{
Q_ASSERT(!radioCircuit.name.empty());
// If we know the new radio circuit already, we keep the CircuitState.
const Key key = Key::createFrom(radioCircuit);
CircuitState state{radioCircuit.name}; // default
auto found = m_radioCircuits.find(key);
bool alreadyKnown = found != m_radioCircuits.end();
if (alreadyKnown)
{
// Use the known state; but in any case use the (possibly) new name.
state = found->second;
state.name = radioCircuit.name;
}
auto insertResult = newCircuits.insert(std::make_pair(key, state));
Q_ASSERT(insertResult.second);
}
m_radioCircuits = std::move(newCircuits);
std::array<PosState, AvaRtPos::count()> newStates;
const auto count = std::min(static_cast<int>(radioCircuits.size()), AvaRtPos::count());
for (int i = 0; i < count; ++i)
{
const Key key = Key::createFrom(radioCircuits.at(i));
auto found = std::find_if(m_states.begin(), m_states.end(), [&key] (const PosState &s) { return s.key == key; });
bool isSelected = found != m_states.end();
if (isSelected)
newStates.at(i) = *found;
else
newStates.at(i) = PosState{key};
}
m_states = std::move(newStates);
}
void RtState::changeName(const RtState::RadioCircuit &radioCircuit)
{
Key key{radioCircuit.radioSystem, radioCircuit.id};
auto found = m_radioCircuits.find(key);
Q_ASSERT(found != m_radioCircuits.end());
if (found == m_radioCircuits.end())
{
qWarning() << "RtState::changeName: radio circuit not found!";
return;
}
found->second.name = radioCircuit.name;
}
void RtState::setSumChannel(AvaSumChannel sumChannel)
{
m_sumChannel = sumChannel;
}
void RtState::setSelection(AvaRtPos pos, const std::string &name, AvaRtButtonState s)
{
if (name.empty())
{
// The assertion does not always hold. AVS_Workstation may send us a button state
// other than AvaRtButtonState::None even when no radio circuit is selected.
// In that case we set the button state to AvaRtButtonState::None anyway.
// Fixed in AVS since Rev. 588.
Q_ASSERT(s == AvaRtButtonState::None);
m_states.at(toIndex(pos)) = PosState{};
return;
}
auto found = findRadioCircuit(name);
Q_ASSERT(found != m_radioCircuits.end());
if (found == m_radioCircuits.end())
{
qWarning() << "RtState::setSelection: radio circuit not found!";
return;
}
m_states.at(toIndex(pos)) = PosState{found->first, s};
}
void RtState::setVolume(const std::string &name, AvaVolume volume)
{
auto it = findRadioCircuit(name);
Q_ASSERT(it != m_radioCircuits.end());
if (it == m_radioCircuits.end())
{
qWarning() << "RtState::setVolume: radio circuit not found!";
return;
}
it->second.volume = volume;
}
std::string RtState::toCommand() const
{
std::ostringstream availableCircuits;
for (const auto &keyValue: m_radioCircuits)
availableCircuits << keyValue.second.toCommandPart() << ' ';
std::ostringstream selectedCircuits;
std::ostringstream states;
for (const auto &s: m_states)
{
selectedCircuits << s.toCommandSelectionPart(m_radioCircuits) << ' ';
states << s.toCommandStatePart() << ' ';
}
static const QString command = QStringLiteral(R"(setRtProfile "Default" "%1" "%2" "%3" %4)");
return command.arg(QString::fromStdString(availableCircuits.str()),
QString::fromStdString(selectedCircuits.str()),
QString::fromStdString(states.str()),
QString::number(static_cast<int>(m_sumChannel))).toStdString();
}
std::vector<std::string> RtState::allRadioCircuits() const
{
std::vector<std::string> allCircuits;
allCircuits.reserve(m_radioCircuits.size());
for (const auto &keyValue: m_radioCircuits)
allCircuits.push_back(keyValue.second.name);
return allCircuits;
}
std::vector<std::string> RtState::selectedRadioCircuits() const
{
std::vector<std::string> selectedCircuits;
selectedCircuits.reserve(m_states.size());
auto isFirstChannel = [](AvaSumChannel sc, AvaRtButtonState bs)
{
switch (sc)
{
case AvaSumChannel::Left:
return bs == AvaRtButtonState::Right;
case AvaSumChannel::Right:
return bs == AvaRtButtonState::Left;
};
return false;
};
for (const PosState &state: m_states)
{
if (state.key)
{
if (isFirstChannel(m_sumChannel, state.buttonState))
selectedCircuits.insert(selectedCircuits.begin(), m_radioCircuits.find(*state.key)->second.name);
else
selectedCircuits.push_back(m_radioCircuits.find(*state.key)->second.name);
}
}
return selectedCircuits;
}
std::map<RtState::Key, RtState::CircuitState>::iterator RtState::findRadioCircuit(const std::string &name)
{
auto withName = [&name] (const std::map<Key, CircuitState>::value_type &keyValue) { return keyValue.second.name == name; };
return std::find_if(m_radioCircuits.begin(), m_radioCircuits.end(), withName);
}
RtState::CircuitState::CircuitState(const std::string &name_):
name(name_)
{}
std::string RtState::CircuitState::toCommandPart() const
{
return QStringLiteral("15 %1 {%2}").arg(QString::number(static_cast<int>(volume)), QString::fromStdString(name)).toStdString();
}
RtState::PosState::PosState(const Key &key_, AvaRtButtonState s)
: key(key_)
, buttonState(s)
{}
std::string RtState::PosState::toCommandSelectionPart(const std::map<Key, CircuitState> &radioCircuits) const
{
std::string name;
if (key)
name = radioCircuits.find(*key)->second.name;
return QStringLiteral("{%1}").arg(QString::fromStdString(name)).toStdString();
}
std::string RtState::PosState::toCommandStatePart() const
{
return std::to_string(static_cast<int>(buttonState));
}
} // namespace AudioVideoManagement