From cdfeabc98bffcd8ce70d90ad3cf173130fcd6c8c Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sat, 23 Sep 2023 11:48:18 +0200 Subject: [PATCH] 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`. --- include/FloatModelEditorBase.h | 5 - include/Knob.h | 64 +--- src/gui/widgets/FloatModelEditorBase.cpp | 17 - src/gui/widgets/Knob.cpp | 407 +---------------------- 4 files changed, 5 insertions(+), 488 deletions(-) diff --git a/include/FloatModelEditorBase.h b/include/FloatModelEditorBase.h index 99078bbcc..ff74b0371 100644 --- a/include/FloatModelEditorBase.h +++ b/include/FloatModelEditorBase.h @@ -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 diff --git a/include/Knob.h b/include/Knob.h index d5739bb1c..580948e25 100644 --- a/include/Knob.h +++ b/include/Knob.h @@ -31,7 +31,7 @@ #include #include -#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( ( 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 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 diff --git a/src/gui/widgets/FloatModelEditorBase.cpp b/src/gui/widgets/FloatModelEditorBase.cpp index 5b58d2b9b..bda363698 100644 --- a/src/gui/widgets/FloatModelEditorBase.cpp +++ b/src/gui/widgets/FloatModelEditorBase.cpp @@ -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 diff --git a/src/gui/widgets/Knob.cpp b/src/gui/widgets/Knob.cpp index 56cf29345..b470a5ff8 100644 --- a/src/gui/widgets/Knob.cpp +++ b/src/gui/widgets/Knob.cpp @@ -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(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 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(); - 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)