changeset 1186:8665e0ffa0d8 levelpanwidget

Merge from branch 3.0-integration
author Chris Cannam
date Wed, 14 Dec 2016 14:28:41 +0000
parents 6a6a63506e3f (diff) f32828ea63d9 (current diff)
children 306c24eeab10
files
diffstat 13 files changed, 272 insertions(+), 163 deletions(-) [+]
line wrap: on
line diff
--- a/files.pri	Wed Dec 14 11:56:47 2016 +0000
+++ b/files.pri	Wed Dec 14 14:28:41 2016 +0000
@@ -80,6 +80,7 @@
            widgets/TipDialog.h \
            widgets/TransformFinder.h \
            widgets/UnitConverter.h \
+           widgets/WidgetScale.h \
            widgets/WindowShapePreview.h \
            widgets/WindowTypeSelector.h
 
--- a/widgets/LEDButton.cpp	Wed Dec 14 11:56:47 2016 +0000
+++ b/widgets/LEDButton.cpp	Wed Dec 14 14:28:41 2016 +0000
@@ -23,6 +23,7 @@
 
 
 #include "LEDButton.h"
+#include "WidgetScale.h"
 
 #include <QPainter>
 #include <QImage>
@@ -279,12 +280,12 @@
 QSize
 LEDButton::sizeHint() const
 {
-    return QSize(17, 17);
+    return WidgetScale::scaleQSize(QSize(17, 17));
 }
 
 QSize
 LEDButton::minimumSizeHint() const
 {
-    return QSize(17, 17);
+    return WidgetScale::scaleQSize(QSize(17, 17));
 }
 
--- a/widgets/LEDButton.h	Wed Dec 14 11:56:47 2016 +0000
+++ b/widgets/LEDButton.h	Wed Dec 14 14:28:41 2016 +0000
@@ -25,8 +25,8 @@
     sunken variant.  This version also implements a simple button API.
 */
 
-#ifndef _LED_BUTTON_H_
-#define _LED_BUTTON_H_
+#ifndef SV_LED_BUTTON_H
+#define SV_LED_BUTTON_H
 
 #include <QWidget>
 #include "base/Debug.h"
--- a/widgets/LevelPanToolButton.cpp	Wed Dec 14 11:56:47 2016 +0000
+++ b/widgets/LevelPanToolButton.cpp	Wed Dec 14 14:28:41 2016 +0000
@@ -170,4 +170,18 @@
     m_lpw->renderTo(this, QRectF(margin, margin, m_pixels, m_pixels), false);
 }
 
+void
+LevelPanToolButton::enterEvent(QEvent *e)
+{
+    QToolButton::enterEvent(e);
+    emit mouseEntered();
+}
 
+void
+LevelPanToolButton::leaveEvent(QEvent *e)
+{
+    QToolButton::enterEvent(e);
+    emit mouseLeft();
+}
+
+
--- a/widgets/LevelPanToolButton.h	Wed Dec 14 11:56:47 2016 +0000
+++ b/widgets/LevelPanToolButton.h	Wed Dec 14 14:28:41 2016 +0000
@@ -56,12 +56,17 @@
     void levelChanged(float);
     void panChanged(float);
 
+    void mouseEntered();
+    void mouseLeft();
+
 private slots:
     void selfLevelChanged(float);
     void selfClicked();
     
 protected:
-    void paintEvent(QPaintEvent *);
+    virtual void paintEvent(QPaintEvent *);
+    virtual void enterEvent(QEvent *);
+    virtual void leaveEvent(QEvent *);
     
     LevelPanWidget *m_lpw;
     int m_pixels;
--- a/widgets/LevelPanWidget.cpp	Wed Dec 14 11:56:47 2016 +0000
+++ b/widgets/LevelPanWidget.cpp	Wed Dec 14 14:28:41 2016 +0000
@@ -21,6 +21,8 @@
 #include "layer/ColourMapper.h"
 #include "base/AudioLevel.h"
 
