Skip to content

Commit e73662f

Browse files
Warchamp7RytoEX
authored andcommitted
frontend: Implement sizeHint for VolumeMeter
1 parent d3dfadf commit e73662f

File tree

3 files changed

+92
-60
lines changed

3 files changed

+92
-60
lines changed

frontend/components/VolumeMeter.cpp

Lines changed: 76 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,15 @@
99

1010
#include "moc_VolumeMeter.cpp"
1111

12-
// Size of the audio indicator in pixels
13-
#define INDICATOR_THICKNESS 3
14-
1512
QPointer<QTimer> VolumeMeter::updateTimer = nullptr;
1613

14+
namespace {
15+
constexpr int INDICATOR_THICKNESS = 3;
16+
constexpr int CLIP_FLASH_DURATION_MS = 1000;
17+
constexpr int TICK_SIZE = 2;
18+
constexpr int TICK_DB_INTERVAL = 6;
19+
} // namespace
20+
1721
static inline QColor color_from_int(long long val)
1822
{
1923
QColor color(val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff, (val >> 24) & 0xff);
@@ -274,17 +278,6 @@ void VolumeMeter::setPeakMeterType(enum obs_peak_meter_type peakMeterType)
274278
updateBackgroundCache();
275279
}
276280

277-
void VolumeMeter::mousePressEvent(QMouseEvent *event)
278-
{
279-
setFocus(Qt::MouseFocusReason);
280-
event->accept();
281-
}
282-
283-
void VolumeMeter::wheelEvent(QWheelEvent *event)
284-
{
285-
QApplication::sendEvent(focusProxy(), event);
286-
}
287-
288281
VolumeMeter::VolumeMeter(QWidget *parent, obs_source_t *source)
289282
: QWidget(parent),
290283
weakSource(OBSGetWeakRef(source)),
@@ -348,7 +341,7 @@ VolumeMeter::VolumeMeter(QWidget *parent, obs_source_t *source)
348341
repaint();
349342
});
350343

351-
connect(App(), &OBSApp::StyleChanged, this, &VolumeMeter::updateBackgroundCache);
344+
connect(App(), &OBSApp::StyleChanged, this, &VolumeMeter::doLayout);
352345
}
353346

354347
VolumeMeter::~VolumeMeter()
@@ -419,10 +412,10 @@ bool VolumeMeter::needLayoutChange()
419412

420413
if (displayNrAudioChannels != currentNrAudioChannels) {
421414
displayNrAudioChannels = currentNrAudioChannels;
422-
recalculateLayout = true;
415+
return true;
423416
}
424417

425-
return recalculateLayout;
418+
return false;
426419
}
427420

428421
void VolumeMeter::setVertical(bool vertical_)
@@ -465,6 +458,18 @@ void VolumeMeter::refreshColors()
465458
updateBackgroundCache();
466459
}
467460

461+
QRect VolumeMeter::getBarRect() const
462+
{
463+
QRect barRect = rect();
464+
if (vertical) {
465+
barRect.setWidth(displayNrAudioChannels * (meterThickness + 1) - 1);
466+
} else {
467+
barRect.setHeight(displayNrAudioChannels * (meterThickness + 1) - 1);
468+
}
469+
470+
return barRect;
471+
}
472+
468473
// When this is called from the constructor, obs_volmeter_get_nr_channels has not
469474
// yet been called and Q_PROPERTY settings have not yet been read from the
470475
// stylesheet.
@@ -476,28 +481,19 @@ inline void VolumeMeter::doLayout()
476481
int meterSize = std::floor(22 / displayNrAudioChannels);
477482
meterThickness = std::clamp(meterSize, 3, 6);
478483
}
479-
recalculateLayout = false;
480484

481485
tickFont = font();
482486
QFontInfo info(tickFont);
483487
tickFont.setPointSizeF(info.pointSizeF() * meterFontScaling);
488+
484489
QFontMetrics metrics(tickFont);
485-
if (vertical) {
486-
// Each meter channel is meterThickness pixels wide, plus one pixel
487-
// between channels, but not after the last.
488-
// Add 4 pixels for ticks, space to hold our longest label in this font,
489-
// and a few pixels before the fader.
490-
QRect scaleBounds = metrics.boundingRect("-88");
491-
setMinimumSize(displayNrAudioChannels * (meterThickness + 1) - 1 + 10 + scaleBounds.width() + 2, 100);
492-
} else {
493-
// Each meter channel is meterThickness pixels high, plus one pixel
494-
// between channels, but not after the last.
495-
// Add 4 pixels for ticks, and space high enough to hold our label in
496-
// this font, presuming that digits don't have descenders.
497-
setMinimumSize(100, displayNrAudioChannels * (meterThickness + 1) - 1 + 4 + metrics.capHeight());
498-
}
490+
// This is a quick and naive assumption for widest potential tick label.
491+
tickTextTokenRect = metrics.boundingRect(" -88 ");
499492

493+
updateBackgroundCache();
500494
resetLevels();
495+
496+
updateGeometry();
501497
}
502498

