Make Knob inherit from FloatModelEditorBase
Make `Knob` inherit from `FloatModelEditorBase`. This is mostly a continuation for the changes introduced with commit c63d86f.
The idea is that `FloatModelEditorBase` contains the underlying functionality and logic to deal with float models. `Knob` and other classes then only override the presentation aspects. This way `Knob` and `BarModelEditor` can share the same functionality but can differ in how they present the data.
Technical details
------------------
Remove all methods that are already defined in `FloatModelEditorBase` from `Knob`. These are all methods that are defined in the same way in `FloatModelEditorBase`. The method `paintEvent` is not removed because it is overridden by `Knob` as it has its own presentation.
Remove forward declaration of `QPixmap` from `FloatModelEditorBase` as it was not used. Remove unused function `convertPixmapToGrayScaleTemp` from `FloatModelEditorBase`.
This commit is contained in:
@@ -32,16 +32,11 @@
|
||||
#include "AutomatableModelView.h"
|
||||
|
||||
|
||||
class QPixmap;
|
||||
|
||||
namespace lmms::gui
|
||||
{
|
||||
|
||||
|
||||
class SimpleTextFloat;
|
||||
|
||||
void convertPixmapToGrayScaleTemp(QPixmap &pixMap);
|
||||
|
||||
class LMMS_EXPORT FloatModelEditorBase : public QWidget, public FloatModelView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include <QPoint>
|
||||
#include <QTextDocument>
|
||||
|
||||
#include "AutomatableModelView.h"
|
||||
#include "FloatModelEditorBase.h"
|
||||
|
||||
|
||||
class QPixmap;
|
||||
@@ -50,7 +50,7 @@ enum class KnobType
|
||||
|
||||
void convertPixmapToGrayScale(QPixmap &pixMap);
|
||||
|
||||
class LMMS_EXPORT Knob : public QWidget, public FloatModelView
|
||||
class LMMS_EXPORT Knob : public FloatModelEditorBase
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS( KnobType )
|
||||
@@ -72,9 +72,6 @@ class LMMS_EXPORT Knob : public QWidget, public FloatModelView
|
||||
Q_PROPERTY(QColor arcActiveColor MEMBER m_arcActiveColor)
|
||||
Q_PROPERTY(QColor arcInactiveColor MEMBER m_arcInactiveColor)
|
||||
|
||||
mapPropertyFromModel(bool,isVolumeKnob,setVolumeKnob,m_volumeKnob);
|
||||
mapPropertyFromModel(float,volumeRatio,setVolumeRatio,m_volumeRatio);
|
||||
|
||||
Q_PROPERTY(KnobType knobNum READ knobNum WRITE setknobNum)
|
||||
|
||||
Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor)
|
||||
@@ -87,13 +84,6 @@ public:
|
||||
Knob( QWidget * _parent = nullptr, const QString & _name = QString() ); //!< default ctor
|
||||
Knob( const Knob& other ) = delete;
|
||||
|
||||
// TODO: remove
|
||||
inline void setHintText( const QString & _txt_before,
|
||||
const QString & _txt_after )
|
||||
{
|
||||
setDescription( _txt_before );
|
||||
setUnit( _txt_after );
|
||||
}
|
||||
void setLabel( const QString & txt );
|
||||
void setHtmlLabel( const QString &htmltxt );
|
||||
|
||||
@@ -125,46 +115,16 @@ public:
|
||||
void setTextColor( const QColor & c );
|
||||
|
||||
|
||||
signals:
|
||||
void sliderPressed();
|
||||
void sliderReleased();
|
||||
void sliderMoved( float value );
|
||||
|
||||
|
||||
protected:
|
||||
void contextMenuEvent( QContextMenuEvent * _me ) override;
|
||||
void dragEnterEvent( QDragEnterEvent * _dee ) override;
|
||||
void dropEvent( QDropEvent * _de ) override;
|
||||
void focusOutEvent( QFocusEvent * _fe ) override;
|
||||
void mousePressEvent( QMouseEvent * _me ) override;
|
||||
void mouseReleaseEvent( QMouseEvent * _me ) override;
|
||||
void mouseMoveEvent( QMouseEvent * _me ) override;
|
||||
void mouseDoubleClickEvent( QMouseEvent * _me ) override;
|
||||
void paintEvent( QPaintEvent * _me ) override;
|
||||
void wheelEvent( QWheelEvent * _me ) override;
|
||||
|
||||
void changeEvent(QEvent * ev) override;
|
||||
|
||||
void enterEvent(QEvent *event) override;
|
||||
void leaveEvent(QEvent *event) override;
|
||||
|
||||
virtual float getValue( const QPoint & _p );
|
||||
|
||||
private slots:
|
||||
virtual void enterValue();
|
||||
void friendlyUpdate();
|
||||
void toggleScale();
|
||||
|
||||
private:
|
||||
virtual QString displayValue() const;
|
||||
|
||||
void doConnections() override;
|
||||
|
||||
QLineF calculateLine( const QPointF & _mid, float _radius,
|
||||
float _innerRadius = 1) const;
|
||||
|
||||
void drawKnob( QPainter * _p );
|
||||
void showTextFloat(int msecBeforeDisplay, int msecDisplayTime);
|
||||
void setPosition( const QPoint & _p );
|
||||
bool updateAngle();
|
||||
|
||||
int angleFromValue( float value, float minValue, float maxValue, float totalAngle ) const
|
||||
@@ -172,25 +132,11 @@ private:
|
||||
return static_cast<int>( ( value - 0.5 * ( minValue + maxValue ) ) / ( maxValue - minValue ) * m_totalAngle ) % 360;
|
||||
}
|
||||
|
||||
inline float pageSize() const
|
||||
{
|
||||
return ( model()->maxValue() - model()->minValue() ) / 100.0f;
|
||||
}
|
||||
|
||||
|
||||
static SimpleTextFloat * s_textFloat;
|
||||
|
||||
QString m_label;
|
||||
bool m_isHtmlLabel;
|
||||
QTextDocument* m_tdRenderer;
|
||||
|
||||
std::unique_ptr<QPixmap> m_knobPixmap;
|
||||
BoolModel m_volumeKnob;
|
||||
FloatModel m_volumeRatio;
|
||||
|
||||
QPoint m_lastMousePos; //!< mouse position in last mouseMoveEvent
|
||||
float m_leftOver;
|
||||
bool m_buttonPressed;
|
||||
|
||||
float m_totalAngle;
|
||||
int m_angle;
|
||||
@@ -211,9 +157,7 @@ private:
|
||||
QColor m_textColor;
|
||||
|
||||
KnobType m_knobNum;
|
||||
|
||||
} ;
|
||||
|
||||
};
|
||||
|
||||
} // namespace lmms::gui
|
||||
|
||||
|
||||
@@ -490,21 +490,4 @@ void FloatModelEditorBase::doConnections()
|
||||
}
|
||||
|
||||
|
||||
void convertPixmapToGrayScaleTemp(QPixmap& pixMap)
|
||||
{
|
||||
QImage temp = pixMap.toImage().convertToFormat(QImage::Format_ARGB32);
|
||||
for (int i = 0; i < temp.height(); ++i)
|
||||
{
|
||||
for (int j = 0; j < temp.width(); ++j)
|
||||
{
|
||||
const auto pix = temp.pixelColor(i, j);
|
||||
const auto gscale = 0.2126 * pix.redF() + 0.7152 * pix.greenF() + 0.0722 * pix.blueF();
|
||||
const auto pixGray = QColor::fromRgbF(gscale, gscale, gscale, pix.alphaF());
|
||||
temp.setPixelColor(i, j, pixGray);
|
||||
}
|
||||
}
|
||||
pixMap.convertFromImage(temp);
|
||||
}
|
||||
|
||||
|
||||
} // namespace lmms::gui
|
||||
|
||||
@@ -52,20 +52,11 @@
|
||||
namespace lmms::gui
|
||||
{
|
||||
|
||||
SimpleTextFloat * Knob::s_textFloat = nullptr;
|
||||
|
||||
|
||||
|
||||
|
||||
Knob::Knob( KnobType _knob_num, QWidget * _parent, const QString & _name ) :
|
||||
QWidget( _parent ),
|
||||
FloatModelView( new FloatModel( 0, 0, 0, 1, nullptr, _name, true ), this ),
|
||||
FloatModelEditorBase(DirectionOfManipulation::Vertical, _parent, _name),
|
||||
m_label( "" ),
|
||||
m_isHtmlLabel(false),
|
||||
m_tdRenderer(nullptr),
|
||||
m_volumeKnob( false ),
|
||||
m_volumeRatio( 100.0, 0.0, 1000000.0 ),
|
||||
m_buttonPressed( false ),
|
||||
m_angle( -10 ),
|
||||
m_lineWidth( 0 ),
|
||||
m_textColor( 255, 255, 255 ),
|
||||
@@ -84,18 +75,10 @@ Knob::Knob( QWidget * _parent, const QString & _name ) :
|
||||
|
||||
void Knob::initUi( const QString & _name )
|
||||
{
|
||||
if( s_textFloat == nullptr )
|
||||
{
|
||||
s_textFloat = new SimpleTextFloat;
|
||||
}
|
||||
|
||||
setWindowTitle( _name );
|
||||
|
||||
onKnobNumUpdated();
|
||||
setTotalAngle( 270.0f );
|
||||
setInnerRadius( 1.0f );
|
||||
setOuterRadius( 10.0f );
|
||||
setFocusPolicy( Qt::ClickFocus );
|
||||
|
||||
// This is a workaround to enable style sheets for knobs which are not styled knobs.
|
||||
//
|
||||
@@ -123,13 +106,9 @@ void Knob::initUi( const QString & _name )
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
doConnections();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Knob::onKnobNumUpdated()
|
||||
{
|
||||
if( m_knobNum != KnobType::Styled )
|
||||
@@ -484,195 +463,6 @@ void Knob::drawKnob( QPainter * _p )
|
||||
_p->drawImage( 0, 0, m_cache );
|
||||
}
|
||||
|
||||
void Knob::showTextFloat(int msecBeforeDisplay, int msecDisplayTime)
|
||||
{
|
||||
s_textFloat->setText(displayValue());
|
||||
s_textFloat->moveGlobal(this, QPoint(width() + 2, 0));
|
||||
s_textFloat->showWithDelay(msecBeforeDisplay, msecDisplayTime);
|
||||
}
|
||||
|
||||
float Knob::getValue( const QPoint & _p )
|
||||
{
|
||||
float value;
|
||||
|
||||
// knob value increase is linear to mouse movement
|
||||
value = .4f * _p.y();
|
||||
|
||||
// if shift pressed we want slower movement
|
||||
if( getGUI()->mainWindow()->isShiftPressed() )
|
||||
{
|
||||
value /= 4.0f;
|
||||
value = qBound( -4.0f, value, 4.0f );
|
||||
}
|
||||
return value * pageSize();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Knob::contextMenuEvent( QContextMenuEvent * )
|
||||
{
|
||||
// for the case, the user clicked right while pressing left mouse-
|
||||
// button, the context-menu appears while mouse-cursor is still hidden
|
||||
// and it isn't shown again until user does something which causes
|
||||
// an QApplication::restoreOverrideCursor()-call...
|
||||
mouseReleaseEvent( nullptr );
|
||||
|
||||
CaptionMenu contextMenu( model()->displayName(), this );
|
||||
addDefaultActions( &contextMenu );
|
||||
contextMenu.addAction( QPixmap(),
|
||||
model()->isScaleLogarithmic() ? tr( "Set linear" ) : tr( "Set logarithmic" ),
|
||||
this, SLOT(toggleScale()));
|
||||
contextMenu.addSeparator();
|
||||
contextMenu.exec( QCursor::pos() );
|
||||
}
|
||||
|
||||
|
||||
void Knob::toggleScale()
|
||||
{
|
||||
model()->setScaleLogarithmic( ! model()->isScaleLogarithmic() );
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Knob::dragEnterEvent( QDragEnterEvent * _dee )
|
||||
{
|
||||
StringPairDrag::processDragEnterEvent( _dee, "float_value,"
|
||||
"automatable_model" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Knob::dropEvent( QDropEvent * _de )
|
||||
{
|
||||
QString type = StringPairDrag::decodeKey( _de );
|
||||
QString val = StringPairDrag::decodeValue( _de );
|
||||
if( type == "float_value" )
|
||||
{
|
||||
model()->setValue( LocaleHelper::toFloat(val) );
|
||||
_de->accept();
|
||||
}
|
||||
else if( type == "automatable_model" )
|
||||
{
|
||||
auto mod = dynamic_cast<AutomatableModel*>(Engine::projectJournal()->journallingObject(val.toInt()));
|
||||
if( mod != nullptr )
|
||||
{
|
||||
AutomatableModel::linkModels( model(), mod );
|
||||
mod->setValue( model()->value() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Knob::mousePressEvent( QMouseEvent * _me )
|
||||
{
|
||||
if( _me->button() == Qt::LeftButton &&
|
||||
! ( _me->modifiers() & Qt::ControlModifier ) &&
|
||||
! ( _me->modifiers() & Qt::ShiftModifier ) )
|
||||
{
|
||||
AutomatableModel *thisModel = model();
|
||||
if( thisModel )
|
||||
{
|
||||
thisModel->addJournalCheckPoint();
|
||||
thisModel->saveJournallingState( false );
|
||||
}
|
||||
|
||||
const QPoint & p = _me->pos();
|
||||
m_lastMousePos = p;
|
||||
m_leftOver = 0.0f;
|
||||
|
||||
emit sliderPressed();
|
||||
|
||||
showTextFloat(0, 0);
|
||||
|
||||
m_buttonPressed = true;
|
||||
}
|
||||
else if( _me->button() == Qt::LeftButton &&
|
||||
(_me->modifiers() & Qt::ShiftModifier) )
|
||||
{
|
||||
new StringPairDrag( "float_value",
|
||||
QString::number( model()->value() ),
|
||||
QPixmap(), this );
|
||||
}
|
||||
else
|
||||
{
|
||||
FloatModelView::mousePressEvent( _me );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Knob::mouseMoveEvent( QMouseEvent * _me )
|
||||
{
|
||||
if( m_buttonPressed && _me->pos() != m_lastMousePos )
|
||||
{
|
||||
// knob position is changed depending on last mouse position
|
||||
setPosition( _me->pos() - m_lastMousePos );
|
||||
emit sliderMoved( model()->value() );
|
||||
// original position for next time is current position
|
||||
m_lastMousePos = _me->pos();
|
||||
}
|
||||
s_textFloat->setText( displayValue() );
|
||||
s_textFloat->show();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Knob::mouseReleaseEvent( QMouseEvent* event )
|
||||
{
|
||||
if( event && event->button() == Qt::LeftButton )
|
||||
{
|
||||
AutomatableModel *thisModel = model();
|
||||
if( thisModel )
|
||||
{
|
||||
thisModel->restoreJournallingState();
|
||||
}
|
||||
}
|
||||
|
||||
m_buttonPressed = false;
|
||||
|
||||
emit sliderReleased();
|
||||
|
||||
QApplication::restoreOverrideCursor();
|
||||
|
||||
s_textFloat->hide();
|
||||
}
|
||||
|
||||
void Knob::enterEvent(QEvent *event)
|
||||
{
|
||||
showTextFloat(700, 2000);
|
||||
}
|
||||
|
||||
void Knob::leaveEvent(QEvent *event)
|
||||
{
|
||||
s_textFloat->hide();
|
||||
}
|
||||
|
||||
|
||||
void Knob::focusOutEvent( QFocusEvent * _fe )
|
||||
{
|
||||
// make sure we don't loose mouse release event
|
||||
mouseReleaseEvent( nullptr );
|
||||
QWidget::focusOutEvent( _fe );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Knob::mouseDoubleClickEvent( QMouseEvent * )
|
||||
{
|
||||
enterValue();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Knob::paintEvent( QPaintEvent * _me )
|
||||
{
|
||||
QPainter p( this );
|
||||
@@ -697,201 +487,6 @@ void Knob::paintEvent( QPaintEvent * _me )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Knob::wheelEvent(QWheelEvent * we)
|
||||
{
|
||||
we->accept();
|
||||
const int deltaY = we->angleDelta().y();
|
||||
float direction = deltaY > 0 ? 1 : -1;
|
||||
|
||||
auto * m = model();
|
||||
float const step = m->step<float>();
|
||||
float const range = m->range();
|
||||
|
||||
// This is the default number of steps or mouse wheel events that it takes to sweep
|
||||
// from the lowest value to the highest value.
|
||||
// It might be modified if the user presses modifier keys. See below.
|
||||
float numberOfStepsForFullSweep = 100.;
|
||||
|
||||
auto const modKeys = we->modifiers();
|
||||
if (modKeys == Qt::ShiftModifier)
|
||||
{
|
||||
// The shift is intended to go through the values in very coarse steps as in:
|
||||
// "Shift into overdrive"
|
||||
numberOfStepsForFullSweep = 10;
|
||||
}
|
||||
else if (modKeys == Qt::ControlModifier)
|
||||
{
|
||||
// The control key gives more control, i.e. it enables more fine-grained adjustments
|
||||
numberOfStepsForFullSweep = 1000;
|
||||
}
|
||||
else if (modKeys == Qt::AltModifier)
|
||||
{
|
||||
// The alt key enables even finer adjustments
|
||||
numberOfStepsForFullSweep = 2000;
|
||||
|
||||
// It seems that on some systems pressing Alt with mess with the directions,
|
||||
// i.e. scrolling the mouse wheel is interpreted as pressing the mouse wheel
|
||||
// left and right. Account for this quirk.
|
||||
if (deltaY == 0)
|
||||
{
|
||||
int const deltaX = we->angleDelta().x();
|
||||
if (deltaX != 0)
|
||||
{
|
||||
direction = deltaX > 0 ? 1 : -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the number of steps but make sure that we always do at least one step
|
||||
const float stepMult = std::max(range / numberOfStepsForFullSweep / step, 1.f);
|
||||
const int inc = direction * stepMult;
|
||||
model()->incValue(inc);
|
||||
|
||||
s_textFloat->setText( displayValue() );
|
||||
s_textFloat->moveGlobal( this, QPoint( width() + 2, 0 ) );
|
||||
s_textFloat->setVisibilityTimeOut( 1000 );
|
||||
|
||||
emit sliderMoved( model()->value() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Knob::setPosition( const QPoint & _p )
|
||||
{
|
||||
const float value = getValue( _p ) + m_leftOver;
|
||||
const auto step = model()->step<float>();
|
||||
const float oldValue = model()->value();
|
||||
|
||||
|
||||
|
||||
if( model()->isScaleLogarithmic() ) // logarithmic code
|
||||
{
|
||||
const float pos = model()->minValue() < 0
|
||||
? oldValue / qMax( qAbs( model()->maxValue() ), qAbs( model()->minValue() ) )
|
||||
: ( oldValue - model()->minValue() ) / model()->range();
|
||||
const float ratio = 0.1f + qAbs( pos ) * 15.f;
|
||||
float newValue = value * ratio;
|
||||
if( qAbs( newValue ) >= step )
|
||||
{
|
||||
float roundedValue = qRound( ( oldValue - value ) / step ) * step;
|
||||
model()->setValue( roundedValue );
|
||||
m_leftOver = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_leftOver = value;
|
||||
}
|
||||
}
|
||||
|
||||
else // linear code
|
||||
{
|
||||
if( qAbs( value ) >= step )
|
||||
{
|
||||
float roundedValue = qRound( ( oldValue - value ) / step ) * step;
|
||||
model()->setValue( roundedValue );
|
||||
m_leftOver = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_leftOver = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Knob::enterValue()
|
||||
{
|
||||
bool ok;
|
||||
float new_val;
|
||||
|
||||
if( isVolumeKnob() &&
|
||||
ConfigManager::inst()->value( "app", "displaydbfs" ).toInt() )
|
||||
{
|
||||
new_val = QInputDialog::getDouble(
|
||||
this, tr( "Set value" ),
|
||||
tr( "Please enter a new value between "
|
||||
"-96.0 dBFS and 6.0 dBFS:" ),
|
||||
ampToDbfs( model()->getRoundedValue() / 100.0 ),
|
||||
-96.0, 6.0, model()->getDigitCount(), &ok );
|
||||
if( new_val <= -96.0 )
|
||||
{
|
||||
new_val = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_val = dbfsToAmp( new_val ) * 100.0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new_val = QInputDialog::getDouble(
|
||||
this, tr( "Set value" ),
|
||||
tr( "Please enter a new value between "
|
||||
"%1 and %2:" ).
|
||||
arg( model()->minValue() ).
|
||||
arg( model()->maxValue() ),
|
||||
model()->getRoundedValue(),
|
||||
model()->minValue(),
|
||||
model()->maxValue(), model()->getDigitCount(), &ok );
|
||||
}
|
||||
|
||||
if( ok )
|
||||
{
|
||||
model()->setValue( new_val );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Knob::friendlyUpdate()
|
||||
{
|
||||
if (model() && (model()->controllerConnection() == nullptr ||
|
||||
model()->controllerConnection()->getController()->frequentUpdates() == false ||
|
||||
Controller::runningFrames() % (256*4) == 0))
|
||||
{
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
QString Knob::displayValue() const
|
||||
{
|
||||
if( isVolumeKnob() &&
|
||||
ConfigManager::inst()->value( "app", "displaydbfs" ).toInt() )
|
||||
{
|
||||
return m_description.trimmed() + QString( " %1 dBFS" ).
|
||||
arg( ampToDbfs( model()->getRoundedValue() / volumeRatio() ),
|
||||
3, 'f', 2 );
|
||||
}
|
||||
return m_description.trimmed() + QString( " %1" ).
|
||||
arg( model()->getRoundedValue() ) + m_unit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Knob::doConnections()
|
||||
{
|
||||
if( model() != nullptr )
|
||||
{
|
||||
QObject::connect( model(), SIGNAL(dataChanged()),
|
||||
this, SLOT(friendlyUpdate()));
|
||||
|
||||
QObject::connect( model(), SIGNAL(propertiesChanged()),
|
||||
this, SLOT(update()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Knob::changeEvent(QEvent * ev)
|
||||
{
|
||||
if (ev->type() == QEvent::EnabledChange)
|
||||
|
||||
Reference in New Issue
Block a user