changeset 929:20698aa6a517 tonioni

Introduce level/pan toolbar buttons
author Chris Cannam
date Wed, 25 Mar 2015 10:33:19 +0000
parents 3fb91da7d98d
children 86df7de08e03
files svgui.pro widgets/LevelPanToolButton.cpp widgets/LevelPanToolButton.h widgets/LevelPanWidget.cpp widgets/LevelPanWidget.h
diffstat 5 files changed, 231 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/svgui.pro	Tue Mar 24 17:05:42 2015 +0000
+++ b/svgui.pro	Wed Mar 25 10:33:19 2015 +0000
@@ -116,6 +116,7 @@
            widgets/LayerTree.h \
            widgets/LayerTreeDialog.h \
            widgets/LEDButton.h \
+           widgets/LevelPanToolButton.h \
            widgets/LevelPanWidget.h \
            widgets/ListInputDialog.h \
            widgets/MIDIFileImportDialog.h \
@@ -155,6 +156,7 @@
            widgets/LayerTree.cpp \
            widgets/LayerTreeDialog.cpp \
            widgets/LEDButton.cpp \
+           widgets/LevelPanToolButton.cpp \
            widgets/LevelPanWidget.cpp \
            widgets/ListInputDialog.cpp \
            widgets/MIDIFileImportDialog.cpp \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/widgets/LevelPanToolButton.cpp	Wed Mar 25 10:33:19 2015 +0000
