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