diff --git a/frontend/cmake/ui-components.cmake b/frontend/cmake/ui-components.cmake index ad0506a0858ff2..61c52d6cf28849 100644 --- a/frontend/cmake/ui-components.cmake +++ b/frontend/cmake/ui-components.cmake @@ -73,6 +73,8 @@ target_sources( components/UIValidation.hpp components/UrlPushButton.cpp components/UrlPushButton.hpp + components/VerticalLabel.cpp + components/VerticalLabel.hpp components/VisibilityItemDelegate.cpp components/VisibilityItemDelegate.hpp components/VisibilityItemWidget.cpp diff --git a/frontend/components/OBSSourceLabel.hpp b/frontend/components/OBSSourceLabel.hpp index c0e9f434fa8071..d100767bdaee5b 100644 --- a/frontend/components/OBSSourceLabel.hpp +++ b/frontend/components/OBSSourceLabel.hpp @@ -19,9 +19,9 @@ #include -#include +#include -class OBSSourceLabel : public QLabel { +class OBSSourceLabel : public VerticalLabel { Q_OBJECT; public: @@ -29,8 +29,8 @@ class OBSSourceLabel : public QLabel { OBSSignal removedSignal; OBSSignal destroyedSignal; - OBSSourceLabel(const obs_source_t *source, QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags()) - : QLabel(obs_source_get_name(source), parent, f), + OBSSourceLabel(const obs_source_t *source, QWidget *parent = nullptr) + : VerticalLabel(QString(obs_source_get_name(source)), parent), renamedSignal(obs_source_get_signal_handler(source), "rename", &OBSSourceLabel::SourceRenamed, this), removedSignal(obs_source_get_signal_handler(source), "remove", &OBSSourceLabel::SourceRemoved, this), destroyedSignal(obs_source_get_signal_handler(source), "destroy", &OBSSourceLabel::SourceDestroyed, diff --git a/frontend/components/VerticalLabel.cpp b/frontend/components/VerticalLabel.cpp new file mode 100644 index 00000000000000..0c7169be2b54d9 --- /dev/null +++ b/frontend/components/VerticalLabel.cpp @@ -0,0 +1,41 @@ +#include "VerticalLabel.hpp" +#include + +#include "moc_VerticalLabel.cpp" + +VerticalLabel::VerticalLabel(const QString &text, QWidget *parent) : QLabel(text, parent) {} + +void VerticalLabel::ShowNormal() +{ + vertical = false; +} + +void VerticalLabel::ShowVertical() +{ + vertical = true; +} + +void VerticalLabel::paintEvent(QPaintEvent *event) +{ + if (!vertical) { + QLabel::paintEvent(event); + return; + } + + QStylePainter painter(this); + painter.translate(0, height()); + painter.rotate(270); + painter.drawText(QRect(QPoint(0, 0), QLabel::sizeHint()), alignment(), text()); +} + +QSize VerticalLabel::minimumSizeHint() const +{ + QSize s = QLabel::minimumSizeHint(); + return QSize(vertical ? s.height() : s.width(), vertical ? s.width() : s.height()); +} + +QSize VerticalLabel::sizeHint() const +{ + QSize s = QLabel::sizeHint(); + return QSize(vertical ? s.height() : s.width(), vertical ? s.width() : s.height()); +} diff --git a/frontend/components/VerticalLabel.hpp b/frontend/components/VerticalLabel.hpp new file mode 100644 index 00000000000000..b9208ee74cdcdf --- /dev/null +++ b/frontend/components/VerticalLabel.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +class VerticalLabel : public QLabel { + Q_OBJECT + +private: + bool vertical = false; + +public: + VerticalLabel(const QString &text, QWidget *parent = nullptr); + void ShowNormal(); + void ShowVertical(); + +protected: + virtual void paintEvent(QPaintEvent *event) override; + virtual QSize sizeHint() const override; + virtual QSize minimumSizeHint() const override; +}; diff --git a/frontend/data/themes/Yami.obt b/frontend/data/themes/Yami.obt index 0190ac52841992..e951d1a040c10f 100644 --- a/frontend/data/themes/Yami.obt +++ b/frontend/data/themes/Yami.obt @@ -1341,7 +1341,6 @@ QSlider::handle:disabled { height: var(--icon_base); background-color: var(--button_bg); padding: var(--padding_base_border) var(--padding_base_border); - margin: 0px; border: 1px solid var(--button_border); border-radius: var(--border_radius); icon-size: var(--icon_base); @@ -1373,24 +1372,17 @@ VolControl { VolControl QLabel { font-size: var(--font_small); - margin: var(--spacing_small) 0px; } VolControl #volLabel { - padding: var(--padding_base) 0px var(--padding_base); - text-align: center; font-size: var(--font_base); color: var(--text_muted); } /* Horizontal Mixer */ #hMixerScrollArea VolControl { - padding: 0px var(--padding_xlarge) var(--padding_base); border-bottom: 1px solid var(--border_color); -} - -#hMixerScrollArea VolControl QSlider { - margin: 0px 0px var(--padding_base); + padding: var(--padding_container); } #hMixerScrollArea VolControl QSlider::groove:horizontal { @@ -1404,20 +1396,12 @@ VolControl #volLabel { } #vMixerScrollArea VolControl { - padding: var(--padding_container) 0px var(--padding_container); border-right: 1px solid var(--border_color); + padding: var(--padding_container); } #vMixerScrollArea VolControl QSlider { width: var(--volume_slider_box); - margin: 0px var(--padding_xlarge); -} - -#vMixerScrollArea VolControl #volLabel { - padding: var(--padding_base) 0px var(--padding_base); - min-width: var(--volume_slider_label); - margin-left: var(--padding_xlarge); - text-align: center; } #vMixerScrollArea VolControl QSlider::groove:vertical { @@ -1425,25 +1409,16 @@ VolControl #volLabel { width: var(--volume_slider); } -#vMixerScrollArea VolControl #volMeterFrame { - padding: var(--padding_large) var(--padding_xlarge) var(--padding_large) 0px; -} - -#vMixerScrollArea VolControl QLabel { - padding: 0px var(--padding_large); -} - -#vMixerScrollArea VolControl QPushButton { - margin-left: var(--spacing_base); - margin-right: var(--padding_xlarge); +VolumeMeter { + background: transparent; } -#vMixerScrollArea VolControl .indicator-mute { - margin-left: var(--padding_xlarge); +VolControl QWidget { + margin: 0px; } -VolumeMeter { - background: transparent; +VolControl .indicator-expand { + margin: 0px; } VolumeMeter { diff --git a/frontend/widgets/OBSBasic.hpp b/frontend/widgets/OBSBasic.hpp index 1cfe14f1adc6ce..b8ce70b598f2ec 100644 --- a/frontend/widgets/OBSBasic.hpp +++ b/frontend/widgets/OBSBasic.hpp @@ -1628,10 +1628,6 @@ private slots: void ToggleMixerLayout(bool vertical); private slots: - void HideAudioControl(); - void UnhideAllAudioControls(); - void ToggleHideMixer(); - void on_vMixerScrollArea_customContextMenuRequested(); void on_hMixerScrollArea_customContextMenuRequested(); diff --git a/frontend/widgets/OBSBasic_SceneItems.cpp b/frontend/widgets/OBSBasic_SceneItems.cpp index 48919c0cdfc402..901bfdca2e404a 100644 --- a/frontend/widgets/OBSBasic_SceneItems.cpp +++ b/frontend/widgets/OBSBasic_SceneItems.cpp @@ -161,15 +161,13 @@ void OBSBasic::MixerRenameSource() void OBSBasic::ActivateAudioSource(OBSSource source) { - if (SourceMixerHidden(source)) - return; if (!obs_source_active(source)) return; if (!obs_source_audio_active(source)) return; bool vertical = config_get_bool(App()->GetUserConfig(), "BasicWindow", "VerticalVolControl"); - VolControl *vol = new VolControl(source, true, vertical); + VolControl *vol = new VolControl(source, vertical, SourceMixerHidden(source)); vol->EnableSlider(!SourceVolumeLocked(source)); @@ -653,12 +651,6 @@ void OBSBasic::CreateSourcePopupMenu(int idx, bool preview) colorSelect = new ColorSelect(colorMenu); popup.addMenu(AddBackgroundColorMenu(colorMenu, colorWidgetAction, colorSelect, sceneItem)); - if (hasAudio) { - QAction *actionHideMixer = - popup.addAction(QTStr("HideMixer"), this, &OBSBasic::ToggleHideMixer); - actionHideMixer->setCheckable(true); - actionHideMixer->setChecked(SourceMixerHidden(source)); - } popup.addSeparator(); } diff --git a/frontend/widgets/OBSBasic_VolControl.cpp b/frontend/widgets/OBSBasic_VolControl.cpp index 674d84829f0a33..1d09b3c9cf2d0d 100644 --- a/frontend/widgets/OBSBasic_VolControl.cpp +++ b/frontend/widgets/OBSBasic_VolControl.cpp @@ -69,56 +69,6 @@ void OBSBasic::RefreshVolumeColors() } } -void OBSBasic::HideAudioControl() -{ - QAction *action = reinterpret_cast(sender()); - VolControl *vol = action->property("volControl").value(); - obs_source_t *source = vol->GetSource(); - - if (!SourceMixerHidden(source)) { - SetSourceMixerHidden(source, true); - DeactivateAudioSource(source); - } -} - -void OBSBasic::UnhideAllAudioControls() -{ - auto UnhideAudioMixer = [this](obs_source_t *source) /* -- */ - { - if (!obs_source_active(source)) - return true; - if (!SourceMixerHidden(source)) - return true; - - SetSourceMixerHidden(source, false); - ActivateAudioSource(source); - return true; - }; - - using UnhideAudioMixer_t = decltype(UnhideAudioMixer); - - auto PreEnum = [](void *data, obs_source_t *source) -> bool /* -- */ - { - return (*reinterpret_cast(data))(source); - }; - - obs_enum_sources(PreEnum, &UnhideAudioMixer); -} - -void OBSBasic::ToggleHideMixer() -{ - OBSSceneItem item = GetCurrentSceneItem(); - OBSSource source = obs_sceneitem_get_source(item); - - if (!SourceMixerHidden(source)) { - SetSourceMixerHidden(source, true); - DeactivateAudioSource(source); - } else { - SetSourceMixerHidden(source, false); - ActivateAudioSource(source); - } -} - void OBSBasic::LockVolumeControl(bool lock) { QAction *action = reinterpret_cast(sender()); @@ -141,8 +91,6 @@ void OBSBasic::VolControlContextMenu() lockAction.setCheckable(true); lockAction.setChecked(SourceVolumeLocked(vol->GetSource())); - QAction hideAction(QTStr("Hide"), this); - QAction unhideAllAction(QTStr("UnhideAll"), this); QAction mixerRenameAction(QTStr("Rename"), this); QAction copyFiltersAction(QTStr("Copy.Filters"), this); @@ -159,8 +107,6 @@ void OBSBasic::VolControlContextMenu() /* ------------------- */ - connect(&hideAction, &QAction::triggered, this, &OBSBasic::HideAudioControl, Qt::DirectConnection); - connect(&unhideAllAction, &QAction::triggered, this, &OBSBasic::UnhideAllAudioControls, Qt::DirectConnection); connect(&lockAction, &QAction::toggled, this, &OBSBasic::LockVolumeControl, Qt::DirectConnection); connect(&mixerRenameAction, &QAction::triggered, this, &OBSBasic::MixerRenameSource, Qt::DirectConnection); @@ -181,7 +127,6 @@ void OBSBasic::VolControlContextMenu() /* ------------------- */ - hideAction.setProperty("volControl", QVariant::fromValue(vol)); lockAction.setProperty("volControl", QVariant::fromValue(vol)); mixerRenameAction.setProperty("volControl", QVariant::fromValue(vol)); @@ -200,8 +145,6 @@ void OBSBasic::VolControlContextMenu() vol->SetContextMenu(&popup); popup.addAction(&lockAction); popup.addSeparator(); - popup.addAction(&unhideAllAction); - popup.addAction(&hideAction); popup.addAction(&mixerRenameAction); popup.addSeparator(); popup.addAction(©FiltersAction); @@ -231,8 +174,6 @@ void OBSBasic::on_vMixerScrollArea_customContextMenuRequested() void OBSBasic::StackedMixerAreaContextMenuRequested() { - QAction unhideAllAction(QTStr("UnhideAll"), this); - QAction advPropAction(QTStr("Basic.MainMenu.Edit.AdvAudio"), this); QAction toggleControlLayoutAction(QTStr("VerticalLayout"), this); @@ -242,8 +183,6 @@ void OBSBasic::StackedMixerAreaContextMenuRequested() /* ------------------- */ - connect(&unhideAllAction, &QAction::triggered, this, &OBSBasic::UnhideAllAudioControls, Qt::DirectConnection); - connect(&advPropAction, &QAction::triggered, this, &OBSBasic::on_actionAdvAudioProperties_triggered, Qt::DirectConnection); @@ -255,7 +194,6 @@ void OBSBasic::StackedMixerAreaContextMenuRequested() /* ------------------- */ QMenu popup; - popup.addAction(&unhideAllAction); popup.addSeparator(); popup.addAction(&toggleControlLayoutAction); popup.addSeparator(); @@ -299,9 +237,6 @@ void OBSBasic::on_actionMixerToolbarAdvAudio_triggered() void OBSBasic::on_actionMixerToolbarMenu_triggered() { - QAction unhideAllAction(QTStr("UnhideAll"), this); - connect(&unhideAllAction, &QAction::triggered, this, &OBSBasic::UnhideAllAudioControls, Qt::DirectConnection); - QAction toggleControlLayoutAction(QTStr("VerticalLayout"), this); toggleControlLayoutAction.setCheckable(true); toggleControlLayoutAction.setChecked( @@ -310,7 +245,6 @@ void OBSBasic::on_actionMixerToolbarMenu_triggered() Qt::DirectConnection); QMenu popup; - popup.addAction(&unhideAllAction); popup.addSeparator(); popup.addAction(&toggleControlLayoutAction); popup.exec(QCursor::pos()); diff --git a/frontend/widgets/VolControl.cpp b/frontend/widgets/VolControl.cpp index ea9ee5c6bc0c17..d98d58389b3b4a 100644 --- a/frontend/widgets/VolControl.cpp +++ b/frontend/widgets/VolControl.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -67,14 +68,6 @@ void VolControl::OBSVolumeLevel(void *data, const float magnitude[MAX_AUDIO_CHAN volControl->volMeter->setLevels(magnitude, peak, inputPeak); } -void VolControl::OBSVolumeMuted(void *data, calldata_t *calldata) -{ - VolControl *volControl = static_cast(data); - bool muted = calldata_bool(calldata, "muted"); - - QMetaObject::invokeMethod(volControl, "VolumeMuted", Q_ARG(bool, muted)); -} - void VolControl::VolumeChanged() { slider->blockSignals(true); @@ -84,34 +77,25 @@ void VolControl::VolumeChanged() updateText(); } -void VolControl::VolumeMuted(bool muted) -{ - bool unassigned = IsSourceUnassigned(source); - - auto newState = GetCheckState(muted, unassigned); - if (mute->checkState() != newState) - mute->setCheckState(newState); - - volMeter->muted = muted || unassigned; -} - -void VolControl::OBSMixersOrMonitoringChanged(void *data, calldata_t *) +void VolControl::OBSAudioChanged(void *data, calldata_t *) { - VolControl *volControl = static_cast(data); - QMetaObject::invokeMethod(volControl, "MixersOrMonitoringChanged", Qt::QueuedConnection); + QMetaObject::invokeMethod(volControl, "AudioChanged", Qt::QueuedConnection); } -void VolControl::MixersOrMonitoringChanged() +void VolControl::AudioChanged() { bool muted = obs_source_muted(source); bool unassigned = IsSourceUnassigned(source); auto newState = GetCheckState(muted, unassigned); - if (mute->checkState() != newState) + if (mute && (mute->checkState() != newState)) mute->setCheckState(newState); - volMeter->muted = muted || unassigned; + if (volMeter) + volMeter->muted = muted || unassigned; + + nameLabel->setDisabled(muted || unassigned); } void VolControl::SetMuted(bool) @@ -191,183 +175,151 @@ void VolControl::EmitConfigClicked() void VolControl::SetMeterDecayRate(qreal q) { - volMeter->setPeakDecayRate(q); + peakDecayRate = q; + + if (volMeter) + volMeter->setPeakDecayRate(peakDecayRate); } -void VolControl::setPeakMeterType(enum obs_peak_meter_type peakMeterType) +void VolControl::setPeakMeterType(enum obs_peak_meter_type peakMeterType_) { - volMeter->setPeakMeterType(peakMeterType); + peakMeterType = peakMeterType_; + + if (volMeter) + volMeter->setPeakMeterType(peakMeterType); } -VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical) +VolControl::VolControl(OBSSource source_, bool vertical_, bool hidden) : source(std::move(source_)), levelTotal(0.0f), levelCount(0.0f), obs_fader(obs_fader_create(OBS_FADER_LOG)), obs_volmeter(obs_volmeter_create(OBS_FADER_LOG)), - vertical(vertical), + vertical(vertical_), contextMenu(nullptr) { - nameLabel = new OBSSourceLabel(source); - volLabel = new QLabel(); - mute = new MuteCheckBox(); - - volLabel->setObjectName("volLabel"); - volLabel->setAlignment(Qt::AlignCenter); - -#ifdef __APPLE__ - mute->setAttribute(Qt::WA_LayoutUsesWidgetRect); -#endif - QString sourceName = obs_source_get_name(source); setObjectName(sourceName); - if (showConfig) { - config = new QPushButton(this); - config->setProperty("class", "icon-dots-vert"); - config->setAutoDefault(false); - - config->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - - config->setAccessibleName(QTStr("VolControl.Properties").arg(sourceName)); - - connect(config, &QAbstractButton::clicked, this, &VolControl::EmitConfigClicked); - } - - QVBoxLayout *mainLayout = new QVBoxLayout; - mainLayout->setContentsMargins(0, 0, 0, 0); - mainLayout->setSpacing(0); - - if (vertical) { - QHBoxLayout *nameLayout = new QHBoxLayout; - QHBoxLayout *controlLayout = new QHBoxLayout; - QHBoxLayout *volLayout = new QHBoxLayout; - QFrame *meterFrame = new QFrame; - QHBoxLayout *meterLayout = new QHBoxLayout; - - volMeter = new VolumeMeter(nullptr, obs_volmeter, true); - slider = new VolumeSlider(obs_fader, Qt::Vertical); - slider->setLayoutDirection(Qt::LeftToRight); - slider->setDisplayTicks(true); - - nameLayout->setAlignment(Qt::AlignCenter); - meterLayout->setAlignment(Qt::AlignCenter); - controlLayout->setAlignment(Qt::AlignCenter); - volLayout->setAlignment(Qt::AlignCenter); - - meterFrame->setObjectName("volMeterFrame"); - - nameLayout->setContentsMargins(0, 0, 0, 0); - nameLayout->setSpacing(0); - nameLayout->addWidget(nameLabel); - - controlLayout->setContentsMargins(0, 0, 0, 0); - controlLayout->setSpacing(0); - - // Add Headphone (audio monitoring) widget here - controlLayout->addWidget(mute); - - if (showConfig) { - controlLayout->addWidget(config); - } - - meterLayout->setContentsMargins(0, 0, 0, 0); - meterLayout->setSpacing(0); - meterLayout->addWidget(slider); - meterLayout->addWidget(volMeter); - - meterFrame->setLayout(meterLayout); + nameLabel = new OBSSourceLabel(source); + nameLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - volLayout->setContentsMargins(0, 0, 0, 0); - volLayout->setSpacing(0); - volLayout->addWidget(volLabel); - volLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Minimum)); + if (vertical) + nameLabel->ShowVertical(); + else + nameLabel->ShowNormal(); - mainLayout->addItem(nameLayout); - mainLayout->addItem(volLayout); - mainLayout->addWidget(meterFrame); - mainLayout->addItem(controlLayout); + QCheckBox *expand = new QCheckBox(); + expand->setChecked(hidden); + expand->setProperty("class", "checkbox-icon indicator-expand"); + connect(expand, &QCheckBox::clicked, this, &VolControl::ResetControls); - volMeter->setFocusProxy(slider); + controlLayout = new QGridLayout(); + controlLayout->setSpacing(2); + controlLayout->setContentsMargins(0, 0, 0, 0); - // Default size can cause clipping of long names in vertical layout. - QFont font = nameLabel->font(); - QFontInfo info(font); - nameLabel->setFont(font); + controlLayout->addWidget(expand, 0, 0); + setLayout(controlLayout); + if (vertical) setMaximumWidth(110); - } else { - QHBoxLayout *textLayout = new QHBoxLayout; - QHBoxLayout *controlLayout = new QHBoxLayout; - QFrame *meterFrame = new QFrame; - QVBoxLayout *meterLayout = new QVBoxLayout; - QVBoxLayout *buttonLayout = new QVBoxLayout; - - volMeter = new VolumeMeter(nullptr, obs_volmeter, false); - volMeter->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); - - slider = new VolumeSlider(obs_fader, Qt::Horizontal); - slider->setLayoutDirection(Qt::LeftToRight); - slider->setDisplayTicks(true); - - textLayout->setContentsMargins(0, 0, 0, 0); - textLayout->addWidget(nameLabel); - textLayout->addWidget(volLabel); - textLayout->setAlignment(nameLabel, Qt::AlignLeft); - textLayout->setAlignment(volLabel, Qt::AlignRight); - - meterFrame->setObjectName("volMeterFrame"); - meterFrame->setLayout(meterLayout); - meterLayout->setContentsMargins(0, 0, 0, 0); - meterLayout->setSpacing(0); + sigs.emplace_back(obs_source_get_signal_handler(source), "mute", OBSAudioChanged, this); + sigs.emplace_back(obs_source_get_signal_handler(source), "audio_mixers", OBSAudioChanged, this); + sigs.emplace_back(obs_source_get_signal_handler(source), "audio_monitoring", OBSAudioChanged, this); - meterLayout->addWidget(volMeter); - meterLayout->addWidget(slider); - - buttonLayout->setContentsMargins(0, 0, 0, 0); - buttonLayout->setSpacing(0); + ResetControls(hidden); +} - if (showConfig) { - buttonLayout->addWidget(config); +void VolControl::ResetControls(bool hidden) +{ + SetSourceMixerHidden(source, hidden); + + if (hidden) { + obs_fader_remove_callback(obs_fader, OBSVolumeChanged, this); + obs_volmeter_remove_callback(obs_volmeter, OBSVolumeLevel, this); + volLabel.reset(); + mute.reset(); + slider.reset(); + volMeter.reset(); + config.reset(); + + if (vertical) { + nameLabel->ShowVertical(); + controlLayout->addWidget(nameLabel, 1, 0); + controlLayout->setAlignment(nameLabel, Qt::AlignTop); + } else { + nameLabel->ShowNormal(); + controlLayout->addWidget(nameLabel, 0, 1, 1, -1); + controlLayout->setAlignment(nameLabel, Qt::AlignLeft); } - buttonLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding)); - buttonLayout->addWidget(mute); - - controlLayout->addItem(buttonLayout); - controlLayout->addWidget(meterFrame); + } else { + nameLabel->ShowNormal(); + controlLayout->addWidget(nameLabel, 0, 1, 1, -1); + controlLayout->setAlignment(nameLabel, Qt::AlignLeft); + } - mainLayout->addItem(textLayout); - mainLayout->addItem(controlLayout); + bool muted = obs_source_muted(source); + bool unassigned = IsSourceUnassigned(source); + nameLabel->setDisabled(muted || unassigned); - volMeter->setFocusProxy(slider); - } + if (hidden) + return; - setLayout(mainLayout); + // Volume label + volLabel.reset(new QLabel()); + volLabel->setObjectName("volLabel"); - nameLabel->setText(sourceName); + // Mute checkbox + mute.reset(new MuteCheckBox()); + mute->setCheckState(GetCheckState(muted, unassigned)); + mute->setAccessibleName(QTStr("VolControl.Mute").arg(nameLabel->text())); +#ifdef __APPLE__ + mute->setAttribute(Qt::WA_LayoutUsesWidgetRect); +#endif + connect(mute.data(), &MuteCheckBox::clicked, this, &VolControl::SetMuted); + // Fader + slider.reset(new VolumeSlider(obs_fader, vertical ? Qt::Vertical : Qt::Horizontal)); + slider->setLayoutDirection(Qt::LeftToRight); + slider->setDisplayTicks(true); slider->setMinimum(0); slider->setMaximum(int(FADER_PRECISION)); - - bool muted = obs_source_muted(source); - bool unassigned = IsSourceUnassigned(source); - mute->setCheckState(GetCheckState(muted, unassigned)); - volMeter->muted = muted || unassigned; - mute->setAccessibleName(QTStr("VolControl.Mute").arg(sourceName)); obs_fader_add_callback(obs_fader, OBSVolumeChanged, this); + obs_fader_attach_source(obs_fader, source); + connect(slider.data(), &VolumeSlider::valueChanged, this, &VolControl::SliderChanged); + + // Config button + config.reset(new QPushButton()); + config->setProperty("class", "icon-dots-vert"); + config->setAutoDefault(false); + config->setAccessibleName(QTStr("VolControl.Properties").arg(nameLabel->text())); + connect(config.data(), &QAbstractButton::clicked, this, &VolControl::EmitConfigClicked); + + // Volume meter + volMeter.reset(new VolumeMeter(nullptr, obs_volmeter, vertical)); + volMeter.data()->muted = muted || unassigned; obs_volmeter_add_callback(obs_volmeter, OBSVolumeLevel, this); + obs_volmeter_attach_source(obs_volmeter, source); - sigs.emplace_back(obs_source_get_signal_handler(source), "mute", OBSVolumeMuted, this); - sigs.emplace_back(obs_source_get_signal_handler(source), "audio_mixers", OBSMixersOrMonitoringChanged, this); - sigs.emplace_back(obs_source_get_signal_handler(source), "audio_monitoring", OBSMixersOrMonitoringChanged, - this); + if (vertical) { + controlLayout->addWidget(volLabel.data(), 1, 0, 1, -1); + controlLayout->addWidget(slider.data(), 2, 0, Qt::AlignHCenter); + controlLayout->addWidget(volMeter.data(), 2, 1, Qt::AlignHCenter); + controlLayout->addWidget(mute.data(), 3, 0, Qt::AlignHCenter); + controlLayout->addWidget(config.data(), 3, 1, Qt::AlignHCenter); + controlLayout->setColumnStretch(2, 1); + } else { + controlLayout->addWidget(volLabel.data(), 0, 2, Qt::AlignRight); + controlLayout->addWidget(config.data(), 1, 0, Qt::AlignVCenter); + controlLayout->addWidget(volMeter.data(), 1, 1, 1, -1, Qt::AlignVCenter); + controlLayout->addWidget(mute.data(), 2, 0, Qt::AlignVCenter); + controlLayout->addWidget(slider.data(), 2, 1, 1, -1, Qt::AlignVCenter); + } - QWidget::connect(slider, &VolumeSlider::valueChanged, this, &VolControl::SliderChanged); - QWidget::connect(mute, &MuteCheckBox::clicked, this, &VolControl::SetMuted); - - obs_fader_attach_source(obs_fader, source); - obs_volmeter_attach_source(obs_volmeter, source); + SetMeterDecayRate(peakDecayRate); + setPeakMeterType(peakMeterType); + EnableSlider(sliderEnabled); /* Call volume changed once to init the slider position and label */ VolumeChanged(); @@ -375,7 +327,10 @@ VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical) void VolControl::EnableSlider(bool enable) { - slider->setEnabled(enable); + sliderEnabled = enable; + + if (slider) + slider->setEnabled(enable); } VolControl::~VolControl() @@ -383,8 +338,6 @@ VolControl::~VolControl() obs_fader_remove_callback(obs_fader, OBSVolumeChanged, this); obs_volmeter_remove_callback(obs_volmeter, OBSVolumeLevel, this); - sigs.clear(); - if (contextMenu) contextMenu->close(); } diff --git a/frontend/widgets/VolControl.hpp b/frontend/widgets/VolControl.hpp index fe4ba8a203ac60..b5c7583fa52009 100644 --- a/frontend/widgets/VolControl.hpp +++ b/frontend/widgets/VolControl.hpp @@ -8,50 +8,59 @@ class OBSSourceLabel; class VolumeMeter; class VolumeSlider; class MuteCheckBox; +class QCheckBox; class QLabel; class QPushButton; +class QGridLayout; +class OBSSourceLabel; class VolControl : public QFrame { Q_OBJECT private: + QScopedPointer controlContainer; + OBSSource source; std::vector sigs; + QGridLayout *controlLayout; OBSSourceLabel *nameLabel; - QLabel *volLabel; - VolumeMeter *volMeter; - VolumeSlider *slider; - MuteCheckBox *mute; - QPushButton *config = nullptr; + QScopedPointer volLabel; + QScopedPointer volMeter; + QScopedPointer slider; + QScopedPointer mute; + QScopedPointer config; + float levelTotal; float levelCount; OBSFader obs_fader; OBSVolMeter obs_volmeter; - bool vertical; + bool vertical = false; QMenu *contextMenu; + enum obs_peak_meter_type peakMeterType = SAMPLE_PEAK_METER; + qreal peakDecayRate; + bool sliderEnabled = true; static void OBSVolumeChanged(void *param, float db); static void OBSVolumeLevel(void *data, const float magnitude[MAX_AUDIO_CHANNELS], const float peak[MAX_AUDIO_CHANNELS], const float inputPeak[MAX_AUDIO_CHANNELS]); - static void OBSVolumeMuted(void *data, calldata_t *calldata); - static void OBSMixersOrMonitoringChanged(void *data, calldata_t *); + static void OBSAudioChanged(void *data, calldata_t *); void EmitConfigClicked(); private slots: void VolumeChanged(); - void VolumeMuted(bool muted); - void MixersOrMonitoringChanged(); + void AudioChanged(); void SetMuted(bool checked); void SliderChanged(int vol); void updateText(); + void ResetControls(bool visible); signals: void ConfigClicked(); public: - explicit VolControl(OBSSource source, bool showConfig = false, bool vertical = false); + explicit VolControl(OBSSource source, bool vertical = false, bool hidden = false); ~VolControl(); inline obs_source_t *GetSource() const { return source; }