503499
inline bool VolumeMeter::detectIdle(uint64_t ts)
@@ -607,7 +603,7 @@ void VolumeMeter::paintHTicks(QPainter &painter, int x, int y, int width)
607603
painter.setPen(majorTickColor);
608604

609605
// Draw major tick lines and numeric indicators.
610-
for (int i = 0; i >= minimumLevel; i -= 6) {
606+
for (int i = 0; i >= minimumLevel; i -= TICK_DB_INTERVAL) {
611607
int position = int(x + width - (i * scale) - 1);
612608
QString str = QString::number(i);
613609

@@ -624,7 +620,7 @@ void VolumeMeter::paintHTicks(QPainter &painter, int x, int y, int width)
624620
}
625621
painter.drawText(pos, y + 4 + metrics.capHeight(), str);
626622

627-
painter.drawLine(position, y, position, y + 2);
623+
painter.drawLine(position, y, position, y + TICK_SIZE);
628624
}
629625
}
630626

@@ -637,7 +633,7 @@ void VolumeMeter::paintVTicks(QPainter &painter, int x, int y, int height)
637633
painter.setPen(majorTickColor);
638634

639635
// Draw major tick lines and numeric indicators.
640-
for (int i = 0; i >= minimumLevel; i -= 6) {
636+
for (int i = 0; i >= minimumLevel; i -= TICK_DB_INTERVAL) {
641637
int position = y + int(i * scale);
642638
QString str = QString::number(i);
643639

@@ -648,12 +644,24 @@ void VolumeMeter::paintVTicks(QPainter &painter, int x, int y, int height)
648644
painter.drawText(x + 8, position + (metrics.capHeight() / 2), str);
649645
}
650646

651-
painter.drawLine(x, position, x + 2, position);
647+
painter.drawLine(x, position, x + TICK_SIZE, position);
652648
}
653649
}
654650

655651
void VolumeMeter::updateBackgroundCache()
656652
{
653+
if (!size().isValid()) {
654+
return;
655+
}
656+
657+
if (backgroundCache.size() == size() && !backgroundCache.isNull()) {
658+
return;
659+
}
660+
661+
if (displayNrAudioChannels <= 0) {
662+
return;
663+
}
664+
657665
QColor backgroundColor = palette().color(QPalette::Window);
658666

659667
backgroundCache = QPixmap(size() * devicePixelRatioF());
@@ -705,8 +713,6 @@ void VolumeMeter::updateBackgroundCache()
705713
}
706714
}
707715

708-
#define CLIP_FLASH_DURATION_MS 1000
709-
710716
inline int VolumeMeter::convertToInt(float number)
711717
{
712718
constexpr int min = std::numeric_limits<int>::min();
@@ -743,9 +749,6 @@ void VolumeMeter::paintEvent(QPaintEvent *)
743749
const qreal scale = meterLength / minimumLevel;
744750

745751
// Paint cached background pixmap
746-
if (backgroundCache.isNull() || backgroundCache.size() != size()) {
747-
updateBackgroundCache();
748-
}
749752
painter.drawPixmap(0, 0, backgroundCache);
750753

751754
// Draw dynamic audio meter bars
@@ -849,23 +852,42 @@ void VolumeMeter::paintEvent(QPaintEvent *)
849852
lastRedrawTime = ts;
850853
}
851854

852-
QRect VolumeMeter::getBarRect() const
855+
void VolumeMeter::resizeEvent(QResizeEvent *event)
853856
{
854-
QRect rec = rect();
855-
if (vertical) {
856-
rec.setWidth(displayNrAudioChannels * (meterThickness + 1) - 1);
857-
} else {
858-
rec.setHeight(displayNrAudioChannels * (meterThickness + 1) - 1);
859-
}
857+
updateBackgroundCache();
858+
return QWidget::resizeEvent(event);
859+
}
860860

861-
return rec;
861+
void VolumeMeter::mousePressEvent(QMouseEvent *event)
862+
{
863+
setFocus(Qt::MouseFocusReason);
864+
event->accept();
862865
}
863866

864-
void VolumeMeter::changeEvent(QEvent *e)
867+
void VolumeMeter::wheelEvent(QWheelEvent *event)
865868
{
866-
if (e->type() == QEvent::StyleChange) {
867-
recalculateLayout = true;
868-
}
869+
QApplication::sendEvent(focusProxy(), event);
870+
}
871+
872+
QSize VolumeMeter::minimumSizeHint() const
873+
{
874+
return sizeHint();
875+
}
869876

870-
QWidget::changeEvent(e);
877+
QSize VolumeMeter::sizeHint() const
878+
{
879+
QRect meterRect = getBarRect();
880+
int labelTotal = std::abs(minimumLevel / TICK_DB_INTERVAL) + 1;
881+
882+
if (vertical) {
883+
int width = meterRect.width() + tickTextTokenRect.width() + TICK_SIZE + 10;
884+
int height = (labelTotal * tickTextTokenRect.height()) + INDICATOR_THICKNESS;
885+
886+
return QSize(width, height * 1.1);
887+
} else {
888+
int width = (labelTotal * tickTextTokenRect.width()) + INDICATOR_THICKNESS;
889+
int height = meterRect.height() + tickTextTokenRect.height();
890+
891+
return QSize(width * 1.1, height);
892+
}
871893
}

