Initial version of FloatModelEditorBase

Create an initial version of `FloatModelEditorBase`. It is intended to
become the base widget for all widgets that manipulate a float model and
provides some base functionalities like context menus, edit dialogs,
mouse handling, etc.

The initial version is a copy of `Knob`. The enum and its values have
been suffixed with "Temp" as they will be removed later anyway. Same
applies for the function `convertPixmapToGrayScaleTemp`.
This commit is contained in:
Michael Gregorius
2023-07-08 13:50:15 +02:00
parent 816f3f5870
commit 15246b2758
4 changed files with 1102 additions and 1 deletions

View File

@@ -0,0 +1,217 @@
/*
* FloatModelEditorBase.h - Base editor for float models
*
* Copyright (c) 2004-2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2023 Michael Gregorius
*
* This file is part of LMMS - https://lmms.io
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef LMMS_GUI_FLOAT_MODEL_EDITOR_BASE_H
#define LMMS_GUI_FLOAT_MODEL_EDITOR_BASE_H
#include <memory>
#include <QPixmap>
#include <QWidget>
#include <QPoint>
#include <QTextDocument>
#include "AutomatableModelView.h"
class QPixmap;
namespace lmms::gui
{
class SimpleTextFloat;
enum knobTypesTemp
{
knobDark_28Temp, knobBright_26Temp, knobSmall_17Temp, knobVintage_32Temp, knobStyledTemp
} ;
void convertPixmapToGrayScaleTemp(QPixmap &pixMap);
class LMMS_EXPORT FloatModelEditorBase : public QWidget, public FloatModelView
{
Q_OBJECT
Q_ENUMS( knobTypesTemp )
Q_PROPERTY(float innerRadius READ innerRadius WRITE setInnerRadius)
Q_PROPERTY(float outerRadius READ outerRadius WRITE setOuterRadius)
Q_PROPERTY(float centerPointX READ centerPointX WRITE setCenterPointX)
Q_PROPERTY(float centerPointY READ centerPointY WRITE setCenterPointY)
Q_PROPERTY(float lineWidth READ lineWidth WRITE setLineWidth)
// Unfortunately, the gradient syntax doesn't create our gradient
// correctly so we need to do this:
Q_PROPERTY(QColor outerColor READ outerColor WRITE setOuterColor)
Q_PROPERTY(QColor lineActiveColor MEMBER m_lineActiveColor)
Q_PROPERTY(QColor lineInactiveColor MEMBER m_lineInactiveColor)
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(knobTypesTemp knobNum READ knobNum WRITE setknobNum)
Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor)
void initUi( const QString & _name ); //!< to be called by ctors
void onKnobNumUpdated(); //!< to be called when you updated @a m_knobNum
public:
FloatModelEditorBase( knobTypesTemp _knob_num, QWidget * _parent = nullptr, const QString & _name = QString() );
FloatModelEditorBase( QWidget * _parent = nullptr, const QString & _name = QString() ); //!< default ctor
FloatModelEditorBase( const FloatModelEditorBase& 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 );
void setTotalAngle( float angle );
// Begin styled knob accessors
float innerRadius() const;
void setInnerRadius( float r );
float outerRadius() const;
void setOuterRadius( float r );
knobTypesTemp knobNum() const;
void setknobNum( knobTypesTemp k );
QPointF centerPoint() const;
float centerPointX() const;
void setCenterPointX( float c );
float centerPointY() const;
void setCenterPointY( float c );
float lineWidth() const;
void setLineWidth( float w );
QColor outerColor() const;
void setOuterColor( const QColor & c );
QColor textColor() const;
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;
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 setPosition( const QPoint & _p );
bool updateAngle();
int angleFromValue( float value, float minValue, float maxValue, float totalAngle ) const
{
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;
QImage m_cache;
// Styled knob stuff, could break out
QPointF m_centerPoint;
float m_innerRadius;
float m_outerRadius;
float m_lineWidth;
QColor m_outerColor;
QColor m_lineActiveColor;
QColor m_lineInactiveColor;
QColor m_arcActiveColor;
QColor m_arcInactiveColor;
QColor m_textColor;
knobTypesTemp m_knobNum;
} ;
} // namespace lmms::gui
#endif // LMMS_GUI_FLOAT_MODEL_EDITOR_BASE_H

View File

@@ -101,6 +101,7 @@ SET(LMMS_SRCS
gui/widgets/ComboBox.cpp
gui/widgets/CustomTextKnob.cpp
gui/widgets/Fader.cpp
gui/widgets/FloatModelEditorBase.cpp
gui/widgets/Graph.cpp
gui/widgets/GroupBox.cpp
gui/widgets/Knob.cpp

View File

@@ -31,6 +31,8 @@
#include "LadspaBase.h"
#include "BarModelEditor.h"
// TODO Only for testing! Remove!
#include "FloatModelEditorBase.h"
#include "LedCheckBox.h"
#include "TempoSyncKnob.h"
@@ -65,7 +67,15 @@ QWidget * LadspaWidgetFactory::createWidget(LadspaControl * ladspaControl, QWidg
knob->setModel(ladspaControl->knobModel());
knob->setLabel(name);
break;*/
return new BarModelEditor(name, ladspaControl->knobModel(), parent);
{
FloatModelEditorBase * fme = new FloatModelEditorBase(knobBright_26Temp, parent, name);
fme->setModel(ladspaControl->knobModel());
fme->setLabel(name);
fme->setHintText(QObject::tr("Value:"), "");
return fme;
}
// FloatModelEditorBase
//return new BarModelEditor(name, ladspaControl->knobModel(), parent);
case TIME:
knob = new TempoSyncKnob(knobBright_26, parent, name);