+#include "WidgetScale.h"
+
 #include <iostream>
 #include <cmath>
 #include <cassert>
@@ -35,6 +37,8 @@
     QWidget(parent),
     m_level(maxLevel),
     m_pan(0),
+    m_monitorLeft(-1),
+    m_monitorRight(-1),
     m_editable(true),
     m_includeMute(true)
 {
@@ -47,22 +51,7 @@
 QSize
 LevelPanWidget::sizeHint() const
 {
-    static double ratio = 0.0;
-    if (ratio == 0.0) {
-        double baseEm;
-#ifdef Q_OS_MAC
-        baseEm = 17.0;
-#else
-        baseEm = 15.0;
-#endif
-        double em = QFontMetrics(QFont()).height();
-        ratio = em / baseEm;
-    }
-
-    int pixels = 40;
-    int scaled = int(pixels * ratio + 0.5);
-    if (pixels != 0 && scaled == 0) scaled = 1;
-    return QSize(scaled, scaled);
+    return WidgetScale::scaleQSize(QSize(40, 40));
 }
 
 static int
@@ -91,18 +80,36 @@
     else return -20.;
 }
 
+int
+LevelPanWidget::audioLevelToLevel(float audioLevel, bool withMute)
+{
+    int level;
+    if (withMute) {
+        level = AudioLevel::multiplier_to_fader
+            (audioLevel, maxLevel, AudioLevel::ShortFader);
+    } else {
+        level = db_to_level(AudioLevel::multiplier_to_dB(audioLevel));
+    }
+    if (level < 0) level = 0;
+    if (level > maxLevel) level = maxLevel;
+    return level;
+}
+
+float
+LevelPanWidget::levelToAudioLevel(int level, bool withMute)
+{
+    if (withMute) {
+        return float(AudioLevel::fader_to_multiplier
+                     (level, maxLevel, AudioLevel::ShortFader));
+    } else {
+        return float(AudioLevel::dB_to_multiplier(level_to_db(level)));
+    }
+}
+
 void
 LevelPanWidget::setLevel(float flevel)
 {
-    int level;
-    if (m_includeMute) {
-        level = AudioLevel::multiplier_to_fader
-            (flevel, maxLevel, AudioLevel::ShortFader);
-    } else {
-        level = db_to_level(AudioLevel::multiplier_to_dB(flevel));
-    }
-    if (level < 0) level = 0;
-    if (level > maxLevel) level = maxLevel;
+    int level = audioLevelToLevel(flevel, m_includeMute);
     if (level != m_level) {
 	m_level = level;
 	float convertsTo = getLevel();
@@ -116,20 +123,45 @@
 float
 LevelPanWidget::getLevel() const
 {
-    if (m_includeMute) {
-        return float(AudioLevel::fader_to_multiplier
-                     (m_level, maxLevel, AudioLevel::ShortFader));
-    } else {
-        return float(AudioLevel::dB_to_multiplier(level_to_db(m_level)));
+    return levelToAudioLevel(m_level, m_includeMute);
+}
+
+int
+LevelPanWidget::audioPanToPan(float audioPan)
+{
+    int pan = int(round(audioPan * maxPan));
+    if (pan < -maxPan) pan = -maxPan;
+    if (pan > maxPan) pan = maxPan;
+    return pan;
+}
+
+float
+LevelPanWidget::panToAudioPan(int pan)
+{
+    return float(pan) / float(maxPan);
+}
+
+void
+LevelPanWidget::setPan(float fpan)
+{
+    int pan = audioPanToPan(fpan);
+    if (pan != m_pan) {
+        m_pan = pan;
+        update();
     }
 }
 
+float
+LevelPanWidget::getPan() const
+{
+    return panToAudioPan(m_pan);
+}
+
 void
-LevelPanWidget::setPan(float pan)
+LevelPanWidget::setMonitoringLevels(float left, float right)
 {
-    m_pan = int(round(pan * maxPan));
-    if (m_pan < -maxPan) m_pan = -maxPan;
-    if (m_pan > maxPan) m_pan = maxPan;
+    m_monitorLeft = left;
+    m_monitorRight = right;
     update();
 }
 
@@ -160,12 +192,6 @@
     update();
 }
 
-float
-LevelPanWidget::getPan() const
-{
-    return float(m_pan) / float(maxPan);
-}
-
 void
 LevelPanWidget::emitLevelChanged()
 {
@@ -338,11 +364,33 @@
     pen.setWidthF(cellLightSize(rect).width() + thin);
     pen.setCapStyle(Qt::RoundCap);
     paint.setPen(pen);
+    paint.setBrush(Qt::NoBrush);
 
     for (int pan = -maxPan; pan <= maxPan; ++pan) {
 	paint.drawLine(cellCentre(rect, 0, pan), cellCentre(rect, maxLevel, pan));
     }
 
+    if (m_monitorLeft > 0.f || m_monitorRight > 0.f) {
+        paint.setPen(Qt::NoPen);
+        for (int pan = -maxPan; pan <= maxPan; ++pan) {
+            float audioPan = panToAudioPan(pan);
+            float audioLevel;
+            if (audioPan < 0.f) {
+                audioLevel = m_monitorLeft + m_monitorRight * (1.f + audioPan);
+            } else {
+                audioLevel = m_monitorRight + m_monitorLeft * (1.f - audioPan);
+            }
+            int levelHere = audioLevelToLevel(audioLevel, false);
+            for (int level = 0; level <= levelHere; ++level) {
+                paint.setBrush(level_to_colour(level));
+                QRectF clr = cellLightRect(rect, level, pan);
+                paint.drawEllipse(clr);
+            }
+        }
+        paint.setPen(pen);
+        paint.setBrush(Qt::NoBrush);
+    }
+    
     if (isEnabled()) {
 	pen.setColor(Qt::black);
     } else {
@@ -384,5 +432,17 @@
     renderTo(this, rect(), m_editable);
 }
 
+void
+LevelPanWidget::enterEvent(QEvent *e)
+{
+    QWidget::enterEvent(e);
+    emit mouseEntered();
+}
 
+void
+LevelPanWidget::leaveEvent(QEvent *e)
+{
+    QWidget::enterEvent(e);
+    emit mouseLeft();
+}
 
--- a/widgets/LevelPanWidget.h	Wed Dec 14 11:56:47 2016 +0000
+++ b/widgets/LevelPanWidget.h	Wed Dec 14 14:28:41 2016 +0000
@@ -53,6 +53,9 @@
     /// Set pan in the range [-1,1] -- will be rounded
     void setPan(float);
 
+    /// Set left and right peak monitoring levels in the range [0,1]
+    void setMonitoringLevels(float, float);
+    
     /// Specify whether the widget is editable or read-only (default editable)
     void setEditable(bool);
 
@@ -60,24 +63,37 @@
     void setIncludeMute(bool);
     
 signals:
-    void levelChanged(float);
-    void panChanged(float);
+    void levelChanged(float); // range [0,1]
+    void panChanged(float); // range [-1,1]
 
+    void mouseEntered();
+    void mouseLeft();
+    
 protected:
     virtual void mousePressEvent(QMouseEvent *ev);
     virtual void mouseMoveEvent(QMouseEvent *ev);
     virtual void mouseReleaseEvent(QMouseEvent *ev);
     virtual void wheelEvent(QWheelEvent *ev);
     virtual void paintEvent(QPaintEvent *ev);
+    virtual void enterEvent(QEvent *);
+    virtual void leaveEvent(QEvent *);
 
     void emitLevelChanged();
     void emitPanChanged();
     
     int m_level;
     int m_pan;
+    float m_monitorLeft;
+    float m_monitorRight;
     bool m_editable;
     bool m_includeMute;
 
+    static int audioLevelToLevel(float audioLevel, bool withMute);
+    static float levelToAudioLevel(int level, bool withMute);
+
+    static int audioPanToPan(float audioPan);
+    static float panToAudioPan(int pan);
+    
     QSizeF cellSize(QRectF) const;
     QPointF cellCentre(QRectF, int level, int pan) const;
     QSizeF cellLightSize(QRectF) const;
--- a/widgets/ModelDataTableDialog.cpp	Wed Dec 14 11:56:47 2016 +0000
+++ b/widgets/ModelDataTableDialog.cpp	Wed Dec 14 14:28:41 2016 +0000
@@ -61,7 +61,7 @@
 
     toolbar = addToolBar(tr("Edit Toolbar"));
 
-    action = new QAction(il.load("datainsert"), tr("Insert New Item"), this);
+    action = new QAction(il.load("draw"), tr("Insert New Item"), this);
     action->setShortcut(tr("Insert"));
     action->setStatusTip(tr("Insert a new item"));
     connect(action, SIGNAL(triggered()), this, SLOT(insertRow()));
--- a/widgets/NotifyingPushButton.h	Wed Dec 14 11:56:47 2016 +0000
+++ b/widgets/NotifyingPushButton.h	Wed Dec 14 14:28:41 2016 +0000
@@ -26,8 +26,8 @@
 class NotifyingPushButton : public QPushButton
 {
     Q_OBJECT
+
 public:
-
     NotifyingPushButton(QWidget *parent = 0) :
         QPushButton(parent) { }
 
--- a/widgets/PropertyBox.cpp	Wed Dec 14 11:56:47 2016 +0000
+++ b/widgets/PropertyBox.cpp	Wed Dec 14 14:28:41 2016 +0000
@@ -27,6 +27,9 @@
 #include "AudioDial.h"
 #include "LEDButton.h"
 #include "IconLoader.h"
+#include "LevelPanWidget.h"
+#include "LevelPanToolButton.h"
+#include "WidgetScale.h"
 
 #include "NotifyingCheckBox.h"
 #include "NotifyingComboBox.h"
@@ -174,14 +177,44 @@
     
     if (params) {
 
-	QLabel *playLabel = new QLabel(tr("Play"));
-	layout->addWidget(playLabel);
-	layout->setAlignment(playLabel, Qt::AlignVCenter);
+	layout->insertStretch(-1, 10);
 
-	m_playButton = new LEDButton(Qt::darkGreen);
-        m_playButton->setState(!params->isPlayMuted());
+        if (params->getPlayClipId() != "") {
+            NotifyingPushButton *playParamButton = new NotifyingPushButton;
+            playParamButton->setObjectName("playParamButton");
+            playParamButton->setIcon(IconLoader().load("faders"));
+            playParamButton->setFixedWidth(WidgetScale::scalePixelSize(24));
+            playParamButton->setFixedHeight(WidgetScale::scalePixelSize(24));
+            layout->addWidget(playParamButton);
+            connect(playParamButton, SIGNAL(clicked()),
+                    this, SLOT(editPlayParameters()));
+            connect(playParamButton, SIGNAL(mouseEntered()),
+                    this, SLOT(mouseEnteredWidget()));
+            connect(playParamButton, SIGNAL(mouseLeft()),
+                    this, SLOT(mouseLeftWidget()));
+        }
+
+        LevelPanToolButton *levelPan = new LevelPanToolButton;
+        layout->addWidget(levelPan);
+        connect(levelPan, SIGNAL(levelChanged(float)),
+                this, SLOT(playGainControlChanged(float)));
+        connect(levelPan, SIGNAL(panChanged(float)),
+                this, SLOT(playPanControlChanged(float)));
+        connect(params, SIGNAL(playGainChanged(float)),
+                levelPan, SLOT(setLevel(float)));
+        connect(params, SIGNAL(playPanChanged(float)),
+                levelPan, SLOT(setPan(float)));
+        connect(levelPan, SIGNAL(mouseEntered()),
+                this, SLOT(mouseEnteredWidget()));
+        connect(levelPan, SIGNAL(mouseLeft()),
+                this, SLOT(mouseLeftWidget()));
+
+        m_playButton = new NotifyingPushButton;
+        m_playButton->setCheckable(true);
+        m_playButton->setIcon(IconLoader().load("speaker"));
+        m_playButton->setChecked(!params->isPlayMuted());
 	layout->addWidget(m_playButton);
-	connect(m_playButton, SIGNAL(stateChanged(bool)),
+	connect(m_playButton, SIGNAL(toggled(bool)),
 		this, SLOT(playAudibleButtonChanged(bool)));
         connect(m_playButton, SIGNAL(mouseEntered()),
                 this, SLOT(mouseEnteredWidget()));
@@ -191,71 +224,6 @@
 		this, SLOT(playAudibleChanged(bool)));
 	layout->setAlignment(m_playButton, Qt::AlignVCenter);
 
-	layout->insertStretch(-1, 10);
-
-        if (params->getPlayClipId() != "") {
-            QPushButton *playParamButton =
-                new QPushButton(QIcon(":icons/faders.png"), "");
-            playParamButton->setFixedWidth(24);
-            playParamButton->setFixedHeight(24);
-            layout->addWidget(playParamButton);
-            connect(playParamButton, SIGNAL(clicked()),
-                    this, SLOT(editPlayParameters()));
-        }
-
-	AudioDial *gainDial = new AudioDial;
-	layout->addWidget(gainDial);
-	gainDial->setMeterColor(Qt::darkRed);
-	gainDial->setMinimum(-50);
-	gainDial->setMaximum(50);
-	gainDial->setPageStep(1);
-	gainDial->setFixedWidth(24);
-	gainDial->setFixedHeight(24);
-	gainDial->setNotchesVisible(false);
-        gainDial->setObjectName(tr("Playback Gain"));
-        gainDial->setRangeMapper(new LinearRangeMapper
-                                 (-50, 50, -25, 25, tr("dB")));
-	gainDial->setDefaultValue(0);
-        gainDial->setShowToolTip(true);
-	connect(gainDial, SIGNAL(valueChanged(int)),
-		this, SLOT(playGainDialChanged(int)));
-	connect(params, SIGNAL(playGainChanged(float)),
-		this, SLOT(playGainChanged(float)));
-	connect(this, SIGNAL(changePlayGainDial(int)),
-		gainDial, SLOT(setValue(int)));
-        connect(gainDial, SIGNAL(mouseEntered()),
-                this, SLOT(mouseEnteredWidget()));
-        connect(gainDial, SIGNAL(mouseLeft()),
-                this, SLOT(mouseLeftWidget()));
-        playGainChanged(params->getPlayGain());
-	layout->setAlignment(gainDial, Qt::AlignVCenter);
-
-	AudioDial *panDial = new AudioDial;
-	layout->addWidget(panDial);
-	panDial->setMeterColor(Qt::darkGreen);
-	panDial->setMinimum(-50);
-	panDial->setMaximum(50);
-	panDial->setPageStep(1);
-	panDial->setFixedWidth(24);
-	panDial->setFixedHeight(24);
-	panDial->setNotchesVisible(false);
-	panDial->setToolTip(tr("Playback Pan / Balance"));
-	panDial->setDefaultValue(0);
-        panDial->setObjectName(tr("Playback Pan / Balance"));
-        panDial->setShowToolTip(true);
-	connect(panDial, SIGNAL(valueChanged(int)),
-		this, SLOT(playPanDialChanged(int)));
-	connect(params, SIGNAL(playPanChanged(float)),
-		this, SLOT(playPanChanged(float)));
-	connect(this, SIGNAL(changePlayPanDial(int)),
-		panDial, SLOT(setValue(int)));
-        connect(panDial, SIGNAL(mouseEntered()),
-                this, SLOT(mouseEnteredWidget()));
-        connect(panDial, SIGNAL(mouseLeft()),
-                this, SLOT(mouseLeftWidget()));
-        playPanChanged(params->getPlayPan());
-	layout->setAlignment(panDial, Qt::AlignVCenter);
-
     } else {
 
 	layout->insertStretch(-1, 10);
@@ -330,7 +298,7 @@
                 QIcon icon(IconLoader().load(iconName));
                 button->setIcon(icon);
                 button->setObjectName(name);
-                button->setFixedSize(QSize(18, 18));
+                button->setFixedSize(WidgetScale::scaleQSize(QSize(18, 18)));
             } else {
                 button = new NotifyingCheckBox();
                 button->setObjectName(name);
@@ -397,13 +365,13 @@
                     this, SLOT(mouseLeftWidget()));
 
 	    if (inGroup) {
-		dial->setFixedWidth(24);
-		dial->setFixedHeight(24);
+		dial->setFixedWidth(WidgetScale::scalePixelSize(24));
+		dial->setFixedHeight(WidgetScale::scalePixelSize(24));
 		m_groupLayouts[groupName]->addWidget
                     (dial, 0, m_groupLayouts[groupName]->columnCount());
 	    } else {
-		dial->setFixedWidth(32);
-		dial->setFixedHeight(32);
+		dial->setFixedWidth(WidgetScale::scalePixelSize(32));
+		dial->setFixedHeight(WidgetScale::scalePixelSize(32));
 		m_layout->addWidget(dial, row, 1);
 		QLabel *label = new QLabel(m_mainWidget);
 		connect(dial, SIGNAL(valueChanged(int)),
@@ -691,7 +659,7 @@
 void
 PropertyBox::playAudibleChanged(bool audible)
 {
-    m_playButton->setState(audible);
+    m_playButton->setChecked(audible);
 }
 
 void
@@ -707,26 +675,15 @@
         CommandHistory::getInstance()->addCommand(command, true, true);
     }
 }
-    
-void
-PropertyBox::playGainChanged(float gain)
-{
-    int dialValue = int(lrint(log10(gain) * 20.0));
-    if (dialValue < -50) dialValue = -50;
-    if (dialValue >  50) dialValue =  50;
-    emit changePlayGainDial(dialValue);
-}
 
 void
-PropertyBox::playGainDialChanged(int dialValue)
+PropertyBox::playGainControlChanged(float gain)
 {
     QObject *obj = sender();
 
     PlayParameters *params = m_container->getPlayParameters();
     if (!params) return;
 
-    float gain = float(pow(10, float(dialValue) / 20.0));
-
     if (params->getPlayGain() != gain) {
         PlayParameterRepository::EditCommand *command =
             new PlayParameterRepository::EditCommand(params);
@@ -736,28 +693,15 @@
 
     updateContextHelp(obj);
 }
-    
-void
-PropertyBox::playPanChanged(float pan)
-{
-    int dialValue = int(lrint(pan * 50.0));
-    if (dialValue < -50) dialValue = -50;
-    if (dialValue >  50) dialValue =  50;
-    emit changePlayPanDial(dialValue);
-}
 
 void
-PropertyBox::playPanDialChanged(int dialValue)
+PropertyBox::playPanControlChanged(float pan)
 {
     QObject *obj = sender();
 
     PlayParameters *params = m_container->getPlayParameters();
     if (!params) return;
 
-    float pan = float(dialValue) / 50.f;
-    if (pan < -1.f) pan = -1.f;
-    if (pan >  1.f) pan =  1.f;
-
     if (params->getPlayPan() != pan) {
         PlayParameterRepository::EditCommand *command =
             new PlayParameterRepository::EditCommand(params);
@@ -849,10 +793,27 @@
     QString cname = m_container->getPropertyContainerName();
     if (cname == "") return;
 
+    LevelPanToolButton *lp = qobject_cast<LevelPanToolButton *>(w);
+    if (lp) {
+        emit contextHelpChanged(tr("Adjust playback level and pan of %1").arg(cname));
+        return;
+    }
+
     QString wname = w->objectName();
 
+    if (wname == "playParamButton") {
+        PlayParameters *params = m_container->getPlayParameters();
+        if (params) {
+            emit contextHelpChanged
+                (tr("Change sound used for playback (currently \"%1\")")
+                 .arg(params->getPlayClipId()));
+            return;
+        }
+    }
+    
     QString extraText;
-    AudioDial *dial = dynamic_cast<AudioDial *>(w);
+    
+    AudioDial *dial = qobject_cast<AudioDial *>(w);
     if (dial) {
         double mv = dial->mappedValue();
         QString unit = "";
--- a/widgets/PropertyBox.h	Wed Dec 14 11:56:47 2016 +0000
+++ b/widgets/PropertyBox.h	Wed Dec 14 14:28:41 2016 +0000
@@ -27,6 +27,7 @@
 class QVBoxLayout;
 class QLabel;
 class LEDButton;
+class NotifyingPushButton;
 
 class PropertyBox : public QFrame
 {
@@ -39,8 +40,6 @@
     PropertyContainer *getContainer() { return m_container; }
 
 signals:
-    void changePlayGainDial(int);
-    void changePlayPanDial(int);
     void showLayer(bool);
     void contextHelpChanged(const QString &);
 
@@ -56,10 +55,8 @@
 
     void playAudibleChanged(bool);
     void playAudibleButtonChanged(bool);
-    void playGainChanged(float);
-    void playGainDialChanged(int);
-    void playPanChanged(float);
-    void playPanDialChanged(int);
+    void playGainControlChanged(float);
+    void playPanControlChanged(float);
 
     void populateViewPlayFrame();
 
@@ -84,7 +81,7 @@
     QFrame *m_viewPlayFrame;
     QVBoxLayout *m_mainBox;
     LEDButton *m_showButton;
-    LEDButton *m_playButton;
+    NotifyingPushButton *m_playButton;
     std::map<QString, QGridLayout *> m_groupLayouts;
     std::map<QString, QWidget *> m_propertyControllers;
 };
--- a/widgets/PropertyStack.cpp	Wed Dec 14 11:56:47 2016 +0000
+++ b/widgets/PropertyStack.cpp	Wed Dec 14 14:28:41 2016 +0000
@@ -25,6 +25,8 @@
 #include "widgets/CommandHistory.h"
 #include "layer/ShowLayerCommand.h"
 
+#include "WidgetScale.h"
+
 #include <QIcon>
 #include <QTabWidget>
 
@@ -45,11 +47,9 @@
 
     setTabBar(bar);
 
-#if (QT_VERSION >= 0x0402)
     setElideMode(Qt::ElideNone); 
     tabBar()->setUsesScrollButtons(true); 
-    tabBar()->setIconSize(QSize(16, 16));
-#endif
+    tabBar()->setIconSize(WidgetScale::scaleQSize(QSize(16, 16)));
 
     repopulate();
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/widgets/WidgetScale.h	Wed Dec 14 14:28:41 2016 +0000
@@ -0,0 +1,54 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#ifndef SV_WIDGET_SCALE_H
+#define SV_WIDGET_SCALE_H
+
+#include <QFont>
+#include <QFontMetrics>
+
+class WidgetScale
+{
+public:   
+    /**
+     * Take a "design pixel" size and scale it for the actual
+     * display. This is relevant to hi-dpi systems that do not do
+     * pixel doubling (i.e. Windows and Linux rather than OS/X).
+     */
+    static int scalePixelSize(int pixels) {
+
+        static double ratio = 0.0;
+        if (ratio == 0.0) {
+            double baseEm;
+#ifdef Q_OS_MAC
+            baseEm = 17.0;
+#else
+            baseEm = 15.0;
+#endif
+            double em = QFontMetrics(QFont()).height();
+            ratio = em / baseEm;
+        }
+
+        int scaled = int(pixels * ratio + 0.5);
+        if (pixels != 0 && scaled == 0) scaled = 1;
+        return scaled;
+    }
+
+    static QSize scaleQSize(QSize size) {
+        return QSize(scalePixelSize(size.width()),
+                     scalePixelSize(size.height()));
+    }
+};
+
+#endif