Chris@58: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
Chris@0: 
Chris@0: /*
Chris@59:     Sonic Visualiser
Chris@59:     An audio file viewer and annotation editor.
Chris@59:     Centre for Digital Music, Queen Mary, University of London.
Chris@0:     
Chris@59:     This program is free software; you can redistribute it and/or
Chris@59:     modify it under the terms of the GNU General Public License as
Chris@59:     published by the Free Software Foundation; either version 2 of the
Chris@59:     License, or (at your option) any later version.  See the file
Chris@59:     COPYING included with this distribution for more information.
Chris@0: */
Chris@0: 
Chris@0: /**
Chris@0:  * Horizontal audio fader and meter widget.
Chris@0:  *
Chris@0:  * Based on the vertical fader and meter widget from the Hydrogen drum
Chris@0:  * machine.  (Any poor taste that has crept in during the
Chris@0:  * modifications for this application is entirely my own, however.)
Chris@0:  * The following copyright notice applies to code from this file, and
Chris@0:  * also to the files in icons/fader_*.png (also modified by me). --cc
Chris@0:  */
Chris@0: 
Chris@0: /**
Chris@0:  * Hydrogen
Chris@0:  * Copyright(c) 2002-2005 by Alex >Comix< Cominu [comix@users.sourceforge.net]
Chris@0:  * http://www.hydrogen-music.org
Chris@0:  */
Chris@0: 
Chris@0: 
Chris@0: #include "Fader.h"
Chris@0: 
Chris@0: #include "base/AudioLevel.h"
Chris@0: 
Chris@0: #include <QMouseEvent>
Chris@0: #include <QPixmap>
Chris@0: #include <QWheelEvent>
Chris@0: #include <QPaintEvent>
Chris@0: #include <QPainter>
Chris@187: #include <QInputDialog>
Chris@187: 
Chris@187: #include <iostream>
Chris@0: 
Chris@0: Fader::Fader(QWidget *parent, bool withoutKnob) :
Chris@0:     QWidget(parent),
Chris@0:     m_withoutKnob(withoutKnob),
Chris@0:     m_value(1.0),
Chris@0:     m_peakLeft(0.0),
Chris@187:     m_peakRight(0.0),
Chris@187:     m_mousePressed(false)
Chris@0: {
Chris@0:     setMinimumSize(116, 23);
Chris@0:     setMaximumSize(116, 23);
Chris@0:     resize(116, 23);
Chris@0: 
Chris@0:     QString background_path = ":/icons/fader_background.png";
Chris@0:     bool ok = m_back.load(background_path);
Chris@0:     if (ok == false) {
Chris@682: 	cerr << "Fader: Error loading pixmap" << endl;
Chris@0:     }
Chris@0: 
Chris@0:     QString leds_path = ":/icons/fader_leds.png";
Chris@0:     ok = m_leds.load(leds_path);
Chris@0:     if (ok == false) {
Chris@682: 	cerr <<  "Error loading pixmap" << endl;
Chris@0:     }
Chris@0: 
Chris@0:     QString knob_path = ":/icons/fader_knob.png";
Chris@0:     ok = m_knob.load(knob_path);
Chris@0:     if (ok == false) {
Chris@682: 	cerr <<  "Error loading pixmap" << endl;
Chris@0:     }
Chris@0: 
Chris@0:     QString clip_path = ":/icons/fader_knob_red.png";
Chris@0:     ok = m_clip.load(clip_path);
Chris@0:     if (ok == false) {
Chris@682: 	cerr <<  "Error loading pixmap" << endl;
Chris@0:     }
Chris@0: }
Chris@0: 
Chris@0: Fader::~Fader()
Chris@0: {
Chris@0: 
Chris@0: }
Chris@0: 
Chris@0: void
Chris@0: Fader::mouseMoveEvent(QMouseEvent *ev)
Chris@0: {
Chris@141:     if (ev->button() == Qt::MidButton) {
Chris@187:         setValue(1.0);
Chris@187:         emit valueChanged(1.0);
Chris@187:         update();
Chris@144:         ev->accept();
Chris@141:         return;
Chris@141:     }
Chris@187:     if (!m_mousePressed) return;
Chris@141: 
Chris@187:     int x = ev->x();
Chris@187:     int diff = x - m_mousePressX;
Chris@187:     if (diff == 0) return;
Chris@0: 
Chris@187:     int vx = AudioLevel::multiplier_to_fader
Chris@187:         (m_mousePressValue, getMaxX(), AudioLevel::LongFader);
Chris@0: 
Chris@187:     vx += diff;
Chris@0: 
Chris@187:     if (vx > getMaxX()) vx = getMaxX();
Chris@187:     if (vx < 0) vx = 0;
Chris@187: 
Chris@0:     float fval = AudioLevel::fader_to_multiplier
Chris@187: 	(vx, getMaxX(), AudioLevel::LongFader);
Chris@0: 
Chris@0:     setValue(fval);
Chris@0:     emit valueChanged(fval);
Chris@187:     ev->accept();
Chris@0: }
Chris@0: 
Chris@0: 
Chris@0: void
Chris@132: Fader::mouseReleaseEvent(QMouseEvent *ev)
Chris@132: {
Chris@187:     if (m_mousePressed) {
Chris@187:         mouseMoveEvent(ev);
Chris@187:         m_mousePressed = false;
Chris@187:     }
Chris@132: }
Chris@132: 
Chris@132: void
Chris@0: Fader::mouseDoubleClickEvent(QMouseEvent *)
Chris@0: {
Chris@187:     bool ok = false;
Chris@187:     float min = AudioLevel::fader_to_dB
Chris@187:         (0, getMaxX(), AudioLevel::LongFader);
Chris@187:     float max = AudioLevel::fader_to_dB
Chris@187:         (getMaxX(), getMaxX(), AudioLevel::LongFader);
Chris@187:     float deft = AudioLevel::multiplier_to_dB(m_value);
Chris@187: 
Chris@187:     float dB = QInputDialog::getDouble
Chris@187:         (this,
Chris@187:          tr("Enter new fader level"),
Chris@187:          tr("New fader level, from %1 to %2 dBFS:").arg(min).arg(max),
Chris@187:          deft, min, max, 3, &ok);
Chris@187: 
Chris@187:     if (ok) {
Chris@187:         float value = AudioLevel::dB_to_multiplier(dB);
Chris@187:         setValue(value);
Chris@187:         emit valueChanged(value);
Chris@187:         update();
Chris@187:     }
Chris@0: }
Chris@0: 
Chris@0: void
Chris@0: Fader::mousePressEvent(QMouseEvent *ev)
Chris@0: {
Chris@187:     if (ev->button() == Qt::MidButton ||
Chris@187:         ((ev->button() == Qt::LeftButton) &&
Chris@187:          (ev->modifiers() & Qt::ControlModifier))) {
Chris@82:         setValue(1.0);
Chris@82:         emit valueChanged(1.0);
Chris@82:         update();
Chris@82:         return;
Chris@82:     }
Chris@82: 
Chris@187:     if (ev->button() != Qt::LeftButton) return;
Chris@187:     m_mousePressed = true;
Chris@187:     m_mousePressX = ev->x();
Chris@187:     m_mousePressValue = getValue();
Chris@0: }
Chris@0: 
Chris@0: 
Chris@0: void
Chris@0: Fader::wheelEvent(QWheelEvent *ev)
Chris@0: {
Chris@0:     ev->accept();
Chris@0: 
Chris@0:     //!!! needs improvement
Chris@0: 
Chris@0:     if (ev->delta() > 0) {
Chris@0: 	setValue(m_value * 1.1);
Chris@0:     } else {
Chris@0: 	setValue(m_value / 1.1);
Chris@0:     }
Chris@0: 
Chris@0:     update();
Chris@0:     emit valueChanged(getValue());
Chris@0: }
Chris@0: 
Chris@189: void
Chris@189: Fader::enterEvent(QEvent *)
Chris@189: {
Chris@189:     emit mouseEntered();
Chris@189: }
Chris@189: 
Chris@189: void
Chris@189: Fader::leaveEvent(QEvent *)
Chris@189: {
Chris@189:     emit mouseLeft();
Chris@189: }
Chris@0: 
Chris@0: void
Chris@0: Fader::setValue(float v)
Chris@0: {
Chris@0:     float max = AudioLevel::dB_to_multiplier(10.0);
Chris@0: 
Chris@0:     if (v > max) {
Chris@0: 	v = max;
Chris@0:     } else if (v < 0.0) {
Chris@0: 	v = 0.0;
Chris@0:     }
Chris@0: 
Chris@0:     if (m_value != v) {
Chris@0: 	m_value = v;
Chris@0: 	float db = AudioLevel::multiplier_to_dB(m_value);
Chris@187:         QString text;
Chris@0: 	if (db <= AudioLevel::DB_FLOOR) {
Chris@187:             text = tr("Level: Off");
Chris@0: 	} else {
Chris@187:             text = tr("Level: %1%2.%3%4 dB")
Chris@187:                 .arg(db < 0.0 ? "-" : "")
Chris@187:                 .arg(abs(int(db)))
Chris@187:                 .arg(abs(int(db * 10.0) % 10))
Chris@187:                 .arg(abs(int(db * 100.0) % 10));
Chris@0: 	}
Chris@682:         cerr << "Fader: setting tooltip to \"" << text << "\"" << endl;
Chris@187:         QWidget::setToolTip(text);
Chris@0: 	update();
Chris@0:     }
Chris@0: }
Chris@0: 
Chris@0: 
Chris@0: float
Chris@0: Fader::getValue()
Chris@0: {
Chris@0:     return m_value;
Chris@0: }
Chris@0: 
Chris@0: 
Chris@0: 
Chris@0: void
Chris@0: Fader::setPeakLeft(float peak)
Chris@0: {
Chris@0:     if (this->m_peakLeft != peak) {
Chris@0: 	this->m_peakLeft = peak;
Chris@0: 	update();
Chris@0:     }
Chris@0: }
Chris@0: 
Chris@0: 
Chris@0: void
Chris@0: Fader::setPeakRight(float peak) 
Chris@0: {
Chris@0:     if (this->m_peakRight != peak) {
Chris@0: 	this->m_peakRight = peak;
Chris@0: 	update();
Chris@0:     }
Chris@0: }
Chris@0: 
Chris@0: 
Chris@0: void
Chris@0: Fader::paintEvent(QPaintEvent *)
Chris@0: {
Chris@0:     QPainter painter(this);
Chris@0: 
Chris@0:     // background
Chris@0:     painter.drawPixmap(rect(), m_back, QRect(0, 0, 116, 23));
Chris@0: 
Chris@0:     int offset_L = AudioLevel::multiplier_to_fader(m_peakLeft, 116,
Chris@0: 						   AudioLevel::IEC268LongMeter);
Chris@0: 
Chris@0:     painter.drawPixmap(QRect(0, 0, offset_L, 11), m_leds,
Chris@0: 		       QRect(0, 0, offset_L, 11));
Chris@0: 
Chris@0:     int offset_R = AudioLevel::multiplier_to_fader(m_peakRight, 116,
Chris@0: 						   AudioLevel::IEC268LongMeter);
Chris@0: 
Chris@0:     painter.drawPixmap(QRect(0, 11, offset_R, 11), m_leds,
Chris@0: 		       QRect(0, 11, offset_R, 11));
Chris@0: 
Chris@0:     if (m_withoutKnob == false) {
Chris@0: 
Chris@0: 	static const uint knob_width = 29;
Chris@0: 	static const uint knob_height = 9;
Chris@0: 
Chris@0: 	int x = AudioLevel::multiplier_to_fader(m_value, 116 - knob_width,
Chris@0: 						AudioLevel::LongFader);
Chris@0: 
Chris@0: 	bool clipping = (m_peakLeft > 1.0 || m_peakRight > 1.0);
Chris@0: 
Chris@0: 	painter.drawPixmap(QRect(x, 7, knob_width, knob_height),
Chris@0: 			   clipping ? m_clip : m_knob,
Chris@0: 			   QRect(0, 0, knob_width, knob_height));
Chris@0:     }
Chris@0: }
Chris@0: 
Chris@187: int
Chris@187: Fader::getMaxX() const
Chris@187: {
Chris@187:     return 116 - 12;
Chris@187: }