From ab4bae21bda0f181c23aa8fbcd0f581441571a51 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Thu, 25 Aug 2022 18:24:45 +0200 Subject: Big refactor, minor design tweak along the way --- src/CMakeLists.txt | 2 ++ src/main.cpp | 28 ++++++++------- src/mainwindow.cpp | 102 +++++++++++++++++++++++++++++++++++++---------------- src/mainwindow.h | 12 ++++++- src/slxoutput.cpp | 101 ++++++++++++++++++++++++++++++++-------------------- src/slxoutput.h | 37 +++++++++++++++---- src/slxoutput.ui | 23 +++++++----- 7 files changed, 208 insertions(+), 97 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d7ff79a..709a77e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,11 +26,13 @@ set(pavucontrol-qt_UI slxoutput.ui ) +qt5_wrap_ui(pavucontrol-qt_UI_HEADERS ${pavucontrol-qt_UI}) qt5_add_resources(pavucontrol-qt_RCS resources.qrc) add_executable(pavucontrol-qt ${pavucontrol-qt_SRCS} ${pavucontrol-qt_RCS} + ${pavucontrol-qt_UI_HEADERS} ) # ${PULSE_LDFLAGS} diff --git a/src/main.cpp b/src/main.cpp index bf22453..adf515b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -70,35 +70,37 @@ static void updateActiveOutput() printf(".--------------------------------------------.\n"); for (auto *sink : i->sinks()) { - QString cardName = sink->cardIndex() < cards.size() ? cards.at(sink->cardIndex())->name() : QString(); + PulseAudioQt::Card *card = nullptr; + if (sink->cardIndex() < cards.size()) { + card = cards.at(sink->cardIndex()); + } int portIndex = -1; for (auto *port : sink->ports()) { portIndex++; //if (port->availability() == PulseAudioQt::Port::Unavailable) // continue; - bool active = (sink->isDefault() && portIndex == sink->activePortIndex()); + bool portIsActive = portIndex == sink->activePortIndex(); + bool defaultSinkAndPort = (sink->isDefault() && portIsActive); qint64 volume = sink->volume(); printf("[%c] Output: '%s %s', volume: %d, mute: %d\n", - active ? 'x' : ' ', + defaultSinkAndPort ? 'x' : ' ', sink->description().toLocal8Bit().constData(), port->description().toLocal8Bit().constData(), (int)volume, (int)sink->isMuted()); - QString id = cardName + sink->name() + port->name(); + QString id = sink->name() + port->name(); // Only once, update port volume to be 100% if it's low - if (active && !_donePorts.contains(id)) { + if (defaultSinkAndPort && !_donePorts.contains(id)) { _donePorts.insert(id); if (volume < 60000) { volume = 65535; sink->setVolume(volume); } } - QString title = sink->description() + ", " + port->description(); - _mainWindow->getOutput(id, true, title)->updateOutput(title, - active, sink->isMuted(), sink->isVolumeWritable() ? sink->volume() : -1, QString(), sink->name(), port->name()); + _mainWindow->getDevice(card, sink, port)->updateDeviceAndPort(defaultSinkAndPort, sink->isMuted(), + (portIsActive && sink->isVolumeWritable()) ? sink->volume() : -1); } } // Now find all the profiles from all cards that are not active and add an entry to the list for each one for (auto *card : cards) { - QString cardDescription = card->description(); int profIndex = -1; for (auto *profile : card->profiles()) { profIndex++; @@ -110,10 +112,7 @@ static void updateActiveOutput() continue; printf("[ ] Output: '%s', sinks: %d\n", profile->description().toLocal8Bit().constData(), profile->sinks()); - QString id = card->name() + profile->name(); - QString title = cardDescription + ", " + profile->description(); - _mainWindow->getOutput(id, false, title)->updateOutput(title, - false, false, -1, card->name(), QString(), profile->name()); + _mainWindow->getCardProfile(card, profile)->updateCardAndProfile(); } } printf("`--------------------------------------------ยด\n"); @@ -341,6 +340,9 @@ int main(int argc, char **argv) for (auto *profile : card->profiles()) { printf(" Profile: %s\n", profile->name().toLocal8Bit().constData()); } + for (auto *port : card->ports()) { + printf(" Port: %s\n", port->name().toLocal8Bit().constData()); + } } for (auto *sink : i->sinks()) { printf("Sink: %s (for card index %d)\n", sink->name().toLocal8Bit().constData(), sink->cardIndex()); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 9ae66d3..b35a8f9 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1,6 +1,11 @@ #include "mainwindow.h" #include "slxoutput.h" +#include +#include +#include +#include + MainWindow::MainWindow() : QDialog() { setupUi(this); @@ -12,43 +17,80 @@ MainWindow::~MainWindow() } -SlxOutput* MainWindow::getOutput(const QString &id, bool isSink, const QString &newTitle) +SlxOutput* MainWindow::getDevice(const PulseAudioQt::Card *card, const PulseAudioQt::Sink *sink, const PulseAudioQt::Port *port) +{ + PulseAudioQt::Profile *profile = nullptr; + QString cardId; + QString id = sink->name() + port->name(); + SlxOutput* w = _widgets.value(id, nullptr); + QString heading = port->description(); + + if (card != nullptr) { + cardId = card->name(); + if (card->activeProfileIndex() < card->profiles().size()) { + profile = card->profiles().at(card->activeProfileIndex()); + heading.append(QLatin1String(" (")).append(profile->description()).append(QLatin1String(")")); + } + } + if (w != nullptr) { + w->headingLabel->setText(heading); + return w; + } + + w = new SlxOutput(SlxOutput::SinkPortItem, id, cardId, QLatin1String(), sink->name(), port->name(), + heading, sink->description()); + _widgets.insert(id, w); + + insertItemWidget(w, true); + return w; +} + +SlxOutput* MainWindow::getCardProfile(const PulseAudioQt::Card *card, const PulseAudioQt::Profile *profile) { + + QString id = card->name() + profile->name(); SlxOutput* w = _widgets.value(id, nullptr); - if (w == nullptr) { - w = new SlxOutput(nullptr, id); - _widgets.insert(id, w); - bool done = false; - printf("New %s - %s\n", isSink ? "SINK" : "PROF", newTitle.toLocal8Bit().constData()); - printf("Conteints: %d\n", container->count()); - int idx; - for (idx = 0; idx < container->count(); ++idx) { - auto *l = container->itemAt(idx); - SlxOutput *other = qobject_cast(l->widget()); - if (other == nullptr) - continue; - printf(" Comparing %s - %s\n", other->isSink() ? "SINK" : "PROF", other->nameLabel->text().toLocal8Bit().constData()); - if (isSink != other->isSink()) { - if (isSink) - break; - continue; - } - if (newTitle.compare(other->nameLabel->text()) < 0) { - done = true; - printf("Inserting before that (%d)!\n", idx); - container->insertWidget(idx, w); + if (w != nullptr) + return w; + + w = new SlxOutput(SlxOutput::CardProfileItem, id, card->name(), profile->name(), QLatin1String(), QLatin1String(), + profile->description(), card->description()); + _widgets.insert(id, w); + + insertItemWidget(w, false); + return w; +} + +void MainWindow::insertItemWidget(SlxOutput* w, bool isDevice) +{ + bool done = false; + int idx; + + for (idx = 0; idx < container->count(); ++idx) { + auto *l = container->itemAt(idx); + SlxOutput *other = qobject_cast(l->widget()); + if (other == nullptr) + continue; + printf(" Comparing %s - %s\n", other->isDevice() ? "SINK" : "PROF", other->nameLabel->text().toLocal8Bit().constData()); + if (isDevice != other->isDevice()) { + if (isDevice) break; - } + continue; } - if (!done) { - if (idx == -1) { - idx = 0; - } - printf("Inserting before that (%d) 2!\n", idx); + if (w->compareTo(other) < 0) { + done = true; + printf("Inserting before that (%d)!\n", idx); container->insertWidget(idx, w); + break; } } - return w; + if (!done) { + if (idx == -1) { + idx = 0; + } + printf("Inserting before that (%d) 2!\n", idx); + container->insertWidget(idx, w); + } } /** diff --git a/src/mainwindow.h b/src/mainwindow.h index 7f792c5..6fbe9f2 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -7,6 +7,13 @@ #include "ui_mainwindow.h" class SlxOutput; +namespace PulseAudioQt { +class Sink; +class Port; +class Source; +class Card; +class Profile; +} class MainWindow : public QDialog, public Ui::MainWindow { @@ -16,7 +23,10 @@ public: MainWindow(); virtual ~MainWindow(); - SlxOutput* getOutput(const QString &id, bool isSink, const QString &newTitle); + SlxOutput* getDevice(const PulseAudioQt::Card *card, const PulseAudioQt::Sink *sink, const PulseAudioQt::Port *port); + SlxOutput* getCardProfile(const PulseAudioQt::Card *card, const PulseAudioQt::Profile *profile); + + void insertItemWidget(SlxOutput* w, bool isDevice); void mark(); void sweep(); diff --git a/src/slxoutput.cpp b/src/slxoutput.cpp index 0ac38b1..5bc319b 100644 --- a/src/slxoutput.cpp +++ b/src/slxoutput.cpp @@ -1,44 +1,66 @@ #include "slxoutput.h" #include "main.h" -SlxOutput::SlxOutput(QWidget *parent, const QString &id) +SlxOutput::SlxOutput(ItemType type, const QString &id, + const QString &card, const QString &profile, + const QString &sink, const QString &port, + const QString &heading, const QString &title) : unused(false), - QWidget(parent), - _id(id) + _id(id), + _type(type), + _cardId(card), + _profileId(profile), + _deviceId(sink), + _portId(port), + QWidget(nullptr) { setupUi(this); - volumeSlider->setMaximum(65535); - volumeSlider->setSingleStep(200); - volumeSlider->setSingleStep(2000); - _volumeTimer.setInterval(100); - _volumeTimer.setSingleShot(true); - // Events - connect(muteToggleButton, &QToolButton::toggled, [this]() { - if (g_IgnoreGui) - return; - if (_sink.isEmpty()) - return; - setMuted(_sink, muteToggleButton->isChecked()); - }); + // Make heading 25% larger than system default + QFont f = headingLabel->font(); + f.setPointSize(f.pointSize() * 5 / 4); + f.setBold(_type == SinkPortItem || _type == SourcePortItem); + headingLabel->setFont(f); + // + if (_type == SinkPortItem || _type == SourcePortItem) { + volumeSlider->setMaximum(65535); + volumeSlider->setSingleStep(200); + volumeSlider->setSingleStep(2000); + _volumeTimer.setInterval(100); + _volumeTimer.setSingleShot(true); + // Events + connect(muteToggleButton, &QToolButton::toggled, [this]() { + if (g_IgnoreGui) + return; + if (_deviceId.isEmpty()) + return; + setMuted(_deviceId, muteToggleButton->isChecked()); + }); + connect(volumeSlider, &QSlider::sliderMoved, this, &SlxOutput::volumeSliderChanged); + connect(volumeSlider, &QSlider::valueChanged, this, &SlxOutput::volumeSliderChanged); + connect(&_volumeTimer, &QTimer::timeout, [this]() { + if (g_IgnoreGui || !isDevice()) + return; + setSinkVolume(_deviceId, volumeSlider->value()); + }); + } else { + volumeSlider->setEnabled(false); + muteToggleButton->setEnabled(false); + } + nameLabel->setText(title); + headingLabel->setText(heading); + // Default Toggle connect(defaultToggleButton, &QToolButton::toggled, [this]() { if (g_IgnoreGui) return; if (!defaultToggleButton->isChecked()) { defaultToggleButton->setChecked(true); } - if (_sink.isEmpty()) { - enableCard(_card, _port); + if (_type == CardProfileItem) { + enableCard(_cardId, _profileId); } else { - enableSink(_sink, _port); + enableSink(_deviceId, _portId); } }); - connect(volumeSlider, &QSlider::sliderMoved, this, &SlxOutput::volumeSliderChanged); - connect(volumeSlider, &QSlider::valueChanged, this, &SlxOutput::volumeSliderChanged); - connect(&_volumeTimer, &QTimer::timeout, [this]() { - if (g_IgnoreGui || !isSink()) - return; - setSinkVolume(_sink, volumeSlider->value()); - }); } SlxOutput::~SlxOutput() @@ -56,28 +78,31 @@ void SlxOutput::volumeSliderChanged(int value) _volumeTimer.start(); } -void SlxOutput::updateOutput(const QString &name, bool isDefault, bool isMuted, int volume, const QString &card, const QString &sink, const QString &port) +/** + * Update this entry, which has to represent a sink/source plus one of its ports. + */ +void SlxOutput::updateDeviceAndPort(bool isDefault, bool isMuted, int volume) { - nameLabel->setText(name); - if (sink != _sink) { - QFont fi = nameLabel->font(); - fi.setBold(!sink.isEmpty()); - nameLabel->setFont(fi); - } - _card = card; - _sink = sink; - _port = port; defaultToggleButton->setChecked(isDefault); muteToggleButton->setChecked(isMuted); if (volume == -1) { volumeSlider->setEnabled(false); + muteToggleButton->setEnabled(false); } else { if (volume > volumeSlider->maximum()) { volumeSlider->setMaximum(volume); } volumeSlider->setValue(volume); - volumeSlider->setEnabled(isSink()); + volumeSlider->setEnabled(true); + muteToggleButton->setEnabled(true); } - muteToggleButton->setEnabled(isSink()); + unused = false; // Entry was updated, so it's being used +} + +/** + * Update this entry, which has to represent a card plus one of its profiles. + */ +void SlxOutput::updateCardAndProfile() +{ unused = false; // Entry was updated, so it's being used } diff --git a/src/slxoutput.h b/src/slxoutput.h index 15f8554..c175899 100644 --- a/src/slxoutput.h +++ b/src/slxoutput.h @@ -10,20 +10,43 @@ class SlxOutput : public QWidget, public Ui::SlxOutput { Q_OBJECT public: - SlxOutput(QWidget *parent, const QString &id); + + enum ItemType { + UnknownItem, + SinkPortItem, + SourcePortItem, + CardProfileItem, + }; + + SlxOutput(ItemType type, const QString &id, + const QString &card, const QString &profile, + const QString &sink, const QString &port, + const QString &heading, const QString &title); virtual ~SlxOutput(); - void updateOutput(const QString &name, bool isDefault, bool isMuted, int volume, const QString &card, const QString &sink, const QString &port); - const QString &sink() const { return _sink; } - const bool isSink() const { return !_sink.isEmpty(); } + void updateDeviceAndPort(bool isDefault, bool isMuted, int volume); + void updateCardAndProfile(); + + const QString &deviceId() const { return _deviceId; } + const bool isDevice() const { return !_deviceId.isEmpty(); } + + int compareTo(SlxOutput* other) const + { + int c = this->nameLabel->text().compare(other->nameLabel->text()); + if (c != 0) + return c; + return this->headingLabel->text().compare(other->headingLabel->text()); + } bool unused; private: + ItemType _type; QString _id; - QString _card; - QString _sink; - QString _port; + QString _cardId; + QString _profileId; + QString _deviceId; + QString _portId; QTimer _volumeTimer; private slots: diff --git a/src/slxoutput.ui b/src/slxoutput.ui index 3516d82..55bf300 100644 --- a/src/slxoutput.ui +++ b/src/slxoutput.ui @@ -7,13 +7,20 @@ 0 0 400 - 81 + 102 Form + + + + Profile/Port/Sink/Source + + + @@ -23,9 +30,8 @@ - :/none - :/checkmark - + :/none + :/checkmark:/none @@ -65,9 +71,8 @@ - :/mute-off - :/mute-on - + :/mute-off + :/mute-on:/mute-off @@ -98,6 +103,8 @@ - + + + -- cgit v1.2.3-55-g7522