frontend/components/VolumeMeter.hpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ class VolumeMeter : public QWidget {
6969

7070
QMutex dataMutex;
7171

72-
bool recalculateLayout{true};
7372
uint64_t currentLastUpdateTime{0};
7473
float currentMagnitude[MAX_AUDIO_CHANNELS];
7574
float currentPeak[MAX_AUDIO_CHANNELS];
@@ -87,6 +86,8 @@ class VolumeMeter : public QWidget {
8786
void updateBackgroundCache();
8887

8988
QFont tickFont;
89+
QRect tickTextTokenRect;
90+
9091
QColor backgroundNominalColor;
9192
QColor backgroundWarningColor;
9293
QColor backgroundErrorColor;
@@ -140,14 +141,14 @@ class VolumeMeter : public QWidget {
140141

141142
void setLevels(const float magnitude[MAX_AUDIO_CHANNELS], const float peak[MAX_AUDIO_CHANNELS],
142143
const float inputPeak[MAX_AUDIO_CHANNELS]);
143-
QRect getBarRect() const;
144144
bool needLayoutChange();
145145

146146
void setVertical(bool vertical = true);
147147
void setUseDisabledColors(bool enable);
148148
void setMuted(bool mute);
149149

150150
void refreshColors();
151+
QRect getBarRect() const;
151152

152153
QColor getBackgroundNominalColor() const;
153154
void setBackgroundNominalColor(QColor c);
@@ -190,12 +191,15 @@ class VolumeMeter : public QWidget {
190191
void setPeakDecayRate(qreal v);
191192
void setPeakMeterType(enum obs_peak_meter_type peakMeterType);
192193

194+
virtual void resizeEvent(QResizeEvent *event) override;
193195
virtual void mousePressEvent(QMouseEvent *event) override;
194196
virtual void wheelEvent(QWheelEvent *event) override;
195197

198+
QSize minimumSizeHint() const override;
199+
QSize sizeHint() const override;
200+
196201
protected:
197202
void paintEvent(QPaintEvent *event) override;
198-
void changeEvent(QEvent *e) override;
199203

200204
private slots:
201205
void handleSourceDestroyed() { deleteLater(); }

frontend/widgets/AudioMixer.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ AudioMixer::AudioMixer(QWidget *parent) : QFrame(parent)
110110
hVolumeWidgets->setLayout(hVolumeControlLayout);
111111
hVolumeControlLayout->setContentsMargins(0, 0, 0, 0);
112112
hVolumeControlLayout->setSpacing(0);
113+
hVolumeControlLayout->setAlignment(Qt::AlignTop);
113114

114115
hMixerScrollArea->setWidget(hVolumeWidgets);
115116

@@ -683,8 +684,8 @@ void AudioMixer::updateVolumeLayouts()
683684
vMixerScrollArea->setWidgetResizable(false);
684685
hMixerScrollArea->setWidgetResizable(false);
685686

687+
QSize minimumSize{};
686688
for (const auto &entry : rankedVolumes) {
687-
688689
VolumeControl *volControl = entry.control;
689690
if (!volControl) {
690691
continue;
@@ -712,6 +713,10 @@ void AudioMixer::updateVolumeLayouts()
712713

713714
prevControl = volControl;
714715

716+
if (!minimumSize.isValid()) {
717+
minimumSize = volControl->minimumSizeHint();
718+
}
719+
715720
++index;
716721
}
717722

@@ -727,6 +732,9 @@ void AudioMixer::updateVolumeLayouts()
727732
vMixerScrollArea->setWidgetResizable(true);
728733
hMixerScrollArea->setWidgetResizable(true);
729734

735+
int scrollBarSize = QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent);
736+
stackedMixerArea->setMinimumSize(minimumSize.width() + scrollBarSize, minimumSize.height() + scrollBarSize);
737+
730738
setUpdatesEnabled(true);
731739
}
732740

@@ -740,7 +748,6 @@ void AudioMixer::setMixerLayoutVertical(bool vertical)
740748
mixerVertical = vertical;
741749

742750
if (vertical) {
743-
stackedMixerArea->setMinimumSize(180, 220);
744751
stackedMixerArea->setCurrentIndex(1);
745752

746753
QIcon layoutIcon;
@@ -749,7 +756,6 @@ void AudioMixer::setMixerLayoutVertical(bool vertical)
749756
layoutButton->setIcon(layoutIcon);
750757
layoutButton->setToolTip(QTStr("Basic.AudioMixer.Layout.Horizontal"));
751758
} else {
752-
stackedMixerArea->setMinimumSize(220, 0);
753759
stackedMixerArea->setCurrentIndex(0);
754760

755761
QIcon layoutIcon;

0 commit comments

Comments
 (0)