View File

@@ -0,0 +1,873 @@
/*
* FloatModelEditorBase.cpp - Base editor for float models
*
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2023 Michael Gregorius
*
* This file is part of LMMS - https://lmms.io
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include "FloatModelEditorBase.h"
#include <memory>
#include <QApplication>
#include <QFontMetrics>
#include <QInputDialog>
#include <QMouseEvent>
#include <QPainter>
#ifndef __USE_XOPEN
#define __USE_XOPEN
#endif
#include "lmms_math.h"
#include "CaptionMenu.h"
#include "ConfigManager.h"
#include "ControllerConnection.h"
#include "DeprecationHelper.h"
#include "embed.h"
#include "gui_templates.h"
#include "GuiApplication.h"
#include "LocaleHelper.h"
#include "MainWindow.h"
#include "ProjectJournal.h"
#include "SimpleTextFloat.h"
#include "StringPairDrag.h"
namespace lmms::gui
{
SimpleTextFloat * FloatModelEditorBase::s_textFloat = nullptr;
FloatModelEditorBase::FloatModelEditorBase( knobTypesTemp _knob_num, QWidget * _parent, const QString & _name ) :
QWidget( _parent ),
FloatModelView( new FloatModel( 0, 0, 0, 1, nullptr, _name, true ), this ),
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 ),
m_knobNum( _knob_num )
{
initUi( _name );
}
FloatModelEditorBase::FloatModelEditorBase( QWidget * _parent, const QString & _name ) :
FloatModelEditorBase( knobBright_26Temp, _parent, _name )
{
}
void FloatModelEditorBase::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.
//
// It works as follows: the palette colors that are assigned as the line color previously
// had been hard coded in the drawKnob method for the different knob types. Now the
// drawKnob method uses the line color to draw the lines. By assigning the palette colors
// as the line colors here the knob lines will be drawn in this color unless the stylesheet
// overrides that color.
switch (knobNum())
{
case knobSmall_17Temp:
case knobBright_26Temp:
case knobDark_28Temp:
m_lineActiveColor = QApplication::palette().color(QPalette::Active, QPalette::WindowText);
m_arcActiveColor = QColor(QApplication::palette().color(
QPalette::Active, QPalette::WindowText));
m_arcActiveColor.setAlpha(70);
break;
case knobVintage_32Temp:
m_lineActiveColor = QApplication::palette().color(QPalette::Active, QPalette::Shadow);
m_arcActiveColor = QColor(QApplication::palette().color(
QPalette::Active, QPalette::Shadow));
m_arcActiveColor.setAlpha(70);
break;
default:
break;
}
doConnections();
}
void FloatModelEditorBase::onKnobNumUpdated()
{
if( m_knobNum != knobStyledTemp )
{
QString knobFilename;
switch (m_knobNum)
{
case knobDark_28Temp:
knobFilename = "knob01";
break;
case knobBright_26Temp:
knobFilename = "knob02";
break;
case knobSmall_17Temp:
knobFilename = "knob03";
break;
case knobVintage_32Temp:
knobFilename = "knob05";
break;
case knobStyledTemp: // only here to stop the compiler from complaining
break;
}
// If knobFilename is still empty here we should get the fallback pixmap of size 1x1
m_knobPixmap = std::make_unique<QPixmap>(QPixmap(embed::getIconPixmap(knobFilename.toUtf8().constData())));
if (!this->isEnabled())
{
convertPixmapToGrayScaleTemp(*m_knobPixmap.get());
}
setFixedSize( m_knobPixmap->width(), m_knobPixmap->height() );
}
}
void FloatModelEditorBase::setLabel( const QString & txt )
{
m_label = txt;
m_isHtmlLabel = false;
if( m_knobPixmap )
{
setFixedSize(qMax<int>( m_knobPixmap->width(),
horizontalAdvance(QFontMetrics(pointSizeF(font(), 6.5)), m_label)),
m_knobPixmap->height() + 10);
}
update();
}
void FloatModelEditorBase::setHtmlLabel(const QString &htmltxt)
{
m_label = htmltxt;
m_isHtmlLabel = true;
// Put the rendered HTML content into cache
if (!m_tdRenderer)
{
m_tdRenderer = new QTextDocument(this);
}
m_tdRenderer->setHtml(QString("<span style=\"color:%1;\">%2</span>").arg(textColor().name(), m_label));
if (m_knobPixmap)
{
setFixedSize(m_knobPixmap->width(),
m_knobPixmap->height() + 15);
}
update();
}
void FloatModelEditorBase::setTotalAngle( float angle )
{
if( angle < 10.0 )
{
m_totalAngle = 10.0;
}
else
{
m_totalAngle = angle;
}
update();
}
float FloatModelEditorBase::innerRadius() const
{
return m_innerRadius;
}
void FloatModelEditorBase::setInnerRadius( float r )
{
m_innerRadius = r;
}
float FloatModelEditorBase::outerRadius() const
{
return m_outerRadius;
}
void FloatModelEditorBase::setOuterRadius( float r )
{
m_outerRadius = r;
}
knobTypesTemp FloatModelEditorBase::knobNum() const
{
return m_knobNum;
}
void FloatModelEditorBase::setknobNum( knobTypesTemp k )
{
if( m_knobNum != k )
{
m_knobNum = k;
onKnobNumUpdated();
}
}
QPointF FloatModelEditorBase::centerPoint() const
{
return m_centerPoint;
}
float FloatModelEditorBase::centerPointX() const
{
return m_centerPoint.x();
}
void FloatModelEditorBase::setCenterPointX( float c )
{
m_centerPoint.setX( c );
}
float FloatModelEditorBase::centerPointY() const
{
return m_centerPoint.y();
}
void FloatModelEditorBase::setCenterPointY( float c )
{
m_centerPoint.setY( c );
}
float FloatModelEditorBase::lineWidth() const
{
return m_lineWidth;
}
void FloatModelEditorBase::setLineWidth( float w )
{
m_lineWidth = w;
}
QColor FloatModelEditorBase::outerColor() const
{
return m_outerColor;
}
void FloatModelEditorBase::setOuterColor( const QColor & c )
{
m_outerColor = c;
}
QColor FloatModelEditorBase::textColor() const
{
return m_textColor;
}
void FloatModelEditorBase::setTextColor( const QColor & c )
{
m_textColor = c;
}
QLineF FloatModelEditorBase::calculateLine( const QPointF & _mid, float _radius, float _innerRadius ) const
{
const float rarc = m_angle * F_PI / 180.0;
const float ca = cos( rarc );
const float sa = -sin( rarc );
return QLineF( _mid.x() - sa*_innerRadius, _mid.y() - ca*_innerRadius,
_mid.x() - sa*_radius, _mid.y() - ca*_radius );
}
bool FloatModelEditorBase::updateAngle()
{
int angle = 0;
if( model() && model()->maxValue() != model()->minValue() )
{
angle = angleFromValue( model()->inverseScaledValue( model()->value() ), model()->minValue(), model()->maxValue(), m_totalAngle );
}
if( qAbs( angle - m_angle ) > 0 )
{
m_angle = angle;
return true;
}
return false;
}
void FloatModelEditorBase::drawKnob( QPainter * _p )
{
bool enabled = this->isEnabled();
QColor currentArcColor = enabled ? m_arcActiveColor : m_arcInactiveColor;
QColor currentLineColor = enabled ? m_lineActiveColor : m_lineInactiveColor;
if( updateAngle() == false && !m_cache.isNull() )
{
_p->drawImage( 0, 0, m_cache );
return;
}
m_cache = QImage( size(), QImage::Format_ARGB32 );
m_cache.fill( qRgba( 0, 0, 0, 0 ) );
QPainter p( &m_cache );
QPoint mid;
if( m_knobNum == knobStyledTemp )
{
p.setRenderHint( QPainter::Antialiasing );
// Perhaps this can move to setOuterRadius()
if( m_outerColor.isValid() )
{
QRadialGradient gradient( centerPoint(), outerRadius() );
gradient.setColorAt( 0.4, _p->pen().brush().color() );
gradient.setColorAt( 1, m_outerColor );
p.setPen( QPen( gradient, lineWidth(),
Qt::SolidLine, Qt::RoundCap ) );
}
else {
QPen pen = p.pen();
pen.setWidth( (int) lineWidth() );
pen.setCapStyle( Qt::RoundCap );
p.setPen( pen );
}
p.drawLine( calculateLine( centerPoint(), outerRadius(),
innerRadius() ) );
p.end();
_p->drawImage( 0, 0, m_cache );
return;
}
// Old-skool knobs
const float radius = m_knobPixmap->width() / 2.0f - 1;
mid = QPoint( width() / 2, m_knobPixmap->height() / 2 );
p.drawPixmap( static_cast<int>(
width() / 2 - m_knobPixmap->width() / 2 ), 0,
*m_knobPixmap );
p.setRenderHint( QPainter::Antialiasing );
const int centerAngle = angleFromValue( model()->inverseScaledValue( model()->centerValue() ), model()->minValue(), model()->maxValue(), m_totalAngle );
const int arcLineWidth = 2;
const int arcRectSize = m_knobPixmap->width() - arcLineWidth;
p.setPen(QPen(currentArcColor, 2));
p.drawArc( mid.x() - arcRectSize/2, 1, arcRectSize, arcRectSize, 315*16, 16*m_totalAngle );
p.setPen(QPen(currentLineColor, 2));
switch( m_knobNum )
{
case knobSmall_17Temp:
{
p.drawLine( calculateLine( mid, radius-2 ) );
break;
}
case knobBright_26Temp:
{
p.drawLine( calculateLine( mid, radius-5 ) );
break;
}
case knobDark_28Temp:
{
const float rb = qMax<float>( ( radius - 10 ) / 3.0,
0.0 );
const float re = qMax<float>( ( radius - 4 ), 0.0 );
QLineF ln = calculateLine( mid, re, rb );
ln.translate( 1, 1 );
p.drawLine( ln );
break;
}
case knobVintage_32Temp:
{
p.drawLine( calculateLine( mid, radius-2, 2 ) );
break;
}
case knobStyledTemp:
break;
}
p.drawArc( mid.x() - arcRectSize/2, 1, arcRectSize, arcRectSize, (90-centerAngle)*16, -16*(m_angle-centerAngle) );
p.end();
_p->drawImage( 0, 0, m_cache );
}
float FloatModelEditorBase::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 FloatModelEditorBase::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 FloatModelEditorBase::toggleScale()
{
model()->setScaleLogarithmic( ! model()->isScaleLogarithmic() );
update();
}
void FloatModelEditorBase::dragEnterEvent( QDragEnterEvent * _dee )
{
StringPairDrag::processDragEnterEvent( _dee, "float_value,"
"automatable_model" );
}
void FloatModelEditorBase::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 FloatModelEditorBase::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();
s_textFloat->setText( displayValue() );
s_textFloat->moveGlobal( this,
QPoint( width() + 2, 0 ) );
s_textFloat->show();
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 FloatModelEditorBase::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() );
}
void FloatModelEditorBase::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 FloatModelEditorBase::focusOutEvent( QFocusEvent * _fe )
{
// make sure we don't loose mouse release event
mouseReleaseEvent( nullptr );
QWidget::focusOutEvent( _fe );
}
void FloatModelEditorBase::mouseDoubleClickEvent( QMouseEvent * )
{
enterValue();
}
void FloatModelEditorBase::paintEvent( QPaintEvent * _me )
{
QPainter p( this );
drawKnob( &p );
if( !m_label.isEmpty() )
{
if (!m_isHtmlLabel)
{
p.setFont(pointSizeF(p.font(), 6.5));
p.setPen(textColor());
p.drawText(width() / 2 -
horizontalAdvance(p.fontMetrics(), m_label) / 2,
height() - 2, m_label);
}
else
{
m_tdRenderer->setDefaultFont(pointSizeF(p.font(), 6.5));
p.translate((width() - m_tdRenderer->idealWidth()) / 2, (height() - m_tdRenderer->pageSize().height()) / 2);
m_tdRenderer->drawContents(&p);
}
}
}
void FloatModelEditorBase::wheelEvent(QWheelEvent * we)
{
we->accept();
const float stepMult = model()->range() / 2000 / model()->step<float>();
const int inc = ((we->angleDelta().y() > 0 ) ? 1 : -1) * ((stepMult < 1 ) ? 1 : 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 FloatModelEditorBase::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 FloatModelEditorBase::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 FloatModelEditorBase::friendlyUpdate()
{
if (model() && (model()->controllerConnection() == nullptr ||
model()->controllerConnection()->getController()->frequentUpdates() == false ||
Controller::runningFrames() % (256*4) == 0))
{
update();
}
}
QString FloatModelEditorBase::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 FloatModelEditorBase::doConnections()
{
if( model() != nullptr )
{
QObject::connect( model(), SIGNAL(dataChanged()),
this, SLOT(friendlyUpdate()));
QObject::connect( model(), SIGNAL(propertiesChanged()),
this, SLOT(update()));
}
}
void FloatModelEditorBase::changeEvent(QEvent * ev)
{
if (ev->type() == QEvent::EnabledChange)
{
onKnobNumUpdated();
if (!m_label.isEmpty())
{
setLabel(m_label);
}
m_cache = QImage();
update();
}
}
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