# HG changeset patch # User Chris Cannam # Date 1427279599 0 # Node ID 20698aa6a5179f4763ad373f950e8e6f1e212feb # Parent 3fb91da7d98d6b82a9be6f824239abe50790ab76 Introduce level/pan toolbar buttons diff -r 3fb91da7d98d -r 20698aa6a517 svgui.pro --- 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 \ diff -r 3fb91da7d98d -r 20698aa6a517 widgets/LevelPanToolButton.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 +#include +#include + +#include +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); +} + diff -r 3fb91da7d98d -r 20698aa6a517 widgets/LevelPanToolButton.h --- /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 + +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 diff -r 3fb91da7d98d -r 20698aa6a517 widgets/LevelPanWidget.cpp --- 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); +} + + diff -r 3fb91da7d98d -r 20698aa6a517 widgets/LevelPanWidget.h --- 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