hydrogen 1.2.6
Fader.cpp
Go to the documentation of this file.
1/*
2 * Hydrogen
3 * Copyright(c) 2002-2008 by Alex >Comix< Cominu [comix@users.sourceforge.net]
4 * Copyright(c) 2008-2025 The hydrogen development team [hydrogen-devel@lists.sourceforge.net]
5 *
6 * http://www.hydrogen-music.org
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY, without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see https://www.gnu.org/licenses
20 *
21 */
22
23#include "Fader.h"
24
26#include "../Skin.h"
27#include "../HydrogenApp.h"
28#include "../MainForm.h"
29#include "MidiSenseWidget.h"
30
31#include <QtGui>
32#include <QtWidgets>
33
34#include <core/Globals.h>
35#include <core/Hydrogen.h>
37
38Fader::Fader( QWidget *pParent, Type type, QString sBaseTooltip, bool bUseIntSteps, bool bWithoutKnob, float fMin, float fMax, bool bModifyOnChange )
39 : WidgetWithInput( pParent,
40 bUseIntSteps,
41 sBaseTooltip,
42 1, // nScrollSpeed
43 5, // nScrollSpeedFast
44 fMin,
45 fMax,
46 bModifyOnChange )
47 , m_type( type )
48 , m_bWithoutKnob( bWithoutKnob )
49 , m_fPeakValue_L( 0.01f )
50 , m_fPeakValue_R( 0.01f )
51 , m_fMinPeak( 0.01f )
52 , m_fMaxPeak( 1.0 )
53{
57
58 installEventFilter( HydrogenApp::get_instance()->getMainForm() );
59
60 if ( type == Type::Vertical ){
61 m_nWidgetWidth = 116;
62 m_nWidgetHeight = 23;
63 } else if ( type == Type::Master ) {
64 m_nWidgetWidth = 34;
65 m_nWidgetHeight = 189;
66 } else {
67 m_nWidgetWidth = 23;
68 m_nWidgetHeight = 117;
69 }
70 setFixedSize( m_nWidgetWidth, m_nWidgetHeight );
71
72 // Background image
73 QString sBackgroundPath;
74 QString sKnobPath;
75 if ( type == Type::Master ) {
76 sBackgroundPath = Skin::getSvgImagePath() + "/fader_master.svg";
77 sKnobPath = Skin::getSvgImagePath() + "/fader_knob.svg";
78 } else if ( type == Type::Vertical ) {
79 sBackgroundPath = Skin::getSvgImagePath() + "/fader_vertical.svg";
80 sKnobPath = Skin::getSvgImagePath() + "/fader_knob_vertical.svg";
81 } else {
82 sBackgroundPath = Skin::getSvgImagePath() + "/fader.svg";
83 sKnobPath = Skin::getSvgImagePath() + "/fader_knob.svg";
84 }
85
86 QFile fileBackground( sBackgroundPath );
87 if ( fileBackground.exists() ) {
88 m_pBackground = new QSvgRenderer( sBackgroundPath, this );
89 } else {
90 m_pBackground = nullptr;
91 ERRORLOG( QString( "Unable to load background image [%1]" ).arg( sBackgroundPath ) );
92 }
93
94 QFile fileKnob( sKnobPath );
95 if ( fileKnob.exists() ) {
96 m_pKnob = new QSvgRenderer( sKnobPath, this );
97 } else {
98 m_pKnob = nullptr;
99 ERRORLOG( QString( "Unable to load knob image [%1]" ).arg( sKnobPath ) );
100 }
101
103
105
106 if ( type == Type::Vertical ) {
107 QTransform transform;
108 transform.rotate(90);
109 }
110}
111
114
116{
117 if ( changes & ( H2Core::Preferences::Changes::Colors ) ) {
118 update();
119 }
120}
121
122void Fader::mouseMoveEvent( QMouseEvent *ev )
123{
124 if ( m_bIgnoreMouseMove || ! m_bIsActive ) {
125 return;
126 }
127
128 auto pEv = static_cast<MouseEvent*>( ev );
129
130 float fValue;
131 if ( m_type == Type::Vertical ) {
132 fValue = static_cast<float>( pEv->position().x() ) / static_cast<float>( width() );
133 } else {
134 fValue = static_cast<float>( height() - pEv->position().y() ) /
135 static_cast<float>( height() );
136 }
137 if ( fValue > 1. ) { // for QToolTip text validity
138 fValue = 1.;
139 } else if ( fValue < 0. ) {
140 fValue = 0.;
141 }
142
143 fValue = fValue * ( m_fMax - m_fMin ) + m_fMin;
144
145 setValue( fValue, true );
146 QToolTip::showText( pEv->globalPosition().toPoint(),
147 QString( "%1" ).arg( m_fValue, 0, 'f', 2 ) , this );
148}
149
150
151void Fader::mousePressEvent(QMouseEvent *ev)
152{
153 if ( ! m_bIsActive ) {
154 return;
155 }
156
157 auto pEv = static_cast<MouseEvent*>( ev );
158
159 if ( ev->button() == Qt::LeftButton && ev->modifiers() == Qt::ControlModifier ) {
161 m_bIgnoreMouseMove = true;
162 }
163 else if ( ev->button() == Qt::LeftButton && ev->modifiers() == Qt::ShiftModifier ) {
164 MidiSenseWidget midiSense( this, true, this->getAction() );
165 midiSense.exec();
166 m_bIgnoreMouseMove = true;
167 }
168 else {
169 setCursor( QCursor( Qt::SizeVerCursor ) );
170
172 m_fMousePressY = pEv->position().y();
173 mouseMoveEvent( ev );
174 }
175
176 QToolTip::showText( pEv->globalPosition().toPoint(),
177 QString( "%1" ).arg( m_fValue, 0, 'f', 2 ) , this );
178}
179
180void Fader::paintEvent( QPaintEvent *ev)
181{
182
184
185 QPainter painter(this);
186
187 QColor colorHighlightActive;
188 if ( m_bIsActive ) {
189 colorHighlightActive = pPref->getColorTheme()->m_highlightColor;
190 } else {
191 colorHighlightActive = pPref->getColorTheme()->m_lightColor;
192 }
193 QColor colorGradientNormal( Qt::green );
194 QColor colorGradientWarning( Qt::yellow );
195 QColor colorGradientDanger( Qt::red );
196
197 // If the mouse is placed on the widget but the user hasn't
198 // clicked it yet, the highlight will be done more transparent to
199 // indicate that keyboard inputs are not accepted yet.
200 if ( ! hasFocus() ) {
201 colorHighlightActive.setAlpha( 150 );
202 }
203
204 if ( m_bEntered || hasFocus() ) {
205 if ( m_type == Type::Master ) {
206 painter.fillRect( 0, 0, 19, 2, colorHighlightActive );
207 painter.fillRect( m_nWidgetWidth / 2 - 10, 2, 3, m_nWidgetHeight - 2, colorHighlightActive );
208 painter.fillRect( m_nWidgetWidth / 2 + 8, 2, 2, m_nWidgetHeight - 4, colorHighlightActive );
209 painter.fillRect( m_nWidgetWidth / 2 + 13, 2, 2, m_nWidgetHeight - 4, colorHighlightActive );
210 painter.fillRect( 0, m_nWidgetHeight - 2, 19, 2, colorHighlightActive );
211 painter.fillRect( m_nWidgetWidth / 2 + 7, 0, 9, 2, colorHighlightActive );
212 painter.fillRect( m_nWidgetWidth / 2 + 7, m_nWidgetHeight - 2, 9, 2, colorHighlightActive );
213 } else if ( m_type == Type::Vertical ) {
214 painter.fillRect( 0, 0, 2, m_nWidgetHeight, colorHighlightActive );
215 painter.fillRect( 2, m_nWidgetHeight / 2 - 3, m_nWidgetWidth - 4, 7, colorHighlightActive );
216 painter.fillRect( m_nWidgetWidth - 2, 0, 2, m_nWidgetHeight, colorHighlightActive );
217 } else {
218 painter.fillRect( 0, 0, m_nWidgetWidth, 2, colorHighlightActive );
219 painter.fillRect( m_nWidgetWidth / 2 - 4, 2, 9, m_nWidgetHeight - 4, colorHighlightActive );
220 painter.fillRect( 0, m_nWidgetHeight - 2, m_nWidgetWidth, 2, colorHighlightActive );
221 }
222 }
223
224 if ( m_bIsActive ) {
225 float fFaderTopLeftX_L, fFaderTopLeftY_L, fFaderTopLeftX_R,
226 fFaderTopLeftY_R, fFaderWidth, fFaderHeight, fPeak_L, fPeak_R;
227
228 if ( m_type == Type::Master ) {
229 fFaderTopLeftX_L = 1;
230 fFaderTopLeftY_L = 2;
231 fFaderTopLeftX_R = 12;
232 fFaderTopLeftY_R = 2;
233 fFaderWidth = 6.8;
234 fFaderHeight = 186;
235 fPeak_L = ( m_fPeakValue_L - m_fMinPeak ) / ( m_fMaxPeak - m_fMinPeak ) * fFaderHeight;
236 fPeak_R = ( m_fPeakValue_R - m_fMinPeak ) / ( m_fMaxPeak - m_fMinPeak ) * fFaderHeight;
237 } else if ( m_type == Type::Vertical ) {
238 fFaderTopLeftX_L = 1.5;
239 fFaderTopLeftY_L = 2;
240 fFaderTopLeftX_R = 1.5;
241 fFaderTopLeftY_R = 14.5;
242 fFaderWidth = 114;
243 fFaderHeight = 6.5;
244 fPeak_L = ( m_fPeakValue_L - m_fMinPeak ) / ( m_fMaxPeak - m_fMinPeak ) * fFaderWidth;
245 fPeak_R = ( m_fPeakValue_R - m_fMinPeak ) / ( m_fMaxPeak - m_fMinPeak ) * fFaderWidth;
246 } else {
247 fFaderTopLeftX_L = 1.5;
248 fFaderTopLeftY_L = 1.7;
249 fFaderTopLeftX_R = 15.5;
250 fFaderTopLeftY_R = 1.7;
251 fFaderWidth = 6.5;
252 fFaderHeight = 114;
253 fPeak_L = ( m_fPeakValue_L - m_fMinPeak ) / ( m_fMaxPeak - m_fMinPeak ) * fFaderHeight;
254 fPeak_R = ( m_fPeakValue_R - m_fMinPeak ) / ( m_fMaxPeak - m_fMinPeak ) * fFaderHeight;
255 }
256
257 QLinearGradient gradient;
258 if ( m_type == Type::Vertical ) {
259 gradient = QLinearGradient( fFaderTopLeftX_L, fFaderTopLeftY_L, fFaderTopLeftX_L + fFaderWidth, fFaderTopLeftY_L );
260 gradient.setColorAt( 0.0, colorGradientNormal );
261 gradient.setColorAt( 0.6, colorGradientNormal );
262 gradient.setColorAt( 0.65, colorGradientWarning );
263 gradient.setColorAt( 0.85, colorGradientWarning );
264 gradient.setColorAt( 0.9, colorGradientDanger );
265 gradient.setColorAt( 1.0, colorGradientDanger );
266 } else {
267 gradient = QLinearGradient( fFaderTopLeftX_L, fFaderTopLeftY_L, fFaderTopLeftX_L, fFaderTopLeftY_L + fFaderHeight );
268 gradient.setColorAt( 1.0, colorGradientNormal );
269 gradient.setColorAt( 0.4, colorGradientNormal );
270 gradient.setColorAt( 0.35, colorGradientWarning );
271 gradient.setColorAt( 0.15, colorGradientWarning );
272 gradient.setColorAt( 0.1, colorGradientDanger );
273 gradient.setColorAt( 0.0, colorGradientDanger );
274 }
275
276 if ( m_type == Type::Vertical ) {
277 painter.fillRect( QRectF( fFaderTopLeftX_L, fFaderTopLeftY_L, fPeak_L, fFaderHeight ), QBrush( gradient ) );
278 painter.fillRect( QRectF( fFaderTopLeftX_R, fFaderTopLeftY_R, fPeak_R, fFaderHeight ), QBrush( gradient ) );
279 } else {
280 painter.fillRect( QRectF( fFaderTopLeftX_L, fFaderTopLeftY_L + fFaderHeight - fPeak_L, fFaderWidth, fPeak_L ), QBrush( gradient ) );
281 painter.fillRect( QRectF( fFaderTopLeftX_R, fFaderTopLeftY_R + fFaderHeight - fPeak_R, fFaderWidth, fPeak_R ), QBrush( gradient ) );
282 }
283 }
284
285 // Draws the outline of the fader on top of the colors indicating
286 // the peak value.
287 if ( m_pBackground != nullptr ) {
288 m_pBackground->render( &painter );
289 }
290
291 if ( m_bIsActive && m_bWithoutKnob == false ) {
292 float fVal = ( m_fValue - m_fMin ) / ( m_fMax - m_fMin );
293 float fKnobHeight, fKnobWidth, fKnobX, fKnobY;
294
295 if ( m_type == Type::Vertical ) {
296 fKnobHeight = 15;
297 fKnobWidth = 29;
298 fKnobX = 116.0 - ( 101 * ( 1 - fVal ) ) - fKnobHeight;
299 fKnobY = 4;
300 } else {
301 fKnobHeight = 29;
302
303 if ( m_type == Type::Master ) {
304 fKnobWidth = 19;
305 fKnobY = 190.0 - ( 159.0 * fVal ) - fKnobHeight;
306 fKnobX = 21;
307 } else {
308 fKnobWidth = 15;
309 fKnobY = 116.0 - ( 86.0 * fVal ) - fKnobHeight;
310 fKnobX = 4;
311 }
312 }
313
314 if ( m_pKnob != nullptr ) {
315 m_pKnob->render( &painter, QRectF( fKnobX, fKnobY, fKnobWidth, fKnobHeight) );
316 }
317 }
318}
319
320
321void Fader::setPeak_L( float fPeak )
322{
323 if ( m_fPeakValue_L == fPeak ) {
324 return;
325 }
326
327 if ( m_bUseIntSteps && std::fmod( fPeak, 1.0 ) != 0.0 ) {
328 ___WARNINGLOG( QString( "As widget is set to use integer values only the supply value [%1] will be rounded to [%2] " )
329 .arg( fPeak )
330 .arg( std::round( fPeak ) ) );
331 fPeak = std::round( fPeak );
332 }
333 if ( fPeak < m_fMinPeak ) {
334 fPeak = m_fMinPeak;
335 }
336 else if ( fPeak > m_fMaxPeak ) {
337 fPeak = m_fMaxPeak;
338 }
339
340 if ( m_fPeakValue_L != fPeak) {
341 m_fPeakValue_L = fPeak;
342 update();
343 }
344}
345
346void Fader::setPeak_R( float fPeak )
347{
348 if ( m_fPeakValue_R == fPeak ) {
349 return;
350 }
351
352 if ( m_bUseIntSteps && std::fmod( fPeak, 1.0 ) != 0.0 ) {
353 ___WARNINGLOG( QString( "As widget is set to use integer values only the supply value [%1] will be rounded to [%2] " )
354 .arg( fPeak )
355 .arg( std::round( fPeak ) ) );
356 fPeak = std::round( fPeak );
357 }
358 if ( fPeak < m_fMinPeak ) {
359 fPeak = m_fMinPeak;
360 }
361 else if ( fPeak > m_fMaxPeak ) {
362 fPeak = m_fMaxPeak;
363 }
364
365 if ( m_fPeakValue_R != fPeak ) {
366 m_fPeakValue_R = fPeak;
367 update();
368 }
369}
370
371void Fader::setMaxPeak( float fMax )
372{
373 if ( m_fMaxPeak == fMax ) {
374 return;
375 }
376
377 if ( m_bUseIntSteps && std::fmod( fMax, 1.0 ) != 0.0 ) {
378 ___WARNINGLOG( QString( "As widget is set to use integer values only the supply value [%1] will be rounded to [%2] " )
379 .arg( fMax )
380 .arg( std::round( fMax ) ) );
381 fMax = std::round( fMax );
382 }
383
384 if ( fMax <= m_fMinPeak ) {
385 ___ERRORLOG( QString( "Supplied value [%1] must be larger than minimal one [%2]" )
386 .arg( fMax ).arg( m_fMinPeak ) );
387 return;
388 }
389
390 if ( m_fMaxPeak != fMax ) {
391 m_fMaxPeak = fMax;
392
393 if ( m_fPeakValue_L > fMax ) {
394 setPeak_L( fMax );
395
396 }
397 if ( m_fPeakValue_R > fMax ) {
398 setPeak_R( fMax );
399 }
400 }
401}
402
403void Fader::setMinPeak( float fMin )
404{
405 if ( m_fMinPeak == fMin ) {
406 return;
407 }
408
409 if ( m_bUseIntSteps && std::fmod( fMin, 1.0 ) != 0.0 ) {
410 ___WARNINGLOG( QString( "As widget is set to use integer values only the supply value [%1] will be rounded to [%2] " )
411 .arg( fMin )
412 .arg( std::round( fMin ) ) );
413 fMin = std::round( fMin );
414 }
415
416 if ( fMin >= m_fMaxPeak ) {
417 ___ERRORLOG( QString( "Supplied value [%1] must be smaller than maximal one [%2]" )
418 .arg( fMin ).arg( m_fMaxPeak ) );
419 return;
420 }
421
422 if ( m_fMinPeak != fMin ) {
423 m_fMinPeak = fMin;
424
425 if ( m_fPeakValue_L < fMin ) {
426 setPeak_L( fMin );
427 }
428 if ( m_fPeakValue_R < fMin ) {
429 setPeak_R( fMin );
430 }
431 }
432}
#define ___WARNINGLOG(x)
Definition Object.h:259
#define ERRORLOG(x)
Definition Object.h:242
#define ___ERRORLOG(x)
Definition Object.h:260
Type m_type
Definition Fader.h:72
virtual void mouseMoveEvent(QMouseEvent *ev) override
Definition Fader.cpp:122
QSvgRenderer * m_pBackground
Definition Fader.h:73
~Fader()
Definition Fader.cpp:112
Type
Definition Fader.h:48
@ Vertical
Only used for the playback track in the SongEditorPanel.
Definition Fader.h:51
virtual void mousePressEvent(QMouseEvent *ev) override
Definition Fader.cpp:151
Fader(QWidget *pParent, Type type, QString sBaseTooltip, bool bUseIntSteps=false, bool bWithoutKnob=false, float fMin=0.0, float fMax=1.0, bool bModifyOnChange=true)
Definition Fader.cpp:38
void onPreferencesChanged(H2Core::Preferences::Changes changes)
Definition Fader.cpp:115
bool m_bWithoutKnob
Definition Fader.h:71
QSvgRenderer * m_pKnob
Definition Fader.h:74
void setPeak_R(float peak)
Definition Fader.cpp:346
float m_fMinPeak
Definition Fader.h:78
float m_fPeakValue_R
Definition Fader.h:77
void setMaxPeak(float fMax)
Definition Fader.cpp:371
void setMinPeak(float fMin)
Definition Fader.cpp:403
float m_fMaxPeak
Definition Fader.h:79
virtual void paintEvent(QPaintEvent *ev) override
Definition Fader.cpp:180
float m_fPeakValue_L
Definition Fader.h:76
void setPeak_L(float peak)
Definition Fader.cpp:321
static Preferences * get_instance()
Returns a pointer to the current Preferences singleton stored in __instance.
Changes
Bitwise or-able options showing which part of the Preferences were altered using the PreferencesDialo...
@ Colors
At least one of the colors has changed.
static HydrogenApp * get_instance()
Returns the instance of HydrogenApp class.
void preferencesChanged(H2Core::Preferences::Changes changes)
Propagates a change in the Preferences through the GUI.
std::shared_ptr< Action > getAction() const
Compatibility class to support QMouseEvent more esily in Qt5 and Qt6.
Definition MouseEvent.h:35
static QString getSvgImagePath()
Definition Skin.h:40
virtual void setValue(float fValue, bool bTriggeredByUserInteraction=false)
void updateTooltip() override
Indicates child class to recalculate its tool tip in case m_registeredMidiEvents changed.
WidgetWithInput(QWidget *parent, bool bUseIntSteps, QString sBaseTooltip, int nScrollSpeed, int nScrollSpeedFast, float fMin, float fMax, bool bModifyOnChange)