mirror of
https://github.com/obsproject/obs-studio.git
synced 2026-08-24 10:14:13 -05:00
frontend: Implement sizeHint for VolumeMeter
This commit is contained in:
@@ -9,11 +9,15 @@
|
||||
|
||||
#include "moc_VolumeMeter.cpp"
|
||||
|
||||
// Size of the audio indicator in pixels
|
||||
#define INDICATOR_THICKNESS 3
|
||||
|
||||
QPointer<QTimer> VolumeMeter::updateTimer = nullptr;
|
||||
|
||||
namespace {
|
||||
constexpr int INDICATOR_THICKNESS = 3;
|
||||
constexpr int CLIP_FLASH_DURATION_MS = 1000;
|
||||
constexpr int TICK_SIZE = 2;
|
||||
constexpr int TICK_DB_INTERVAL = 6;
|
||||
} // namespace
|
||||
|
||||
static inline QColor color_from_int(long long val)
|
||||
{
|
||||
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)
|
||||
updateBackgroundCache();
|
||||
}
|
||||
|
||||
void VolumeMeter::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
setFocus(Qt::MouseFocusReason);
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void VolumeMeter::wheelEvent(QWheelEvent *event)
|
||||
{
|
||||
QApplication::sendEvent(focusProxy(), event);
|
||||
}
|
||||
|
||||
VolumeMeter::VolumeMeter(QWidget *parent, obs_source_t *source)
|
||||
: QWidget(parent),
|
||||
weakSource(OBSGetWeakRef(source)),
|
||||
@@ -348,7 +341,7 @@ VolumeMeter::VolumeMeter(QWidget *parent, obs_source_t *source)
|
||||
repaint();
|
||||
});
|
||||
|
||||
connect(App(), &OBSApp::StyleChanged, this, &VolumeMeter::updateBackgroundCache);
|
||||
connect(App(), &OBSApp::StyleChanged, this, &VolumeMeter::doLayout);
|
||||
}
|
||||
|
||||
VolumeMeter::~VolumeMeter()
|
||||
@@ -419,10 +412,10 @@ bool VolumeMeter::needLayoutChange()
|
||||
|
||||
if (displayNrAudioChannels != currentNrAudioChannels) {
|
||||
displayNrAudioChannels = currentNrAudioChannels;
|
||||
recalculateLayout = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return recalculateLayout;
|
||||
return false;
|
||||
}
|
||||
|
||||
void VolumeMeter::setVertical(bool vertical_)
|
||||
@@ -465,6 +458,18 @@ void VolumeMeter::refreshColors()
|
||||
updateBackgroundCache();
|
||||
}
|
||||
|
||||
QRect VolumeMeter::getBarRect() const
|
||||
{
|
||||
QRect barRect = rect();
|
||||
if (vertical) {
|
||||
barRect.setWidth(displayNrAudioChannels * (meterThickness + 1) - 1);
|
||||
} else {
|
||||
barRect.setHeight(displayNrAudioChannels * (meterThickness + 1) - 1);
|
||||
}
|
||||
|
||||
return barRect;
|
||||
}
|
||||
|
||||
// When this is called from the constructor, obs_volmeter_get_nr_channels has not
|
||||
// yet been called and Q_PROPERTY settings have not yet been read from the
|
||||
// stylesheet.
|
||||
@@ -476,28 +481,19 @@ inline void VolumeMeter::doLayout()
|
||||
int meterSize = std::floor(22 / displayNrAudioChannels);
|
||||
meterThickness = std::clamp(meterSize, 3, 6);
|
||||
}
|
||||
recalculateLayout = false;
|
||||
|
||||
tickFont = font();
|
||||
QFontInfo info(tickFont);
|
||||
tickFont.setPointSizeF(info.pointSizeF() * meterFontScaling);
|
||||
QFontMetrics metrics(tickFont);
|
||||
if (vertical) {
|
||||
// Each meter channel is meterThickness pixels wide, plus one pixel
|
||||
// between channels, but not after the last.
|
||||
// Add 4 pixels for ticks, space to hold our longest label in this font,
|
||||
// and a few pixels before the fader.
|
||||
QRect scaleBounds = metrics.boundingRect("-88");
|
||||
setMinimumSize(displayNrAudioChannels * (meterThickness + 1) - 1 + 10 + scaleBounds.width() + 2, 100);
|
||||
} else {
|
||||
// Each meter channel is meterThickness pixels high, plus one pixel
|
||||
// between channels, but not after the last.
|
||||
// Add 4 pixels for ticks, and space high enough to hold our label in
|
||||
// this font, presuming that digits don't have descenders.
|
||||
setMinimumSize(100, displayNrAudioChannels * (meterThickness + 1) - 1 + 4 + metrics.capHeight());
|
||||
}
|
||||
|
||||
QFontMetrics metrics(tickFont);
|
||||
// This is a quick and naive assumption for widest potential tick label.
|
||||
tickTextTokenRect = metrics.boundingRect(" -88 ");
|
||||
|
||||
updateBackgroundCache();
|
||||
resetLevels();
|
||||
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
inline bool VolumeMeter::detectIdle(uint64_t ts)
|
||||
@@ -607,7 +603,7 @@ void VolumeMeter::paintHTicks(QPainter &painter, int x, int y, int width)
|
||||
painter.setPen(majorTickColor);
|
||||
|
||||
// Draw major tick lines and numeric indicators.
|
||||
for (int i = 0; i >= minimumLevel; i -= 6) {
|
||||
for (int i = 0; i >= minimumLevel; i -= TICK_DB_INTERVAL) {
|
||||
int position = int(x + width - (i * scale) - 1);
|
||||
QString str = QString::number(i);
|
||||
|
||||
@@ -624,7 +620,7 @@ void VolumeMeter::paintHTicks(QPainter &painter, int x, int y, int width)
|
||||
}
|
||||
painter.drawText(pos, y + 4 + metrics.capHeight(), str);
|
||||
|
||||
painter.drawLine(position, y, position, y + 2);
|
||||
painter.drawLine(position, y, position, y + TICK_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -637,7 +633,7 @@ void VolumeMeter::paintVTicks(QPainter &painter, int x, int y, int height)
|
||||
painter.setPen(majorTickColor);
|
||||
|
||||
// Draw major tick lines and numeric indicators.
|
||||
for (int i = 0; i >= minimumLevel; i -= 6) {
|
||||
for (int i = 0; i >= minimumLevel; i -= TICK_DB_INTERVAL) {
|
||||
int position = y + int(i * scale);
|
||||
QString str = QString::number(i);
|
||||
|
||||
@@ -648,12 +644,24 @@ void VolumeMeter::paintVTicks(QPainter &painter, int x, int y, int height)
|
||||
painter.drawText(x + 8, position + (metrics.capHeight() / 2), str);
|
||||
}
|
||||
|
||||
painter.drawLine(x, position, x + 2, position);
|
||||
painter.drawLine(x, position, x + TICK_SIZE, position);
|
||||
}
|
||||
}
|
||||
|
||||
void VolumeMeter::updateBackgroundCache()
|
||||
{
|
||||
if (!size().isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (backgroundCache.size() == size() && !backgroundCache.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (displayNrAudioChannels <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
QColor backgroundColor = palette().color(QPalette::Window);
|
||||
|
||||
backgroundCache = QPixmap(size() * devicePixelRatioF());
|
||||
@@ -705,8 +713,6 @@ void VolumeMeter::updateBackgroundCache()
|
||||
}
|
||||
}
|
||||
|
||||
#define CLIP_FLASH_DURATION_MS 1000
|
||||
|
||||
inline int VolumeMeter::convertToInt(float number)
|
||||
{
|
||||
constexpr int min = std::numeric_limits<int>::min();
|
||||
@@ -743,9 +749,6 @@ void VolumeMeter::paintEvent(QPaintEvent *)
|
||||
const qreal scale = meterLength / minimumLevel;
|
||||
|
||||
// Paint cached background pixmap
|
||||
if (backgroundCache.isNull() || backgroundCache.size() != size()) {
|
||||
updateBackgroundCache();
|
||||
}
|
||||
painter.drawPixmap(0, 0, backgroundCache);
|
||||
|
||||
// Draw dynamic audio meter bars
|
||||
@@ -849,23 +852,42 @@ void VolumeMeter::paintEvent(QPaintEvent *)
|
||||
lastRedrawTime = ts;
|
||||
}
|
||||
|
||||
QRect VolumeMeter::getBarRect() const
|
||||
void VolumeMeter::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QRect rec = rect();
|
||||
updateBackgroundCache();
|
||||
return QWidget::resizeEvent(event);
|
||||
}
|
||||
|
||||
void VolumeMeter::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
setFocus(Qt::MouseFocusReason);
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void VolumeMeter::wheelEvent(QWheelEvent *event)
|
||||
{
|
||||
QApplication::sendEvent(focusProxy(), event);
|
||||
}
|
||||
|
||||
QSize VolumeMeter::minimumSizeHint() const
|
||||
{
|
||||
return sizeHint();
|
||||
}
|
||||
|
||||
QSize VolumeMeter::sizeHint() const
|
||||
{
|
||||
QRect meterRect = getBarRect();
|
||||
int labelTotal = std::abs(minimumLevel / TICK_DB_INTERVAL) + 1;
|
||||
|
||||
if (vertical) {
|
||||
rec.setWidth(displayNrAudioChannels * (meterThickness + 1) - 1);
|
||||
int width = meterRect.width() + tickTextTokenRect.width() + TICK_SIZE + 10;
|
||||
int height = (labelTotal * tickTextTokenRect.height()) + INDICATOR_THICKNESS;
|
||||
|
||||
return QSize(width, height * 1.1);
|
||||
} else {
|
||||
rec.setHeight(displayNrAudioChannels * (meterThickness + 1) - 1);
|
||||
int width = (labelTotal * tickTextTokenRect.width()) + INDICATOR_THICKNESS;
|
||||
int height = meterRect.height() + tickTextTokenRect.height();
|
||||
|
||||
return QSize(width * 1.1, height);
|
||||
}
|
||||
|
||||
return rec;
|
||||
}
|
||||
|
||||
void VolumeMeter::changeEvent(QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::StyleChange) {
|
||||
recalculateLayout = true;
|
||||
}
|
||||
|
||||
QWidget::changeEvent(e);
|
||||
}
|
||||
|
||||
@@ -69,7 +69,6 @@ private:
|
||||
|
||||
QMutex dataMutex;
|
||||
|
||||
bool recalculateLayout{true};
|
||||
uint64_t currentLastUpdateTime{0};
|
||||
float currentMagnitude[MAX_AUDIO_CHANNELS];
|
||||
float currentPeak[MAX_AUDIO_CHANNELS];
|
||||
@@ -87,6 +86,8 @@ private:
|
||||
void updateBackgroundCache();
|
||||
|
||||
QFont tickFont;
|
||||
QRect tickTextTokenRect;
|
||||
|
||||
QColor backgroundNominalColor;
|
||||
QColor backgroundWarningColor;
|
||||
QColor backgroundErrorColor;
|
||||
@@ -140,7 +141,6 @@ public:
|
||||
|
||||
void setLevels(const float magnitude[MAX_AUDIO_CHANNELS], const float peak[MAX_AUDIO_CHANNELS],
|
||||
const float inputPeak[MAX_AUDIO_CHANNELS]);
|
||||
QRect getBarRect() const;
|
||||
bool needLayoutChange();
|
||||
|
||||
void setVertical(bool vertical = true);
|
||||
@@ -148,6 +148,7 @@ public:
|
||||
void setMuted(bool mute);
|
||||
|
||||
void refreshColors();
|
||||
QRect getBarRect() const;
|
||||
|
||||
QColor getBackgroundNominalColor() const;
|
||||
void setBackgroundNominalColor(QColor c);
|
||||
@@ -190,12 +191,15 @@ public:
|
||||
void setPeakDecayRate(qreal v);
|
||||
void setPeakMeterType(enum obs_peak_meter_type peakMeterType);
|
||||
|
||||
virtual void resizeEvent(QResizeEvent *event) override;
|
||||
virtual void mousePressEvent(QMouseEvent *event) override;
|
||||
virtual void wheelEvent(QWheelEvent *event) override;
|
||||
|
||||
QSize minimumSizeHint() const override;
|
||||
QSize sizeHint() const override;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void changeEvent(QEvent *e) override;
|
||||
|
||||
private slots:
|
||||
void handleSourceDestroyed() { deleteLater(); }
|
||||
|
||||
@@ -110,6 +110,7 @@ AudioMixer::AudioMixer(QWidget *parent) : QFrame(parent)
|
||||
hVolumeWidgets->setLayout(hVolumeControlLayout);
|
||||
hVolumeControlLayout->setContentsMargins(0, 0, 0, 0);
|
||||
hVolumeControlLayout->setSpacing(0);
|
||||
hVolumeControlLayout->setAlignment(Qt::AlignTop);
|
||||
|
||||
hMixerScrollArea->setWidget(hVolumeWidgets);
|
||||
|
||||
@@ -683,8 +684,8 @@ void AudioMixer::updateVolumeLayouts()
|
||||
vMixerScrollArea->setWidgetResizable(false);
|
||||
hMixerScrollArea->setWidgetResizable(false);
|
||||
|
||||
QSize minimumSize{};
|
||||
for (const auto &entry : rankedVolumes) {
|
||||
|
||||
VolumeControl *volControl = entry.control;
|
||||
if (!volControl) {
|
||||
continue;
|
||||
@@ -712,6 +713,10 @@ void AudioMixer::updateVolumeLayouts()
|
||||
|
||||
prevControl = volControl;
|
||||
|
||||
if (!minimumSize.isValid()) {
|
||||
minimumSize = volControl->minimumSizeHint();
|
||||
}
|
||||
|
||||
++index;
|
||||
}
|
||||
|
||||
@@ -727,6 +732,9 @@ void AudioMixer::updateVolumeLayouts()
|
||||
vMixerScrollArea->setWidgetResizable(true);
|
||||
hMixerScrollArea->setWidgetResizable(true);
|
||||
|
||||
int scrollBarSize = QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent);
|
||||
stackedMixerArea->setMinimumSize(minimumSize.width() + scrollBarSize, minimumSize.height() + scrollBarSize);
|
||||
|
||||
setUpdatesEnabled(true);
|
||||
}
|
||||
|
||||
@@ -740,7 +748,6 @@ void AudioMixer::setMixerLayoutVertical(bool vertical)
|
||||
mixerVertical = vertical;
|
||||
|
||||
if (vertical) {
|
||||
stackedMixerArea->setMinimumSize(180, 220);
|
||||
stackedMixerArea->setCurrentIndex(1);
|
||||
|
||||
QIcon layoutIcon;
|
||||
@@ -749,7 +756,6 @@ void AudioMixer::setMixerLayoutVertical(bool vertical)
|
||||
layoutButton->setIcon(layoutIcon);
|
||||
layoutButton->setToolTip(QTStr("Basic.AudioMixer.Layout.Horizontal"));
|
||||
} else {
|
||||
stackedMixerArea->setMinimumSize(220, 0);
|
||||
stackedMixerArea->setCurrentIndex(0);
|
||||
|
||||
QIcon layoutIcon;
|
||||
|
||||
Reference in New Issue
Block a user