Chris@929: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
Chris@929: 
Chris@929: /*
Chris@929:     Sonic Visualiser
Chris@929:     An audio file viewer and annotation editor.
Chris@929:     Centre for Digital Music, Queen Mary, University of London.
Chris@929:     
Chris@929:     This program is free software; you can redistribute it and/or
Chris@929:     modify it under the terms of the GNU General Public License as
Chris@929:     published by the Free Software Foundation; either version 2 of the
Chris@929:     License, or (at your option) any later version.  See the file
Chris@929:     COPYING included with this distribution for more information.
Chris@929: */
Chris@929: 
Chris@929: #include "LevelPanToolButton.h"
Chris@929: #include "LevelPanWidget.h"
Chris@929: 
Chris@929: #include <QMenu>
Chris@929: #include <QWidgetAction>
Chris@929: #include <QImage>
Chris@1300: #include <QMouseEvent>
Chris@936: #include <QStylePainter>
Chris@936: #include <QStyleOptionToolButton>
Chris@1589: #include <QMenu>
Chris@929: 
Chris@1300: #include "base/Debug.h"
Chris@1589: #include "base/AudioLevel.h"
Chris@1589: #include "MenuTitle.h"
Chris@1300: 
Chris@929: #include <iostream>
Chris@929: using std::cerr;
Chris@929: using std::endl;
Chris@929: 
Chris@929: LevelPanToolButton::LevelPanToolButton(QWidget *parent) :
Chris@929:     QToolButton(parent),
Chris@930:     m_pixels(32),
Chris@942:     m_pixelsBig(32 * 3),
Chris@930:     m_muted(false),
Chris@1589:     m_savedLevel(1.f),
Chris@1589:     m_provideContextMenu(true),
Chris@1589:     m_lastContextMenu(nullptr)
Chris@929: {
Chris@929:     m_lpw = new LevelPanWidget();
Chris@929: 
Chris@929:     connect(m_lpw, SIGNAL(levelChanged(float)), this, SIGNAL(levelChanged(float)));
Chris@930:     connect(m_lpw, SIGNAL(levelChanged(float)), this, SLOT(selfLevelChanged(float)));
Chris@929: 
Chris@929:     connect(m_lpw, SIGNAL(panChanged(float)), this, SIGNAL(panChanged(float)));
Chris@932:     connect(m_lpw, SIGNAL(panChanged(float)), this, SLOT(update()));
Chris@930: 
Chris@930:     connect(this, SIGNAL(clicked(bool)), this, SLOT(selfClicked()));
Chris@929:     
Chris@929:     QMenu *menu = new QMenu();
Chris@929:     QWidgetAction *wa = new QWidgetAction(menu);
Chris@929:     wa->setDefaultWidget(m_lpw);
Chris@929:     menu->addAction(wa);
Chris@929: 
Chris@936:     setPopupMode(InstantPopup);
Chris@929:     setMenu(menu);
Chris@1191:     setToolTip(tr("Click to adjust level and pan"));
Chris@929: 
Chris@932:     setImageSize(m_pixels);
Chris@942:     setBigImageSize(m_pixelsBig);
Chris@1589:     
Chris@1589:     setContextMenuPolicy(Qt::CustomContextMenu);
Chris@1589:     connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
Chris@1589:             this, SLOT(contextMenuRequested(const QPoint &)));
Chris@929: }
Chris@929: 
Chris@929: LevelPanToolButton::~LevelPanToolButton()
Chris@929: {
Chris@1589:     delete m_lastContextMenu;
Chris@929: }
Chris@929: 
Chris@1200: void
Chris@1300: LevelPanToolButton::mousePressEvent(QMouseEvent *e)
Chris@1300: {
Chris@1300:     if (e->button() == Qt::MidButton ||
Chris@1300:         ((e->button() == Qt::LeftButton) &&
Chris@1300:          (e->modifiers() & Qt::ControlModifier))) {
Chris@1300:         m_lpw->setToDefault();
Chris@1300:         e->accept();
Chris@1300:     } else {
Chris@1300:         QToolButton::mousePressEvent(e);
Chris@1300:     }
Chris@1300: }
Chris@1300: 
Chris@1300: void
Chris@1200: LevelPanToolButton::wheelEvent(QWheelEvent *e)
Chris@1200: {
Chris@1200:     m_lpw->wheelEvent(e);
Chris@1200: }
Chris@1200: 
Chris@929: float
Chris@929: LevelPanToolButton::getLevel() const
Chris@929: {
Chris@929:     return m_lpw->getLevel();
Chris@929: }
Chris@929: 
Chris@929: float
Chris@929: LevelPanToolButton::getPan() const
Chris@929: {
Chris@929:     return m_lpw->getPan();
Chris@929: }
Chris@929: 
Chris@940: bool
Chris@940: LevelPanToolButton::includesMute() const
Chris@940: {
Chris@940:     return m_lpw->includesMute();
Chris@940: }
Chris@940: 
Chris@929: void
Chris@929: LevelPanToolButton::setImageSize(int pixels)
Chris@929: {
Chris@929:     m_pixels = pixels;
Chris@932: 
Chris@932:     QPixmap px(m_pixels, m_pixels);
Chris@932:     px.fill(Qt::transparent);
Chris@932:     setIcon(px);
Chris@942: }
Chris@932: 
Chris@942: void
Chris@1589: LevelPanToolButton::setProvideContextMenu(bool provide)
Chris@1589: {
Chris@1589:     m_provideContextMenu = provide;
Chris@1589: }
Chris@1589: 
Chris@1589: void
Chris@942: LevelPanToolButton::setBigImageSize(int pixels)
Chris@942: {
Chris@942:     m_pixelsBig = pixels;
Chris@942: 
Chris@942:     m_lpw->setFixedWidth(m_pixelsBig);
Chris@942:     m_lpw->setFixedHeight(m_pixelsBig);
Chris@929: }
Chris@929: 
Chris@929: void
Chris@929: LevelPanToolButton::setLevel(float level)
Chris@929: {
Chris@929:     m_lpw->setLevel(level);
Chris@932:     update();
Chris@929: }
Chris@929: 
Chris@929: void
Chris@929: LevelPanToolButton::setPan(float pan)
Chris@929: {
Chris@929:     m_lpw->setPan(pan);
Chris@932:     update();
Chris@930: }
Chris@930: 
Chris@930: void
Chris@1187: LevelPanToolButton::setMonitoringLevels(float left, float right)
Chris@1187: {
Chris@1187:     m_lpw->setMonitoringLevels(left, right);
Chris@1187:     update();
Chris@1187: }
Chris@1187: 
Chris@1187: void
Chris@940: LevelPanToolButton::setIncludeMute(bool include)
Chris@940: {
Chris@940:     m_lpw->setIncludeMute(include);
Chris@940:     update();
Chris@940: }
Chris@940: 
Chris@940: void
Chris@933: LevelPanToolButton::setEnabled(bool enabled)
Chris@933: {
Chris@933:     m_lpw->setEnabled(enabled);
Chris@933:     QToolButton::setEnabled(enabled);
Chris@933: }
Chris@933: 
Chris@933: void
Chris@930: LevelPanToolButton::selfLevelChanged(float level)
Chris@930: {
Chris@930:     if (level > 0.f) {
Chris@1266:         m_muted = false;
Chris@930:     } else {
Chris@1266:         m_muted = true;
Chris@1266:         m_savedLevel = 1.f;
Chris@930:     }
Chris@932:     update();
Chris@930: }
Chris@930: 
Chris@930: void
Chris@930: LevelPanToolButton::selfClicked()
Chris@930: {
Chris@930:     if (m_muted) {
Chris@1266:         m_muted = false;
Chris@1266:         m_lpw->setLevel(m_savedLevel);
Chris@1266:         emit levelChanged(m_savedLevel);
Chris@930:     } else {
Chris@1266:         m_savedLevel = m_lpw->getLevel();
Chris@1266:         m_muted = true;
Chris@1266:         m_lpw->setLevel(0.f);
Chris@1266:         emit levelChanged(0.f);
Chris@930:     }
Chris@932:     update();
Chris@929: }
Chris@929: 
Chris@929: void
Chris@1589: LevelPanToolButton::contextMenuRequested(const QPoint &pos)
Chris@1589: {
Chris@1589:     if (!m_provideContextMenu) {
Chris@1589:         return;
Chris@1589:     }
Chris@1589:     
Chris@1589:     delete m_lastContextMenu;
Chris@1589:     m_lastContextMenu = new QMenu;
Chris@1589:     auto m = m_lastContextMenu;
Chris@1589: 
Chris@1589:     QString title;
Chris@1589: 
Chris@1589:     if (m_muted) {
Chris@1589:         title = tr("Muted");
Chris@1589:     } else {
Chris@1589:         // Pan is actually stereo balance in most applications...
Chris@1589:         auto level = AudioLevel::multiplier_to_dB(m_lpw->getLevel());
Chris@1589:         auto pan = m_lpw->getPan();
Chris@1589:         if (pan == 0) {
Chris@1589:             title = tr("Level: %1 dB - Balance: Middle").arg(level);
Chris@1589:         } else if (pan > 0) {
Chris@1589:             title = tr("Level: %1 dB - Balance: +%2").arg(level).arg(pan);
Chris@1589:         } else {
Chris@1589:             title = tr("Level: %1 dB - Balance: %2").arg(level).arg(pan);
Chris@1589:         }
Chris@1589:     }
Chris@1589:     
Chris@1589:     MenuTitle::addTitle(m, title);
Chris@1589: 
Chris@1602:     m->addAction(tr("&Reset to Default"), m_lpw, SLOT(setToDefault()));
Chris@1589: 
Chris@1589:     m->popup(mapToGlobal(pos));
Chris@1589: }
Chris@1589: 
Chris@1589: void
Chris@936: LevelPanToolButton::paintEvent(QPaintEvent *)
Chris@929: {
Chris@936:     QStylePainter p(this);
Chris@936:     QStyleOptionToolButton opt;
Chris@936:     initStyleOption(&opt);
Chris@936:     opt.features &= (~QStyleOptionToolButton::HasMenu);
Chris@936:     p.drawComplexControl(QStyle::CC_ToolButton, opt);
Chris@936:     
Chris@934:     if (m_pixels >= height()) {
Chris@934:         setImageSize(height()-1);
Chris@934:     }
Chris@936:     
Chris@932:     double margin = (double(height()) - m_pixels) / 2.0;
Chris@932:     m_lpw->renderTo(this, QRectF(margin, margin, m_pixels, m_pixels), false);
Chris@929: }
Chris@929: 
Chris@1180: void
Chris@1180: LevelPanToolButton::enterEvent(QEvent *e)
Chris@1180: {
Chris@1180:     QToolButton::enterEvent(e);
Chris@1180:     emit mouseEntered();
Chris@1180: }
Chris@932: 
Chris@1180: void
Chris@1180: LevelPanToolButton::leaveEvent(QEvent *e)
Chris@1180: {
Chris@1180:     QToolButton::enterEvent(e);
Chris@1180:     emit mouseLeft();
Chris@1180: }
Chris@1180: 
Chris@1180: