Mercurial > hg > svgui
changeset 1203:ff042979331b 3.0-integration
Merge from branch svg, and thus (in some subrepos) from levelpanwidget
author | Chris Cannam |
---|---|
date | Mon, 19 Dec 2016 16:34:38 +0000 |
parents | f32828ea63d9 (current diff) 6828735468c9 (diff) |
children | d421df27e184 |
files | |
diffstat | 31 files changed, 995 insertions(+), 392 deletions(-) [+] |
line wrap: on
line diff
--- a/files.pri Wed Dec 14 11:56:47 2016 +0000 +++ b/files.pri Mon Dec 19 16:34:38 2016 +0000 @@ -44,6 +44,8 @@ widgets/ActivityLog.h \ widgets/AudioDial.h \ widgets/ClickableLabel.h \ + widgets/ColourComboBox.h \ + widgets/ColourMapComboBox.h \ widgets/ColourNameDialog.h \ widgets/CommandHistory.h \ widgets/CSVFormatDialog.h \ @@ -66,6 +68,7 @@ widgets/NotifyingComboBox.h \ widgets/NotifyingPushButton.h \ widgets/NotifyingTabBar.h \ + widgets/NotifyingToolButton.h \ widgets/Panner.h \ widgets/PluginParameterBox.h \ widgets/PluginParameterDialog.h \ @@ -80,6 +83,7 @@ widgets/TipDialog.h \ widgets/TransformFinder.h \ widgets/UnitConverter.h \ + widgets/WidgetScale.h \ widgets/WindowShapePreview.h \ widgets/WindowTypeSelector.h @@ -121,6 +125,8 @@ view/ViewManager.cpp \ widgets/ActivityLog.cpp \ widgets/AudioDial.cpp \ + widgets/ColourComboBox.cpp \ + widgets/ColourMapComboBox.cpp \ widgets/ColourNameDialog.cpp \ widgets/CommandHistory.cpp \ widgets/CSVFormatDialog.cpp \ @@ -143,6 +149,7 @@ widgets/NotifyingComboBox.cpp \ widgets/NotifyingPushButton.cpp \ widgets/NotifyingTabBar.cpp \ + widgets/NotifyingToolButton.cpp \ widgets/Panner.cpp \ widgets/PluginParameterBox.cpp \ widgets/PluginParameterDialog.cpp \
--- a/layer/Colour3DPlotLayer.cpp Wed Dec 14 11:56:47 2016 +0000 +++ b/layer/Colour3DPlotLayer.cpp Mon Dec 19 16:34:38 2016 +0000 @@ -275,6 +275,7 @@ if (name == "Invert Vertical Scale") return ToggleProperty; if (name == "Opaque") return ToggleProperty; if (name == "Smooth") return ToggleProperty; + if (name == "Colour") return ColourMapProperty; return ValueProperty; }
--- a/layer/ColourMapper.cpp Wed Dec 14 11:56:47 2016 +0000 +++ b/layer/ColourMapper.cpp Mon Dec 19 16:34:38 2016 +0000 @@ -4,7 +4,7 @@ Sonic Visualiser An audio file viewer and annotation editor. Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006-2007 Chris Cannam and QMUL. + This file copyright 2006-2016 Chris Cannam and QMUL. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -23,6 +23,8 @@ #include <vector> +#include <QPainter> + using namespace std; static vector<QColor> convertStrings(const vector<QString> &strs) @@ -320,4 +322,29 @@ } } +QPixmap +ColourMapper::getExamplePixmap(QSize size) const +{ + QPixmap pmap(size); + pmap.fill(Qt::white); + QPainter paint(&pmap); + int w = size.width(), h = size.height(); + + int margin = 2; + if (w < 4 || h < 4) margin = 0; + else if (w < 8 || h < 8) margin = 1; + + int n = w - margin*2; + + for (int x = 0; x < n; ++x) { + double value = m_min + ((m_max - m_min) * x) / (n-1); + QColor colour(map(value)); + paint.setPen(colour); + paint.drawLine(x + margin, margin, x + margin, h - margin); + } + + return pmap; +} + +
--- a/layer/ColourMapper.h Wed Dec 14 11:56:47 2016 +0000 +++ b/layer/ColourMapper.h Mon Dec 19 16:34:38 2016 +0000 @@ -13,12 +13,13 @@ COPYING included with this distribution for more information. */ -#ifndef _COLOUR_MAPPER_H_ -#define _COLOUR_MAPPER_H_ +#ifndef SV_COLOUR_MAPPER_H +#define SV_COLOUR_MAPPER_H #include <QObject> #include <QColor> #include <QString> +#include <QPixmap> /** * A class for mapping intensity values onto various colour maps. @@ -59,6 +60,8 @@ QColor getContrastingColour() const; // for cursors etc bool hasLightBackground() const; + QPixmap getExamplePixmap(QSize size) const; + protected: int m_map; double m_min;
--- a/layer/SpectrogramLayer.cpp Wed Dec 14 11:56:47 2016 +0000 +++ b/layer/SpectrogramLayer.cpp Mon Dec 19 16:34:38 2016 +0000 @@ -255,6 +255,7 @@ if (name == "Gain") return RangeProperty; if (name == "Colour Rotation") return RangeProperty; if (name == "Threshold") return RangeProperty; + if (name == "Colour") return ColourMapProperty; return ValueProperty; }
--- a/layer/TimeValueLayer.cpp Wed Dec 14 11:56:47 2016 +0000 +++ b/layer/TimeValueLayer.cpp Mon Dec 19 16:34:38 2016 +0000 @@ -132,7 +132,7 @@ if (name == "Plot Type") return ValueProperty; if (name == "Vertical Scale") return ValueProperty; if (name == "Scale Units") return UnitsProperty; - if (name == "Colour" && m_plotStyle == PlotSegmentation) return ValueProperty; + if (name == "Colour" && m_plotStyle == PlotSegmentation) return ColourMapProperty; if (name == "Draw Segment Division Lines") return ToggleProperty; if (name == "Show Derivative") return ToggleProperty; return SingleColourLayer::getPropertyType(name);
--- a/view/Pane.cpp Wed Dec 14 11:56:47 2016 +0000 +++ b/view/Pane.cpp Mon Dec 19 16:34:38 2016 +0000 @@ -22,6 +22,7 @@ #include "ViewManager.h" #include "widgets/CommandHistory.h" #include "widgets/TextAbbrev.h" +#include "widgets/IconLoader.h" #include "base/Preferences.h" #include "layer/WaveformLayer.h" #include "layer/TimeRulerLayer.h" @@ -142,8 +143,8 @@ m_hthumb->setObjectName(tr("Horizontal Zoom")); m_hthumb->setCursor(Qt::ArrowCursor); layout->addWidget(m_hthumb, 1, 0, 1, 2); - m_hthumb->setFixedWidth(70); - m_hthumb->setFixedHeight(16); + m_hthumb->setFixedWidth(m_manager->scalePixelSize(70)); + m_hthumb->setFixedHeight(m_manager->scalePixelSize(16)); m_hthumb->setDefaultValue(0); m_hthumb->setSpeed(0.6f); connect(m_hthumb, SIGNAL(valueChanged(int)), this, @@ -154,8 +155,8 @@ m_vpan = new Panner; m_vpan->setCursor(Qt::ArrowCursor); layout->addWidget(m_vpan, 0, 1); - m_vpan->setFixedWidth(12); - m_vpan->setFixedHeight(70); + m_vpan->setFixedWidth(m_manager->scalePixelSize(12)); + m_vpan->setFixedHeight(m_manager->scalePixelSize(70)); m_vpan->setAlpha(80, 130); connect(m_vpan, SIGNAL(rectExtentsChanged(float, float, float, float)), this, SLOT(verticalPannerMoved(float, float, float, float))); @@ -168,8 +169,8 @@ m_vthumb->setObjectName(tr("Vertical Zoom")); m_vthumb->setCursor(Qt::ArrowCursor); layout->addWidget(m_vthumb, 0, 2); - m_vthumb->setFixedWidth(16); - m_vthumb->setFixedHeight(70); + m_vthumb->setFixedWidth(m_manager->scalePixelSize(16)); + m_vthumb->setFixedHeight(m_manager->scalePixelSize(70)); connect(m_vthumb, SIGNAL(valueChanged(int)), this, SLOT(verticalThumbwheelMoved(int))); connect(m_vthumb, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget())); @@ -183,9 +184,9 @@ m_reset = new NotifyingPushButton; m_reset->setFlat(true); m_reset->setCursor(Qt::ArrowCursor); - m_reset->setFixedHeight(16); - m_reset->setFixedWidth(16); - m_reset->setIcon(QPixmap(":/icons/zoom-reset.png")); + m_reset->setFixedHeight(m_manager->scalePixelSize(16)); + m_reset->setFixedWidth(m_manager->scalePixelSize(16)); + m_reset->setIcon(IconLoader().load("zoom-reset")); m_reset->setToolTip(tr("Reset zoom to default")); layout->addWidget(m_reset, 1, 2); @@ -284,16 +285,19 @@ updateVerticalPanner(); if (m_manager && m_manager->getZoomWheelsEnabled() && - width() > 120 && height() > 100) { + width() > m_manager->scalePixelSize(120) && + height() > m_manager->scalePixelSize(100)) { if (!m_headsUpDisplay->isVisible()) { m_headsUpDisplay->show(); } + int shift = m_manager->scalePixelSize(86); if (haveVThumb) { m_headsUpDisplay->setFixedHeight(m_vthumb->height() + m_hthumb->height()); - m_headsUpDisplay->move(width() - 86, height() - 86); + m_headsUpDisplay->move(width() - shift, height() - shift); } else { m_headsUpDisplay->setFixedHeight(m_hthumb->height()); - m_headsUpDisplay->move(width() - 86, height() - 16); + m_headsUpDisplay->move(width() - shift, + height() - m_manager->scalePixelSize(16)); } } else { m_headsUpDisplay->hide(); @@ -920,7 +924,7 @@ int lly = height() - 6; if (m_manager->getZoomWheelsEnabled()) { - lly -= 20; + lly -= m_manager->scalePixelSize(20); } if (r.y() + r.height() < lly - int(m_layerStack.size()) * fontHeight) { @@ -942,7 +946,7 @@ int llx = width() - maxTextWidth - 5; if (m_manager->getZoomWheelsEnabled()) { - llx -= 36; + llx -= m_manager->scalePixelSize(36); } if (r.x() + r.width() >= llx - fontAscent - 3) { @@ -1119,7 +1123,7 @@ } QImage * -Pane::toNewImage(sv_frame_t f0, sv_frame_t f1) +Pane::renderPartToNewImage(sv_frame_t f0, sv_frame_t f1) { int x0 = int(f0 / getZoomLevel()); int x1 = int(f1 / getZoomLevel()); @@ -1158,9 +1162,9 @@ } QSize -Pane::getImageSize(sv_frame_t f0, sv_frame_t f1) +Pane::getRenderedPartImageSize(sv_frame_t f0, sv_frame_t f1) { - QSize s = View::getImageSize(f0, f1); + QSize s = View::getRenderedPartImageSize(f0, f1); QImage *image = new QImage(100, 100, QImage::Format_RGB32); QPainter paint(image);
--- a/view/Pane.h Wed Dec 14 11:56:47 2016 +0000 +++ b/view/Pane.h Mon Dec 19 16:34:38 2016 +0000 @@ -37,28 +37,35 @@ public: Pane(QWidget *parent = 0); - virtual QString getPropertyContainerIconName() const { return "pane"; } + virtual QString getPropertyContainerIconName() const override { return "pane"; } virtual bool shouldIlluminateLocalFeatures(const Layer *layer, - QPoint &pos) const; + QPoint &pos) const override; virtual bool shouldIlluminateLocalSelection(QPoint &pos, bool &closeToLeft, - bool &closeToRight) const; + bool &closeToRight) const override; void setCentreLineVisible(bool visible); bool getCentreLineVisible() const { return m_centreLineVisible; } - virtual sv_frame_t getFirstVisibleFrame() const; + virtual sv_frame_t getFirstVisibleFrame() const override; - virtual int getVerticalScaleWidth() const; + int getVerticalScaleWidth() const; - virtual QImage *toNewImage(sv_frame_t f0, sv_frame_t f1); - virtual QImage *toNewImage() { return View::toNewImage(); } - virtual QSize getImageSize(sv_frame_t f0, sv_frame_t f1); - virtual QSize getImageSize() { return View::getImageSize(); } + virtual QImage *renderToNewImage() override { + return View::renderToNewImage(); + } + + virtual QImage *renderPartToNewImage(sv_frame_t f0, sv_frame_t f1) override; + + virtual QSize getRenderedImageSize() override { + return View::getRenderedImageSize(); + } + + virtual QSize getRenderedPartImageSize(sv_frame_t f0, sv_frame_t f1) override; virtual void toXml(QTextStream &stream, QString indent = "", - QString extraAttributes = "") const; + QString extraAttributes = "") const override; static void registerShortcuts(KeyReference &kr);
--- a/view/View.cpp Wed Dec 14 11:56:47 2016 +0000 +++ b/view/View.cpp Mon Dec 19 16:34:38 2016 +0000 @@ -41,6 +41,7 @@ #include <QMessageBox> #include <QPushButton> #include <QSettings> +#include <QSvgGenerator> #include <iostream> #include <cassert> @@ -2100,11 +2101,15 @@ dx = p1 - 2 - dw; } - paint.drawText(sx, sy, startText); - paint.drawText(ex, ey, endText); - paint.drawText(dx, dy, durationText); + PaintAssistant::drawVisibleText(this, paint, sx, sy, startText, + PaintAssistant::OutlinedText); + PaintAssistant::drawVisibleText(this, paint, ex, ey, endText, + PaintAssistant::OutlinedText); + PaintAssistant::drawVisibleText(this, paint, dx, dy, durationText, + PaintAssistant::OutlinedText); if (durationBothEnds) { - paint.drawText(sx, dy, durationText); + PaintAssistant::drawVisibleText(this, paint, sx, dy, durationText, + PaintAssistant::OutlinedText); } } } @@ -2457,16 +2462,16 @@ } QImage * -View::toNewImage() +View::renderToNewImage() { sv_frame_t f0 = getModelsStartFrame(); sv_frame_t f1 = getModelsEndFrame(); - return toNewImage(f0, f1); + return renderPartToNewImage(f0, f1); } QImage * -View::toNewImage(sv_frame_t f0, sv_frame_t f1) +View::renderPartToNewImage(sv_frame_t f0, sv_frame_t f1) { int x0 = int(f0 / getZoomLevel()); int x1 = int(f1 / getZoomLevel()); @@ -2485,16 +2490,16 @@ } QSize -View::getImageSize() +View::getRenderedImageSize() { sv_frame_t f0 = getModelsStartFrame(); sv_frame_t f1 = getModelsEndFrame(); - return getImageSize(f0, f1); + return getRenderedPartImageSize(f0, f1); } QSize -View::getImageSize(sv_frame_t f0, sv_frame_t f1) +View::getRenderedPartImageSize(sv_frame_t f0, sv_frame_t f1) { int x0 = int(f0 / getZoomLevel()); int x1 = int(f1 / getZoomLevel()); @@ -2502,6 +2507,35 @@ return QSize(x1 - x0, height()); } +bool +View::renderToSvgFile(QString filename) +{ + sv_frame_t f0 = getModelsStartFrame(); + sv_frame_t f1 = getModelsEndFrame(); + + return renderPartToSvgFile(filename, f0, f1); +} + +bool +View::renderPartToSvgFile(QString filename, sv_frame_t f0, sv_frame_t f1) +{ + int x0 = int(f0 / getZoomLevel()); + int x1 = int(f1 / getZoomLevel()); + + QSvgGenerator generator; + generator.setFileName(filename); + generator.setSize(QSize(x1 - x0, height())); + generator.setViewBox(QRect(0, 0, x1 - x0, height())); + generator.setTitle(tr("Exported image from %1") + .arg(QApplication::applicationName())); + + QPainter paint; + paint.begin(&generator); + bool result = render(paint, 0, f0, f1); + paint.end(); + return result; +} + void View::toXml(QTextStream &stream, QString indent, QString extraAttributes) const
--- a/view/View.h Wed Dec 14 11:56:47 2016 +0000 +++ b/view/View.h Mon Dec 19 16:34:38 2016 +0000 @@ -308,12 +308,42 @@ virtual const PropertyContainer *getPropertyContainer(int i) const; virtual PropertyContainer *getPropertyContainer(int i); - // Render the contents on a wide canvas - virtual QImage *toNewImage(sv_frame_t f0, sv_frame_t f1); - virtual QImage *toNewImage(); - virtual QSize getImageSize(sv_frame_t f0, sv_frame_t f1); - virtual QSize getImageSize(); + /** + * Render the view contents to a new QImage (which may be wider + * than the visible View). + */ + virtual QImage *renderToNewImage(); + /** + * Render the view contents between the given frame extents to a + * new QImage (which may be wider than the visible View). + */ + virtual QImage *renderPartToNewImage(sv_frame_t f0, sv_frame_t f1); + + /** + * Calculate and return the size of image that will be generated + * by renderToNewImage(). + */ + virtual QSize getRenderedImageSize(); + + /** + * Calculate and return the size of image that will be generated + * by renderPartToNewImage(f0, f1). + */ + virtual QSize getRenderedPartImageSize(sv_frame_t f0, sv_frame_t f1); + + /** + * Render the view contents to a new SVG file. + */ + virtual bool renderToSvgFile(QString filename); + + /** + * Render the view contents between the given frame extents to a + * new SVG file. + */ + virtual bool renderPartToSvgFile(QString filename, + sv_frame_t f0, sv_frame_t f1); + virtual int getTextLabelHeight(const Layer *layer, QPainter &) const; virtual bool getValueExtents(QString unit, double &min, double &max,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/ColourComboBox.cpp Mon Dec 19 16:34:38 2016 +0000 @@ -0,0 +1,101 @@ +/* -*- 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 file copyright 2007-2016 QMUL. + + 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 "ColourComboBox.h" + +#include "ColourNameDialog.h" + +#include "layer/ColourDatabase.h" + +#include "base/Debug.h" + +#include <QFontMetrics> +#include <QColorDialog> + +#include <iostream> + +using namespace std; + +ColourComboBox::ColourComboBox(bool withAddNewColourEntry, QWidget *parent) : + NotifyingComboBox(parent), + m_withAddNewColourEntry(withAddNewColourEntry) +{ + setEditable(false); + rebuild(); + + connect(this, SIGNAL(activated(int)), this, SLOT(comboActivated(int))); + connect(ColourDatabase::getInstance(), SIGNAL(colourDatabaseChanged()), + this, SLOT(rebuild())); + + if (count() < 20 && count() > maxVisibleItems()) { + setMaxVisibleItems(count()); + } +} + +void +ColourComboBox::comboActivated(int index) +{ + if (!m_withAddNewColourEntry || + index < int(ColourDatabase::getInstance()->getColourCount())) { + emit colourChanged(index); + return; + } + + QColor newColour = QColorDialog::getColor(); + if (!newColour.isValid()) return; + + ColourNameDialog dialog(tr("Name New Colour"), + tr("Enter a name for the new colour:"), + newColour, newColour.name(), this); + dialog.showDarkBackgroundCheckbox(tr("Prefer black background for this colour")); + if (dialog.exec() == QDialog::Accepted) { + //!!! command + ColourDatabase *db = ColourDatabase::getInstance(); + int index = db->addColour(newColour, dialog.getColourName()); + db->setUseDarkBackground(index, dialog.isDarkBackgroundChecked()); + // addColour will have called back on rebuild(), and the new + // colour will be at the index previously occupied by Add New + // Colour, which is our current index + emit colourChanged(currentIndex()); + } +} + +void +ColourComboBox::rebuild() +{ + blockSignals(true); + + int ix = currentIndex(); + + clear(); + + int size = (QFontMetrics(QFont()).height() * 2) / 3; + if (size < 12) size = 12; + + ColourDatabase *db = ColourDatabase::getInstance(); + for (int i = 0; i < db->getColourCount(); ++i) { + QString name = db->getColourName(i); + addItem(db->getExamplePixmap(i, QSize(size, size)), name); + } + + if (m_withAddNewColourEntry) { + addItem(tr("Add New Colour...")); + } + + setCurrentIndex(ix); + + blockSignals(false); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/ColourComboBox.h Mon Dec 19 16:34:38 2016 +0000 @@ -0,0 +1,44 @@ +/* -*- 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 file copyright 2007-2016 QMUL. + + 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_COLOUR_COMBO_BOX_H +#define SV_COLOUR_COMBO_BOX_H + +#include "NotifyingComboBox.h" + +/** + * Colour-picker combo box with swatches, optionally including "Add + * New Colour..." entry to invoke a QColorDialog/ColourNameDialog + */ +class ColourComboBox : public NotifyingComboBox +{ + Q_OBJECT + +public: + ColourComboBox(bool withAddNewColourEntry, QWidget *parent = 0); + +signals: + void colourChanged(int colourIndex); + +private slots: + void rebuild(); + void comboActivated(int); + +private: + bool m_withAddNewColourEntry; +}; + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/ColourMapComboBox.cpp Mon Dec 19 16:34:38 2016 +0000 @@ -0,0 +1,74 @@ +/* -*- 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 file copyright 2007-2016 QMUL. + + 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 "ColourMapComboBox.h" + +#include "layer/ColourMapper.h" + +#include "base/Debug.h" + +#include <QFontMetrics> + +#include <iostream> + +using namespace std; + +ColourMapComboBox::ColourMapComboBox(bool includeSwatches, QWidget *parent) : + NotifyingComboBox(parent), + m_includeSwatches(includeSwatches) +{ + setEditable(false); + rebuild(); + + connect(this, SIGNAL(activated(int)), this, SLOT(comboActivated(int))); + + if (count() < 20 && count() > maxVisibleItems()) { + setMaxVisibleItems(count()); + } +} + +void +ColourMapComboBox::comboActivated(int index) +{ + emit colourMapChanged(index); +} + +void +ColourMapComboBox::rebuild() +{ + blockSignals(true); + + int ix = currentIndex(); + + clear(); + + int size = (QFontMetrics(QFont()).height() * 2) / 3; + if (size < 12) size = 12; + + for (int i = 0; i < ColourMapper::getColourMapCount(); ++i) { + QString name = ColourMapper::getColourMapName(i); + if (m_includeSwatches) { + ColourMapper mapper(i, 0.0, 1.0); + addItem(mapper.getExamplePixmap(QSize(size * 2, size)), name); + } else { + addItem(name); + } + } + + setCurrentIndex(ix); + + blockSignals(false); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/ColourMapComboBox.h Mon Dec 19 16:34:38 2016 +0000 @@ -0,0 +1,43 @@ +/* -*- 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 file copyright 2007-2016 QMUL. + + 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_COLOURMAP_COMBO_BOX_H +#define SV_COLOURMAP_COMBO_BOX_H + +#include "NotifyingComboBox.h" + +/** + * Colour map picker combo box with optional swatches + */ +class ColourMapComboBox : public NotifyingComboBox +{ + Q_OBJECT + +public: + ColourMapComboBox(bool includeSwatches, QWidget *parent = 0); + +signals: + void colourMapChanged(int index); + +private slots: + void rebuild(); + void comboActivated(int); + +private: + bool m_includeSwatches; +}; + +#endif +
--- a/widgets/InteractiveFileFinder.cpp Wed Dec 14 11:56:47 2016 +0000 +++ b/widgets/InteractiveFileFinder.cpp Mon Dec 19 16:34:38 2016 +0000 @@ -134,6 +134,11 @@ } break; + case SVGFile: + settingsKeyStub = "svg"; + filter = tr("Scalable Vector Graphics files (*.svg)\nAll files (*.*)"); + break; + case CSVFile: settingsKeyStub = "layer"; filter = tr("Comma-separated data files (*.csv)\nSpace-separated .lab files (*.lab)\nText files (*.txt)\nAll files (*.*)"); @@ -282,6 +287,12 @@ filter = tr("Portable Network Graphics files (*.png)\nAll files (*.*)"); break; + case SVGFile: + settingsKeyStub = "savesvg"; + title = tr("Select a file to export to"); + filter = tr("Scalable Vector Graphics files (*.svg)\nAll files (*.*)"); + break; + case CSVFile: settingsKeyStub = "savelayer"; title = tr("Select a file to export to"); @@ -330,6 +341,8 @@ defaultSuffix = "wav"; } else if (type == ImageFile) { defaultSuffix = "png"; + } else if (type == SVGFile) { + defaultSuffix = "svg"; } else if (type == CSVFile) { defaultSuffix = "csv"; } @@ -450,6 +463,10 @@ settingsKeyStub = "image"; break; + case SVGFile: + settingsKeyStub = "svg"; + break; + case CSVFile: settingsKeyStub = "layer"; break;
--- a/widgets/LEDButton.cpp Wed Dec 14 11:56:47 2016 +0000 +++ b/widgets/LEDButton.cpp Mon Dec 19 16:34:38 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 Mon Dec 19 16:34:38 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 Mon Dec 19 16:34:38 2016 +0000 @@ -49,6 +49,7 @@ setPopupMode(InstantPopup); setMenu(menu); + setToolTip(tr("Click to adjust level and pan")); setImageSize(m_pixels); setBigImageSize(m_pixelsBig); @@ -58,6 +59,12 @@ { } +void +LevelPanToolButton::wheelEvent(QWheelEvent *e) +{ + m_lpw->wheelEvent(e); +} + float LevelPanToolButton::getLevel() const { @@ -110,6 +117,13 @@ } void +LevelPanToolButton::setMonitoringLevels(float left, float right) +{ + m_lpw->setMonitoringLevels(left, right); + update(); +} + +void LevelPanToolButton::setIncludeMute(bool include) { m_lpw->setIncludeMute(include); @@ -170,4 +184,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 Mon Dec 19 16:34:38 2016 +0000 @@ -47,6 +47,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 level range should include muting or not void setIncludeMute(bool); @@ -56,12 +59,18 @@ 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 *); + virtual void wheelEvent(QWheelEvent *e); LevelPanWidget *m_lpw; int m_pixels;
--- a/widgets/LevelPanWidget.cpp Wed Dec 14 11:56:47 2016 +0000 +++ b/widgets/LevelPanWidget.cpp Mon Dec 19 16:34:38 2016 +0000 @@ -21,6 +21,8 @@ #include "layer/ColourMapper.h" #include "base/AudioLevel.h" +#include "WidgetScale.h" + #include <iostream> #include <cmath> #include <cassert> @@ -35,9 +37,14 @@ QWidget(parent), m_level(maxLevel), m_pan(0), + m_monitorLeft(-1), + m_monitorRight(-1), m_editable(true), m_includeMute(true) { + setToolTip(tr("Drag vertically to adjust level, horizontally to adjust pan")); + setLevel(1.0); + setPan(0.0); } LevelPanWidget::~LevelPanWidget() @@ -47,22 +54,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 +83,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 +126,46 @@ 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))); + float flevel = levelToAudioLevel(m_level, m_includeMute); + return flevel; +} + +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,23 +196,15 @@ update(); } -float -LevelPanWidget::getPan() const -{ - return float(m_pan) / float(maxPan); -} - void LevelPanWidget::emitLevelChanged() { - cerr << "emitting levelChanged(" << getLevel() << ")" << endl; emit levelChanged(getLevel()); } void LevelPanWidget::emitPanChanged() { - cerr << "emitting panChanged(" << getPan() << ")" << endl; emit panChanged(getPan()); } @@ -338,11 +366,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 +434,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 Mon Dec 19 16:34:38 2016 +0000 @@ -29,7 +29,8 @@ LevelPanWidget(QWidget *parent = 0); ~LevelPanWidget(); - /// Return level as a gain value in the range [0,1] + /// Return level as a gain value. The basic level range is [0,1] but the + /// gain scale may go up to 4.0 float getLevel() const; /// Return pan as a value in the range [-1,1] @@ -47,37 +48,56 @@ QSize sizeHint() const; public slots: - /// Set level in the range [0,1] -- will be rounded + /// Set level. The basic level range is [0,1] but the scale may go + /// higher. The value will be rounded. void setLevel(float); - /// Set pan in the range [-1,1] -- will be rounded + /// Set pan in the range [-1,1]. The value 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); /// Specify whether the level range should include muting or not void setIncludeMute(bool); + // public so it can be called from LevelPanToolButton (ew) + virtual void wheelEvent(QWheelEvent *ev); + 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 Mon Dec 19 16:34:38 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/NotifyingComboBox.h Wed Dec 14 11:56:47 2016 +0000 +++ b/widgets/NotifyingComboBox.h Mon Dec 19 16:34:38 2016 +0000 @@ -13,8 +13,8 @@ COPYING included with this distribution for more information. */ -#ifndef _NOTIFYING_COMBO_BOX_H_ -#define _NOTIFYING_COMBO_BOX_H_ +#ifndef SV_NOTIFYING_COMBO_BOX_H +#define SV_NOTIFYING_COMBO_BOX_H #include <QComboBox> @@ -26,8 +26,8 @@ class NotifyingComboBox : public QComboBox { Q_OBJECT + public: - NotifyingComboBox(QWidget *parent = 0) : QComboBox(parent) { }
--- a/widgets/NotifyingPushButton.h Wed Dec 14 11:56:47 2016 +0000 +++ b/widgets/NotifyingPushButton.h Mon Dec 19 16:34:38 2016 +0000 @@ -13,21 +13,22 @@ COPYING included with this distribution for more information. */ -#ifndef _NOTIFYING_PUSH_BUTTON_H_ -#define _NOTIFYING_PUSH_BUTTON_H_ +#ifndef SV_NOTIFYING_PUSH_BUTTON_H +#define SV_NOTIFYING_PUSH_BUTTON_H #include <QPushButton> /** - * Very trivial enhancement to QPushButton to make it emit signals when - * the mouse enters and leaves (for context help). + * Very trivial enhancement to QPushButton to make it emit signals + * when the mouse enters and leaves (for context help). See also + * NotifyingToolButton */ class NotifyingPushButton : public QPushButton { Q_OBJECT + public: - NotifyingPushButton(QWidget *parent = 0) : QPushButton(parent) { }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/NotifyingToolButton.cpp Mon Dec 19 16:34:38 2016 +0000 @@ -0,0 +1,35 @@ +/* -*- 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 file copyright 2007 QMUL. + + 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 "NotifyingToolButton.h" + +NotifyingToolButton::~NotifyingToolButton() +{ +} + +void +NotifyingToolButton::enterEvent(QEvent *e) +{ + QToolButton::enterEvent(e); + emit mouseEntered(); +} + +void +NotifyingToolButton::leaveEvent(QEvent *e) +{ + QToolButton::enterEvent(e); + emit mouseLeft(); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/NotifyingToolButton.h Mon Dec 19 16:34:38 2016 +0000 @@ -0,0 +1,47 @@ +/* -*- 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 file copyright 2007 QMUL. + + 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_NOTIFYING_TOOL_BUTTON_H +#define SV_NOTIFYING_TOOL_BUTTON_H + +#include <QToolButton> + +/** + * Very trivial enhancement to QToolButton to make it emit signals + * when the mouse enters and leaves (for context help). See also + * NotifyingPushButton + */ + +class NotifyingToolButton : public QToolButton +{ + Q_OBJECT + +public: + NotifyingToolButton(QWidget *parent = 0) : + QToolButton(parent) { } + + virtual ~NotifyingToolButton(); + +signals: + void mouseEntered(); + void mouseLeft(); + +protected: + virtual void enterEvent(QEvent *); + virtual void leaveEvent(QEvent *); +}; + +#endif +
--- a/widgets/PropertyBox.cpp Wed Dec 14 11:56:47 2016 +0000 +++ b/widgets/PropertyBox.cpp Mon Dec 19 16:34:38 2016 +0000 @@ -20,23 +20,28 @@ #include "base/PlayParameters.h" #include "base/PlayParameterRepository.h" #include "layer/Layer.h" -#include "layer/ColourDatabase.h" #include "base/UnitDatabase.h" #include "base/RangeMapper.h" #include "AudioDial.h" #include "LEDButton.h" #include "IconLoader.h" +#include "LevelPanWidget.h" +#include "LevelPanToolButton.h" +#include "WidgetScale.h" #include "NotifyingCheckBox.h" #include "NotifyingComboBox.h" #include "NotifyingPushButton.h" -#include "ColourNameDialog.h" +#include "NotifyingToolButton.h" +#include "ColourComboBox.h" +#include "ColourMapComboBox.h" #include <QGridLayout> #include <QHBoxLayout> #include <QVBoxLayout> #include <QPushButton> +#include <QToolButton> #include <QLabel> #include <QFrame> #include <QApplication> @@ -103,9 +108,6 @@ connect(UnitDatabase::getInstance(), SIGNAL(unitDatabaseChanged()), this, SLOT(unitDatabaseChanged())); - connect(ColourDatabase::getInstance(), SIGNAL(colourDatabaseChanged()), - this, SLOT(colourDatabaseChanged())); - #ifdef DEBUG_PROPERTY_BOX cerr << "PropertyBox[" << this << "]::PropertyBox returning" << endl; #endif @@ -147,7 +149,7 @@ m_viewPlayFrame->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); m_mainBox->addWidget(m_viewPlayFrame); - QHBoxLayout *layout = new QHBoxLayout; + QGridLayout *layout = new QGridLayout; m_viewPlayFrame->setLayout(layout); layout->setMargin(layout->margin() / 2); @@ -156,32 +158,18 @@ SVDEBUG << "PropertyBox::populateViewPlayFrame: container " << m_container << " (name " << m_container->getPropertyContainerName() << ") params " << params << endl; #endif - if (layer) { - QLabel *showLabel = new QLabel(tr("Show")); - layout->addWidget(showLabel); - layout->setAlignment(showLabel, Qt::AlignVCenter); + QSize buttonSize = WidgetScale::scaleQSize(QSize(26, 26)); + int col = 0; - m_showButton = new LEDButton(Qt::blue); - layout->addWidget(m_showButton); - connect(m_showButton, SIGNAL(stateChanged(bool)), - this, SIGNAL(showLayer(bool))); - connect(m_showButton, SIGNAL(mouseEntered()), - this, SLOT(mouseEnteredWidget())); - connect(m_showButton, SIGNAL(mouseLeft()), - this, SLOT(mouseLeftWidget())); - layout->setAlignment(m_showButton, Qt::AlignVCenter); - } - if (params) { - - QLabel *playLabel = new QLabel(tr("Play")); - layout->addWidget(playLabel); - layout->setAlignment(playLabel, Qt::AlignVCenter); - - m_playButton = new LEDButton(Qt::darkGreen); - m_playButton->setState(!params->isPlayMuted()); - layout->addWidget(m_playButton); - connect(m_playButton, SIGNAL(stateChanged(bool)), + + m_playButton = new NotifyingToolButton; + m_playButton->setCheckable(true); + m_playButton->setIcon(IconLoader().load("speaker")); + m_playButton->setToolTip(tr("Click to toggle playback")); + m_playButton->setChecked(!params->isPlayMuted()); + m_playButton->setFixedSize(buttonSize); + connect(m_playButton, SIGNAL(toggled(bool)), this, SLOT(playAudibleButtonChanged(bool))); connect(m_playButton, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget())); @@ -189,76 +177,56 @@ this, SLOT(mouseLeftWidget())); connect(params, SIGNAL(playAudibleChanged(bool)), this, SLOT(playAudibleChanged(bool))); - layout->setAlignment(m_playButton, Qt::AlignVCenter); - layout->insertStretch(-1, 10); + LevelPanToolButton *levelPan = new LevelPanToolButton; + levelPan->setFixedSize(buttonSize); + levelPan->setImageSize((buttonSize.height() * 3) / 4); + layout->addWidget(levelPan, 0, col++, Qt::AlignCenter); + 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())); + + layout->addWidget(m_playButton, 0, col++, Qt::AlignCenter); if (params->getPlayClipId() != "") { - QPushButton *playParamButton = - new QPushButton(QIcon(":icons/faders.png"), ""); - playParamButton->setFixedWidth(24); - playParamButton->setFixedHeight(24); - layout->addWidget(playParamButton); + QToolButton *playParamButton = new QToolButton; + playParamButton->setObjectName("playParamButton"); + playParamButton->setIcon(IconLoader().load("faders")); + playParamButton->setFixedSize(buttonSize); + layout->addWidget(playParamButton, 0, col++, Qt::AlignCenter); connect(playParamButton, SIGNAL(clicked()), this, SLOT(editPlayParameters())); + connect(playParamButton, SIGNAL(mouseEntered()), + this, SLOT(mouseEnteredWidget())); + connect(playParamButton, SIGNAL(mouseLeft()), + this, SLOT(mouseLeftWidget())); } + } - 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()), + layout->setColumnStretch(col++, 10); + + if (layer) { + + QLabel *showLabel = new QLabel(tr("Show")); + layout->addWidget(showLabel, 0, col++, Qt::AlignVCenter | Qt::AlignRight); + + m_showButton = new LEDButton(palette().highlight().color()); + layout->addWidget(m_showButton, 0, col++, Qt::AlignVCenter | Qt::AlignLeft); + connect(m_showButton, SIGNAL(stateChanged(bool)), + this, SIGNAL(showLayer(bool))); + connect(m_showButton, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget())); - connect(gainDial, SIGNAL(mouseLeft()), + connect(m_showButton, 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); } } @@ -288,27 +256,38 @@ << groupName << "\"" << endl; #endif - bool inGroup = (groupName != QString()); + if (!have) { - if (!have) { - if (inGroup) { + QLabel *labelWidget = 0; + + if (groupName != QString()) { if (m_groupLayouts.find(groupName) == m_groupLayouts.end()) { -#ifdef DEBUG_PROPERTY_BOX - cerr << "PropertyBox: adding label \"" << groupName << "\" and frame for group for \"" << name << "\"" << endl; + labelWidget = new QLabel(groupName, m_mainWidget); + } + } else { + groupName = "ungrouped: " + propertyLabel; + if (m_groupLayouts.find(groupName) == m_groupLayouts.end()) { + labelWidget = new QLabel(propertyLabel, m_mainWidget); + } + } + + if (labelWidget) { + m_layout->addWidget(labelWidget, row, 0); + QWidget *frame = new QWidget(m_mainWidget); + frame->setMinimumSize(WidgetScale::scaleQSize(QSize(1, 24))); + m_groupLayouts[groupName] = new QGridLayout; +#ifdef Q_OS_MAC + // Seems to be plenty of whitespace already + m_groupLayouts[groupName]->setContentsMargins(0, 0, 0, 0); +#else + // Need a bit of padding on the left + m_groupLayouts[groupName]->setContentsMargins + (WidgetScale::scalePixelSize(10), 0, 0, 0); #endif - m_layout->addWidget(new QLabel(groupName, m_mainWidget), row, 0); - QFrame *frame = new QFrame(m_mainWidget); - m_layout->addWidget(frame, row, 1, 1, 2); - m_groupLayouts[groupName] = new QGridLayout; - m_groupLayouts[groupName]->setMargin(0); - frame->setLayout(m_groupLayouts[groupName]); - } - } else { -#ifdef DEBUG_PROPERTY_BOX - cerr << "PropertyBox: adding label \"" << propertyLabel << "\"" << endl; -#endif - m_layout->addWidget(new QLabel(propertyLabel, m_mainWidget), row, 0); - } + frame->setLayout(m_groupLayouts[groupName]); + m_layout->addWidget(frame, row, 1, 1, 2); + m_layout->setColumnStretch(1, 10); + } } switch (type) { @@ -318,7 +297,7 @@ QAbstractButton *button = 0; if (have) { - button = dynamic_cast<QAbstractButton *>(m_propertyControllers[name]); + button = qobject_cast<QAbstractButton *>(m_propertyControllers[name]); assert(button); } else { #ifdef DEBUG_PROPERTY_BOX @@ -330,7 +309,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); @@ -341,13 +320,9 @@ this, SLOT(mouseEnteredWidget())); connect(button, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget())); - if (inGroup) { - button->setToolTip(propertyLabel); - m_groupLayouts[groupName]->addWidget - (button, 0, m_groupLayouts[groupName]->columnCount()); - } else { - m_layout->addWidget(button, row, 1, 1, 2); - } + button->setToolTip(propertyLabel); + m_groupLayouts[groupName]->addWidget + (button, 0, m_groupLayouts[groupName]->columnCount()); m_propertyControllers[name] = button; } @@ -364,7 +339,7 @@ AudioDial *dial; if (have) { - dial = dynamic_cast<AudioDial *>(m_propertyControllers[name]); + dial = qobject_cast<AudioDial *>(m_propertyControllers[name]); assert(dial); if (rangeChanged) { dial->blockSignals(true); @@ -396,21 +371,10 @@ connect(dial, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget())); - if (inGroup) { - dial->setFixedWidth(24); - dial->setFixedHeight(24); - m_groupLayouts[groupName]->addWidget - (dial, 0, m_groupLayouts[groupName]->columnCount()); - } else { - dial->setFixedWidth(32); - dial->setFixedHeight(32); - m_layout->addWidget(dial, row, 1); - QLabel *label = new QLabel(m_mainWidget); - connect(dial, SIGNAL(valueChanged(int)), - label, SLOT(setNum(int))); - label->setNum(value); - m_layout->addWidget(label, row, 2); - } + dial->setFixedWidth(WidgetScale::scalePixelSize(24)); + dial->setFixedHeight(WidgetScale::scalePixelSize(24)); + m_groupLayouts[groupName]->addWidget + (dial, 0, m_groupLayouts[groupName]->columnCount()); m_propertyControllers[name] = dial; } @@ -423,14 +387,85 @@ break; } + case PropertyContainer::ColourProperty: + { + ColourComboBox *cb; + + if (have) { + cb = qobject_cast<ColourComboBox *>(m_propertyControllers[name]); + assert(cb); + } else { +#ifdef DEBUG_PROPERTY_BOX + cerr << "PropertyBox: creating new colour combobox" << endl; +#endif + cb = new ColourComboBox(true); + cb->setObjectName(name); + + connect(cb, SIGNAL(colourChanged(int)), + this, SLOT(propertyControllerChanged(int))); + connect(cb, SIGNAL(mouseEntered()), + this, SLOT(mouseEnteredWidget())); + connect(cb, SIGNAL(mouseLeft()), + this, SLOT(mouseLeftWidget())); + + cb->setToolTip(propertyLabel); + m_groupLayouts[groupName]->addWidget + (cb, 0, m_groupLayouts[groupName]->columnCount()); + m_propertyControllers[name] = cb; + } + + if (cb->currentIndex() != value) { + cb->blockSignals(true); + cb->setCurrentIndex(value); + cb->blockSignals(false); + } + + break; + } + + case PropertyContainer::ColourMapProperty: + { + ColourMapComboBox *cb; + + if (have) { + cb = qobject_cast<ColourMapComboBox *>(m_propertyControllers[name]); + assert(cb); + } else { +#ifdef DEBUG_PROPERTY_BOX + cerr << "PropertyBox: creating new colourmap combobox" << endl; +#endif + cb = new ColourMapComboBox(false); + cb->setObjectName(name); + + connect(cb, SIGNAL(colourMapChanged(int)), + this, SLOT(propertyControllerChanged(int))); + connect(cb, SIGNAL(mouseEntered()), + this, SLOT(mouseEnteredWidget())); + connect(cb, SIGNAL(mouseLeft()), + this, SLOT(mouseLeftWidget())); + + cb->setToolTip(propertyLabel); + m_groupLayouts[groupName]->addWidget + (cb, 0, m_groupLayouts[groupName]->columnCount()); + m_propertyControllers[name] = cb; + } + + if (cb->currentIndex() != value) { + cb->blockSignals(true); + cb->setCurrentIndex(value); + cb->blockSignals(false); + } + + break; + } + case PropertyContainer::ValueProperty: case PropertyContainer::UnitsProperty: - case PropertyContainer::ColourProperty: { NotifyingComboBox *cb; if (have) { - cb = dynamic_cast<NotifyingComboBox *>(m_propertyControllers[name]); + cb = qobject_cast<NotifyingComboBox *>(m_propertyControllers[name]); assert(cb); } else { #ifdef DEBUG_PROPERTY_BOX @@ -463,7 +498,7 @@ } } - } else if (type == PropertyContainer::UnitsProperty) { + } else { // PropertyContainer::UnitsProperty QStringList units = UnitDatabase::getInstance()->getKnownUnits(); for (int i = 0; i < units.size(); ++i) { @@ -471,26 +506,6 @@ } cb->setEditable(true); - - } else { // ColourProperty - - //!!! should be a proper colour combobox class that - // manages its own Add New Colour entry... - - int size = (QFontMetrics(QFont()).height() * 2) / 3; - if (size < 12) size = 12; - - ColourDatabase *db = ColourDatabase::getInstance(); - for (int i = 0; i < db->getColourCount(); ++i) { - QString name = db->getColourName(i); - cb->addItem(db->getExamplePixmap(i, QSize(size, size)), name); - } - cb->addItem(tr("Add New Colour...")); - } - - cb->blockSignals(false); - if (cb->count() < 20 && cb->count() > cb->maxVisibleItems()) { - cb->setMaxVisibleItems(cb->count()); } } @@ -502,19 +517,14 @@ connect(cb, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget())); - if (inGroup) { - cb->setToolTip(propertyLabel); - m_groupLayouts[groupName]->addWidget - (cb, 0, m_groupLayouts[groupName]->columnCount()); - } else { - m_layout->addWidget(cb, row, 1, 1, 2); - } + cb->setToolTip(propertyLabel); + m_groupLayouts[groupName]->addWidget + (cb, 0, m_groupLayouts[groupName]->columnCount()); m_propertyControllers[name] = cb; } cb->blockSignals(true); - if (type == PropertyContainer::ValueProperty || - type == PropertyContainer::ColourProperty) { + if (type == PropertyContainer::ValueProperty) { if (cb->currentIndex() != value) { cb->setCurrentIndex(value); } @@ -531,13 +541,6 @@ } cb->blockSignals(false); -#ifdef Q_OS_MAC - // Crashes on startup without this, for some reason; also - // prevents combo boxes from getting weirdly squished - // vertically - cb->setMinimumSize(QSize(10, cb->font().pixelSize() * 2)); -#endif - break; } @@ -605,22 +608,6 @@ } void -PropertyBox::colourDatabaseChanged() -{ - blockSignals(true); - - PropertyContainer::PropertyList properties = m_container->getProperties(); - for (size_t i = 0; i < properties.size(); ++i) { - if (m_container->getPropertyType(properties[i]) == - PropertyContainer::ColourProperty) { - updatePropertyEditor(properties[i], true); - } - } - - blockSignals(false); -} - -void PropertyBox::propertyControllerChanged(bool on) { propertyControllerChanged(on ? 1 : 0); @@ -642,24 +629,13 @@ if (type == PropertyContainer::UnitsProperty) { - NotifyingComboBox *cb = dynamic_cast<NotifyingComboBox *>(obj); + NotifyingComboBox *cb = qobject_cast<NotifyingComboBox *>(obj); if (cb) { QString unit = cb->currentText(); c = m_container->getSetPropertyCommand (name, UnitDatabase::getInstance()->getUnitId(unit)); } - } else if (type == PropertyContainer::ColourProperty) { - - if (value == int(ColourDatabase::getInstance()->getColourCount())) { - addNewColour(); - if (value == int(ColourDatabase::getInstance()->getColourCount())) { - propertyContainerPropertyChanged(m_container); - return; - } - } - c = m_container->getSetPropertyCommand(name, value); - } else if (type != PropertyContainer::InvalidProperty) { c = m_container->getSetPropertyCommand(name, value); @@ -671,27 +647,9 @@ } void -PropertyBox::addNewColour() -{ - QColor newColour = QColorDialog::getColor(); - if (!newColour.isValid()) return; - - ColourNameDialog dialog(tr("Name New Colour"), - tr("Enter a name for the new colour:"), - newColour, newColour.name(), this); - dialog.showDarkBackgroundCheckbox(tr("Prefer black background for this colour")); - if (dialog.exec() == QDialog::Accepted) { - //!!! command - ColourDatabase *db = ColourDatabase::getInstance(); - int index = db->addColour(newColour, dialog.getColourName()); - db->setUseDarkBackground(index, dialog.isDarkBackgroundChecked()); - } -} - -void PropertyBox::playAudibleChanged(bool audible) { - m_playButton->setState(audible); + m_playButton->setChecked(audible); } void @@ -707,26 +665,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 +683,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); @@ -842,17 +776,34 @@ void PropertyBox::updateContextHelp(QObject *o) { - QWidget *w = dynamic_cast<QWidget *>(o); + QWidget *w = qobject_cast<QWidget *>(o); if (!w) return; if (!m_container) return; 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 = ""; @@ -870,7 +821,7 @@ emit contextHelpChanged(tr("Toggle Playback of %1").arg(cname)); } else if (wname == "") { return; - } else if (dynamic_cast<QAbstractButton *>(w)) { + } else if (qobject_cast<QAbstractButton *>(w)) { emit contextHelpChanged(tr("Toggle %1 property of %2") .arg(wname).arg(cname)); } else {
--- a/widgets/PropertyBox.h Wed Dec 14 11:56:47 2016 +0000 +++ b/widgets/PropertyBox.h Mon Dec 19 16:34:38 2016 +0000 @@ -13,8 +13,8 @@ COPYING included with this distribution for more information. */ -#ifndef _PROPERTY_BOX_H_ -#define _PROPERTY_BOX_H_ +#ifndef SV_PROPERTY_BOX_H +#define SV_PROPERTY_BOX_H #include "base/PropertyContainer.h" @@ -27,6 +27,8 @@ class QVBoxLayout; class QLabel; class LEDButton; +class QToolButton; +class NotifyingPushButton; class PropertyBox : public QFrame { @@ -39,8 +41,6 @@ PropertyContainer *getContainer() { return m_container; } signals: - void changePlayGainDial(int); - void changePlayPanDial(int); void showLayer(bool); void contextHelpChanged(const QString &); @@ -56,15 +56,12 @@ 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(); void unitDatabaseChanged(); - void colourDatabaseChanged(); void editPlayParameters(); @@ -75,7 +72,6 @@ void updatePropertyEditor(PropertyContainer::PropertyName, bool rangeChanged = false); void updateContextHelp(QObject *o); - void addNewColour(); QLabel *m_nameWidget; QWidget *m_mainWidget; @@ -84,7 +80,7 @@ QFrame *m_viewPlayFrame; QVBoxLayout *m_mainBox; LEDButton *m_showButton; - LEDButton *m_playButton; + QToolButton *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 Mon Dec 19 16:34:38 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();
--- a/widgets/Thumbwheel.cpp Wed Dec 14 11:56:47 2016 +0000 +++ b/widgets/Thumbwheel.cpp Mon Dec 19 16:34:38 2016 +0000 @@ -445,35 +445,36 @@ if (!m_cache.isNull()) { QPainter paint(this); - paint.drawImage(0, 0, m_cache); + paint.drawImage(rect(), m_cache, m_cache.rect()); return; } Profiler profiler2("Thumbwheel::paintEvent (no cache)"); - m_cache = QImage(size(), QImage::Format_ARGB32); + QSize imageSize = size() * devicePixelRatio(); + m_cache = QImage(imageSize, QImage::Format_ARGB32); m_cache.fill(Qt::transparent); - int bw = 3; + int w = m_cache.width(); + int h = m_cache.height(); + int bw = 3; // border width QRect subclip; if (m_orientation == Qt::Horizontal) { - subclip = QRect(bw, bw+1, width() - bw*2, height() - bw*2 - 2); + subclip = QRect(bw, bw+1, w - bw*2, h - bw*2 - 2); } else { - subclip = QRect(bw+1, bw, width() - bw*2 - 2, height() - bw*2); + subclip = QRect(bw+1, bw, w - bw*2 - 2, h - bw*2); } QPainter paint(&m_cache); - paint.setClipRect(rect()); + paint.setClipRect(m_cache.rect()); paint.fillRect(subclip, palette().background().color()); paint.setRenderHint(QPainter::Antialiasing, true); - double w = width(); double w0 = 0.5; double w1 = w - 0.5; - double h = height(); double h0 = 0.5; double h1 = h - 0.5; @@ -508,13 +509,13 @@ // cerr << "value = " << m_value << ", min = " << m_min << ", max = " << m_max << ", rotation = " << rotation << endl; - w = (m_orientation == Qt::Horizontal ? width() : height()) - bw*2; + int ww = (m_orientation == Qt::Horizontal ? w : h) - bw*2; // wheel width // total number of notches on the entire wheel int notches = 25; // radius of the wheel including invisible part - int radius = int(w / 2 + 2); + int radius = int(ww / 2 + 2); for (int i = 0; i < notches; ++i) { @@ -525,13 +526,13 @@ double depth = cos((a0 + a2) / 2); if (depth < 0) continue; - double x0 = radius * sin(a0) + w/2; - double x1 = radius * sin(a1) + w/2; - double x2 = radius * sin(a2) + w/2; - if (x2 < 0 || x0 > w) continue; + double x0 = radius * sin(a0) + ww/2; + double x1 = radius * sin(a1) + ww/2; + double x2 = radius * sin(a2) + ww/2; + if (x2 < 0 || x0 > ww) continue; if (x0 < 0) x0 = 0; - if (x2 > w) x2 = w; + if (x2 > ww) x2 = ww; x0 += bw; x1 += bw; @@ -557,10 +558,10 @@ } if (m_orientation == Qt::Horizontal) { - paint.drawRect(QRectF(x1, height() - (height() - bw*2) * prop - bw, - x2 - x1, height() * prop)); + paint.drawRect(QRectF(x1, h - (h - bw*2) * prop - bw, + x2 - x1, h * prop)); } else { - paint.drawRect(QRectF(bw, x1, (width() - bw*2) * prop, x2 - x1)); + paint.drawRect(QRectF(bw, x1, (w - bw*2) * prop, x2 - x1)); } } @@ -568,14 +569,14 @@ paint.setBrush(palette().background().color()); if (m_orientation == Qt::Horizontal) { - paint.drawRect(QRectF(x0, bw, x1 - x0, height() - bw*2)); + paint.drawRect(QRectF(x0, bw, x1 - x0, h - bw*2)); } else { - paint.drawRect(QRectF(bw, x0, width() - bw*2, x1 - x0)); + paint.drawRect(QRectF(bw, x0, w - bw*2, x1 - x0)); } } QPainter paint2(this); - paint2.drawImage(0, 0, m_cache); + paint2.drawImage(rect(), m_cache, m_cache.rect()); } QSize
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/WidgetScale.h Mon Dec 19 16:34:38 2016 +0000 @@ -0,0 +1,59 @@ +/* -*- 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> + +#include "base/Debug.h" + +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; + SVDEBUG << "WidgetScale::scalePixelSize: baseEm = " << baseEm + << ", platform default font height = " << em + << ", resulting scale factor = " << ratio << endl; + } + + 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