@@ -0,0 +1,98 @@
+/* -*- 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.
+*/
+
+#include "LevelPanToolButton.h"
+#include "LevelPanWidget.h"
+
+#include <QMenu>
+#include <QWidgetAction>
+#include <QImage>
+
+#include <iostream>
+using std::cerr;
+using std::endl;
+
+LevelPanToolButton::LevelPanToolButton(QWidget *parent) :
+    QToolButton(parent),
+    m_pixels(32)
+{
+    m_lpw = new LevelPanWidget();
+
+    connect(m_lpw, SIGNAL(levelChanged(float)), this, SIGNAL(levelChanged(float)));
+    connect(m_lpw, SIGNAL(levelChanged(float)), this, SLOT(redraw()));
+
+    connect(m_lpw, SIGNAL(panChanged(float)), this, SIGNAL(panChanged(float)));
+    connect(m_lpw, SIGNAL(panChanged(float)), this, SLOT(redraw()));
+    
+    QMenu *menu = new QMenu();
+    QWidgetAction *wa = new QWidgetAction(menu);
+    wa->setDefaultWidget(m_lpw);
+    menu->addAction(wa);
+
+    setPopupMode(MenuButtonPopup);
+    setMenu(menu);
+    setCheckable(true);
+
+    redraw();
+}
+
+LevelPanToolButton::~LevelPanToolButton()
+{
+}
+
+float
+LevelPanToolButton::getLevel() const
+{
+    return m_lpw->getLevel();
+}
+
+float
+LevelPanToolButton::getPan() const
+{
+    return m_lpw->getPan();
+}
+
+void
+LevelPanToolButton::setImageSize(int pixels)
+{
+    m_pixels = pixels;
+    redraw();
+}
+
+void
+LevelPanToolButton::setLevel(float level)
+{
+    m_lpw->setLevel(level);
+}
+
+void
+LevelPanToolButton::setPan(float pan)
+{
+    m_lpw->setPan(pan);
+}
+
+void
+LevelPanToolButton::redraw()
+{
+    QSize sz(m_pixels, m_pixels);
+
+    m_lpw->setFixedWidth(m_pixels * 4);
+    m_lpw->setFixedHeight(m_pixels * 4);
+    
+    QPixmap px(sz);
+    px.fill(Qt::transparent);
+    m_lpw->renderTo(&px, QRectF(QPointF(), sz), false);
+    setIcon(px);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/widgets/LevelPanToolButton.h	Wed Mar 25 10:33:19 2015 +0000
@@ -0,0 +1,57 @@
+/* -*- 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 LEVEL_PAN_TOOLBUTTON_H
+#define LEVEL_PAN_TOOLBUTTON_H
+
+#include <QToolButton>
+
+class LevelPanWidget;
+
+class LevelPanToolButton : public QToolButton
+{
+    Q_OBJECT
+
+public:
+    LevelPanToolButton(QWidget *parent = 0);
+    ~LevelPanToolButton();
+    
+    /// Return level as a gain value in the range [0,1]
+    float getLevel() const; 
+    
+    /// Return pan as a value in the range [-1,1]
+    float getPan() const;
+
+    void setImageSize(int pixels);
+			
+public slots:
+    /// Set level in the range [0,1] -- will be rounded
+    void setLevel(float);
+
+    /// Set pan in the range [-1,1] -- will be rounded
+    void setPan(float);
+
+    /// Redraw icon for toolbar button based on level-pan widget contents
+    void redraw();
+
+signals:
+    void levelChanged(float);
+    void panChanged(float);
+
+protected:
+    LevelPanWidget *m_lpw;
+    int m_pixels;
+};
+
+#endif
--- a/widgets/LevelPanWidget.cpp	Tue Mar 24 17:05:42 2015 +0000
+++ b/widgets/LevelPanWidget.cpp	Wed Mar 25 10:33:19 2015 +0000
@@ -42,6 +42,27 @@
 {
 }
 
+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);
+}
+
 void
 LevelPanWidget::setLevel(float flevel)
 {
@@ -114,7 +135,7 @@
     if (!m_editable) return;
     
     int level, pan;
-    toCell(e->pos(), level, pan);
+    toCell(rect(), e->pos(), level, pan);
     if (level == m_level && pan == m_pan) {
 	return;
     }
@@ -170,24 +191,28 @@
 }
 
 void
-LevelPanWidget::toCell(QPointF loc, int &level, int &pan) const
+LevelPanWidget::toCell(QRectF rect, QPointF loc, int &level, int &pan) const
 {
-    double w = width(), h = height();
+    double w = rect.width(), h = rect.height();
+
     int npan = maxPan * 2 + 1;
     int nlevel = maxLevel + 1;
+
     double wcell = w / npan, hcell = h / nlevel;
+
     level = int((h - loc.y()) / hcell);
     if (level < 0) level = 0;
     if (level > maxLevel) level = maxLevel;
+
     pan = int(loc.x() / wcell) - maxPan;
     if (pan < -maxPan) pan = -maxPan;
     if (pan > maxPan) pan = maxPan;
 }
 
 QSizeF
-LevelPanWidget::cellSize() const
+LevelPanWidget::cellSize(QRectF rect) const
 {
-    double w = width(), h = height();
+    double w = rect.width(), h = rect.height();
     int npan = maxPan * 2 + 1;
     int nlevel = maxLevel + 1;
     double wcell = w / npan, hcell = h / nlevel;
@@ -195,27 +220,27 @@
 }
 
 QPointF
-LevelPanWidget::cellCentre(int level, int pan) const
+LevelPanWidget::cellCentre(QRectF rect, int level, int pan) const
 {
-    QSizeF cs = cellSize();
+    QSizeF cs = cellSize(rect);
     return QPointF(cs.width() * (pan + maxPan) + cs.width() / 2.,
-		   height() - cs.height() * (level + 1) + cs.height() / 2.);
+		   rect.height() - cs.height() * (level + 1) + cs.height() / 2.);
 }
 
 QSizeF
-LevelPanWidget::cellLightSize() const
+LevelPanWidget::cellLightSize(QRectF rect) const
 {
     double extent = 3. / 4.;
-    QSizeF cs = cellSize();
+    QSizeF cs = cellSize(rect);
     double m = std::min(cs.width(), cs.height());
     return QSizeF(m * extent, m * extent);
 }
 
 QRectF
-LevelPanWidget::cellLightRect(int level, int pan) const
+LevelPanWidget::cellLightRect(QRectF rect, int level, int pan) const
 {
-    QSizeF cls = cellLightSize();
-    QPointF cc = cellCentre(level, pan);
+    QSizeF cls = cellLightSize(rect);
+    QPointF cc = cellCentre(rect, level, pan);
     return QRectF(cc.x() - cls.width() / 2., 
 		  cc.y() - cls.height() / 2.,
 		  cls.width(),
@@ -223,32 +248,32 @@
 }
 
 double
-LevelPanWidget::thinLineWidth() const
+LevelPanWidget::thinLineWidth(QRectF rect) const
 {
-    double tw = ceil(width() / (maxPan * 2. * 10.));
-    double th = ceil(height() / (maxLevel * 10.));
+    double tw = ceil(rect.width() / (maxPan * 2. * 10.));
+    double th = ceil(rect.height() / (maxLevel * 10.));
     return std::min(th, tw);
 }
 
 void
-LevelPanWidget::paintEvent(QPaintEvent *)
+LevelPanWidget::renderTo(QPaintDevice *dev, QRectF rect, bool asIfEditable) const
 {
-    QPainter paint(this);
+    QPainter paint(dev);
     ColourMapper mapper(ColourMapper::Sunset, 0, maxLevel);
 
     paint.setRenderHint(QPainter::Antialiasing, true);
 
     QPen pen;
 
-    double thin = thinLineWidth();
+    double thin = thinLineWidth(rect);
     
     pen.setColor(QColor(127, 127, 127, 127));
-    pen.setWidthF(cellLightSize().width() + thin);
+    pen.setWidthF(cellLightSize(rect).width() + thin);
     pen.setCapStyle(Qt::RoundCap);
     paint.setPen(pen);
 
     for (int pan = -maxPan; pan <= maxPan; ++pan) {
-	paint.drawLine(cellCentre(0, pan), cellCentre(maxLevel, pan));
+	paint.drawLine(cellCentre(rect, 0, pan), cellCentre(rect, maxLevel, pan));
     }
 
     if (isEnabled()) {
@@ -256,6 +281,15 @@
     } else {
 	pen.setColor(Qt::darkGray);
     }
+
+    if (!asIfEditable && m_level == 0) {
+        pen.setWidthF(thin * 2);
+        pen.setCapStyle(Qt::RoundCap);
+        paint.setPen(pen);
+        paint.drawLine(rect.topLeft(), rect.bottomRight());
+        paint.drawLine(rect.bottomLeft(), rect.topRight());
+        return;
+    }
     
     pen.setWidthF(thin);
     pen.setCapStyle(Qt::FlatCap);
@@ -265,7 +299,7 @@
 	if (isEnabled()) {
 	    paint.setBrush(mapper.map(level));
 	}
-	QRectF clr = cellLightRect(level, m_pan);
+	QRectF clr = cellLightRect(rect, level, m_pan);
 	if (m_level == 0) {
 	    paint.drawLine(clr.topLeft(), clr.bottomRight());
 	    paint.drawLine(clr.bottomLeft(), clr.topRight());
@@ -275,4 +309,11 @@
     }
 }
 
+void
+LevelPanWidget::paintEvent(QPaintEvent *)
+{
+    renderTo(this, rect(), m_editable);
+}
 
+
+
--- a/widgets/LevelPanWidget.h	Tue Mar 24 17:05:42 2015 +0000
+++ b/widgets/LevelPanWidget.h	Wed Mar 25 10:33:19 2015 +0000
@@ -19,10 +19,6 @@
 
 /**
  * A simple widget for coarse level and pan control.
- *
- * For this initial implementation at least, pan is in five steps only
- * (hard left, mid-left, centre, mid-right, hard right) and level is
- * in five plus mute.
  */
 
 class LevelPanWidget : public QWidget
@@ -42,6 +38,11 @@
     /// Find out whether the widget is editable
     bool isEditable() const;
 
+    /// Draw a suitably sized copy of the widget's contents to the given device
+    void renderTo(QPaintDevice *, QRectF, bool asIfEditable) const;
+
+    QSize sizeHint() const;
+                                               
 public slots:
     /// Set level in the range [0,1] -- will be rounded
     void setLevel(float);
@@ -70,12 +71,12 @@
     int m_pan;
     bool m_editable;
 
-    QSizeF cellSize() const;
-    QPointF cellCentre(int level, int pan) const;
-    QSizeF cellLightSize() const;
-    QRectF cellLightRect(int level, int pan) const;
-    double thinLineWidth() const;
-    void toCell(QPointF loc, int &level, int &pan) const;
+    QSizeF cellSize(QRectF) const;
+    QPointF cellCentre(QRectF, int level, int pan) const;
+    QSizeF cellLightSize(QRectF) const;
+    QRectF cellLightRect(QRectF, int level, int pan) const;
+    double thinLineWidth(QRectF) const;
+    void toCell(QRectF, QPointF loc, int &level, int &pan) const;
 };
 
 #endif