hydrogen 1.2.3
LCDSpinBox.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, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include "LCDSpinBox.h"
25#include "../HydrogenApp.h"
26#include "../Skin.h"
27#include <core/Globals.h>
29
30// used in PlayerControl
31LCDSpinBox::LCDSpinBox( QWidget *pParent, QSize size, Type type, double fMin, double fMax, bool bModifyOnChange, bool bMinusOneAsOff )
32 : QDoubleSpinBox( pParent )
33 , m_size( size )
34 , m_bEntered( false )
35 , m_kind( Kind::Default )
36 , m_bIsActive( true )
37 , m_bModifyOnChange( bModifyOnChange )
38 , m_bMinusOneAsOff( bMinusOneAsOff )
39{
40 setFocusPolicy( Qt::ClickFocus );
41 setLocale( QLocale( QLocale::C, QLocale::AnyCountry ) );
42
43 if ( size.isNull() || size.isEmpty() ) {
44 m_size = sizeHint();
45 }
46 adjustSize();
47 setFixedSize( m_size );
48
49 setType( type );
50
52
53 connect( this, SIGNAL(valueChanged(double)), this,
54 SLOT(valueChanged(double)));
57
58 setMaximum( fMax );
59 setMinimum( fMin );
60 setValue( fMin );
61}
62
65
67 m_type = type;
68
69 if ( type == Type::Int ) {
70 setDecimals( 0 );
71 }
72 else {
73 setDecimals( std::numeric_limits<double>::max_exponent );
74 }
75}
76
77void LCDSpinBox::setSize( QSize size ) {
78 m_size = size;
79
80 setFixedSize( size );
81 adjustSize();
82}
83
84void LCDSpinBox::setIsActive( bool bIsActive ) {
85 m_bIsActive = bIsActive;
86
87 update();
88
89 setEnabled( bIsActive );
90 setReadOnly( ! bIsActive );
91}
92
93void LCDSpinBox::wheelEvent( QWheelEvent *ev ) {
94 static float fCumulatedDelta;
95
96 double fOldValue = value();
97
99
100 // Cumulate scroll positions to provide a native feeling for
101 // fine-grained mouse wheel and touch pads.
102 fCumulatedDelta += ev->angleDelta().y();
103
104 if ( std::fabs( fCumulatedDelta ) >= 120 ) {
105 fCumulatedDelta = 0;
106
107 double fNextValue = nextValueInPatternSizeDenominator( ev->angleDelta().y() > 0, ev->modifiers() == Qt::ControlModifier );
108
109
110 if ( fNextValue == 0 ) {
111 ERRORLOG( QString( "Couldn't find next value for input: %1" ).arg( value() ) );
112 return;
113 }
114
115 if ( ev->angleDelta().y() > 0 ) {
116 setValue( fNextValue + 1 );
117 } else {
118 setValue( fNextValue - 1 );
119 }
120 }
121 } else if ( m_kind == Kind::PatternSizeNumerator ) {
122 QDoubleSpinBox::wheelEvent( ev );
123 if ( value() < 1 ) {
124 setValue( 1 );
125 }
126 } else {
127 QDoubleSpinBox::wheelEvent( ev );
128
129 }
130
131 if ( fOldValue != value() && m_bModifyOnChange ) {
133 }
134}
135
136void LCDSpinBox::keyPressEvent( QKeyEvent *ev ) {
137 double fOldValue = value();
138
139 // Pass Undo/Redo commands up to the parent
140 if ( ev->matches( QKeySequence::StandardKey::Undo )
141 || ev->matches( QKeySequence::StandardKey::Redo ) ) {
142 ev->ignore();
143 return;
144 }
145
147 ( ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down ||
148 ev->key() == Qt::Key_PageUp || ev->key() == Qt::Key_PageDown ) ) {
149 double fNextValue;
150
151 if ( ev->key() == Qt::Key_Up ) {
152 fNextValue = nextValueInPatternSizeDenominator( true, false );
153 } else if ( ev->key() == Qt::Key_Down ) {
154 fNextValue = nextValueInPatternSizeDenominator( false, false );
155 } else if ( ev->key() == Qt::Key_PageUp ) {
156 fNextValue = nextValueInPatternSizeDenominator( true, true );
157 } else if ( ev->key() == Qt::Key_PageDown ) {
158 fNextValue = nextValueInPatternSizeDenominator( false, true );
159 }
160
161 if ( fNextValue == 0 ) {
162 ERRORLOG( QString( "Couldn't find next value for input: %1" ).arg( value() ) );
163 return;
164 }
165
166 setValue( fNextValue );
167
168 QDoubleSpinBox::keyPressEvent( ev );
169
170 } else if ( m_kind == Kind::PatternSizeNumerator ) {
171
172 QDoubleSpinBox::keyPressEvent( ev );
173
174 if ( value() < 1 ) {
175 setValue( 1 );
176 }
177
178 } else {
179 QDoubleSpinBox::keyPressEvent( ev );
180 }
181
182 if ( fOldValue != value() && m_bModifyOnChange ) {
184 }
185}
186
187double LCDSpinBox::nextValueInPatternSizeDenominator( bool bUp, bool bAccelerated ) {
188
189 // Determine the next value.
190 std::vector vChoices{ 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 192 };
191
192 double fNextValue = 1.0;
193 double fOffset = 0.0;
194
195 if ( bAccelerated ) {
196 fOffset = 10;
197 } else {
198 fOffset = 1;
199 }
200 for ( int ii = 0; ii < vChoices.size(); ii++ ) {
201 if ( vChoices[ ii ] == value() ) {
202
203 if ( bUp ) {
204 if ( ii < vChoices.size() - 1 ) {
205 fNextValue = vChoices[ ii + 1 ] - fOffset;
206 } else {
207 fNextValue = vChoices[ ii ] - fOffset;
208 }
209 if ( fNextValue < 0 ) {
210 fNextValue = 2;
211 }
212 } else {
213 if ( ii > 0 ) {
214 fNextValue = vChoices[ ii - 1 ] + fOffset;
215 } else {
216 fNextValue = vChoices[ ii ] + fOffset;
217 }
218 }
219 }
220 }
221
222 return fNextValue;
223}
224
225QString LCDSpinBox::textFromValue( double fValue ) const {
226 QString result;
227 if ( m_type == Type::Int && m_bMinusOneAsOff &&
228 fValue == -1.0 ) {
229 result = "off";
230 } else {
231 if ( m_type == Type::Int ) {
232 result = QString( "%1" ).arg( fValue, 0, 'f', 0 );
233 }
234 else {
235 result = QString( "%1" ).arg( fValue ) ;
236 }
237 }
238
239 return result;
240}
241
242QValidator::State LCDSpinBox::validate( QString &text, int &pos ) const {
244 std::vector vChoices{ "1", "2", "3", "4", "6", "8", "12", "16", "24", "32", "48", "64", "96", "192" };
245 std::vector vCandidates1{ "1", "2", "3", "4", "6", "9" };
246 QString sCandidate2( "19" );
247 bool bContained = false;
248 bool bIsCandidate = false;
249 for ( const auto& ii : vChoices ) {
250 if ( ii == text ) {
251 bContained = true;
252 }
253 }
254 for ( const auto& ii : vCandidates1 ) {
255 if ( ii == text.left( 1 ) ) {
256 bIsCandidate = true;
257 }
258 }
259 if ( sCandidate2 == text.left( 2 ) ) {
260 bIsCandidate = true;
261 }
262
263 if ( bContained ) {
264 return QValidator::Acceptable;
265 } else if ( bIsCandidate ) {
266 return QValidator::Intermediate;
267 } else {
268 return QValidator::Invalid;
269 }
270 }
271 return QDoubleSpinBox::validate( text, pos );
272}
273
274double LCDSpinBox::valueFromText( const QString& sText ) const {
275
276 double fResult;
277
278 if ( sText == "off" ){
279 fResult = -1.0;
280 } else {
281 fResult = QDoubleSpinBox::valueFromText( sText );
282 }
283
284 return fResult;
285}
286
287void LCDSpinBox::setValue( double fValue ) {
288 if ( value() == fValue ) {
289 return;
290 }
291
292 QDoubleSpinBox::setValue( fValue );
293}
294
295bool LCDSpinBox::event( QEvent* ev ) {
296
297 if ( ev->type() == QEvent::KeyPress && dynamic_cast<QKeyEvent*>( ev)->key() == Qt::Key_Slash ) {
298 emit slashKeyPressed();
299 return 0;
300 }
301
302 return QDoubleSpinBox::event( ev );
303}
304
305void LCDSpinBox::mousePressEvent( QMouseEvent* ev ) {
306 double fOldValue = value();
307
308 QDoubleSpinBox::mousePressEvent( ev );
309
310 if ( fOldValue != value() && m_bModifyOnChange ) {
312 }
313}
314
315void LCDSpinBox::mouseMoveEvent( QMouseEvent* ev ) {
316 double fOldValue = value();
317
318 QDoubleSpinBox::mouseMoveEvent( ev );
319
320 if ( fOldValue != value() && m_bModifyOnChange ) {
322 }
323}
324
325void LCDSpinBox::mouseReleaseEvent( QMouseEvent* ev ) {
326 double fOldValue = value();
327
328 QDoubleSpinBox::mouseReleaseEvent( ev );
329
330 if ( fOldValue != value() && m_bModifyOnChange ) {
332 }
333}
334
335void LCDSpinBox::paintEvent( QPaintEvent *ev ) {
336
338
339 QDoubleSpinBox::paintEvent( ev );
340
341 if ( m_bEntered || hasFocus() ) {
342 QPainter painter(this);
343
344
345 QColor colorHighlightActive;
346 if ( m_bIsActive ) {
347 colorHighlightActive = pPref->getColorTheme()->m_highlightColor;
348 } else {
349 colorHighlightActive = pPref->getColorTheme()->m_lightColor;
350 }
351
352 // If the mouse is placed on the widget but the user hasn't
353 // clicked it yet, the highlight will be done more transparent to
354 // indicate that keyboard inputs are not accepted yet.
355 if ( ! hasFocus() ) {
356 colorHighlightActive.setAlpha( 150 );
357 }
358
359 QPen pen;
360 pen.setColor( colorHighlightActive );
361 pen.setWidth( 3 );
362 painter.setPen( pen );
363 painter.drawRoundedRect( QRect( 0, 0, m_size.width(), m_size.height() ), 3, 3 );
364 }
365}
366
367void LCDSpinBox::enterEvent( QEvent* ev ) {
368 QDoubleSpinBox::enterEvent( ev );
369 m_bEntered = true;
370}
371
372void LCDSpinBox::leaveEvent( QEvent* ev ) {
373 QDoubleSpinBox::leaveEvent( ev );
374 m_bEntered = false;
375}
376
378
380
381 QColor spinBoxColor = pPref->getColorTheme()->m_spinBoxColor;
382 QColor spinBoxTextColor = pPref->getColorTheme()->m_spinBoxTextColor;
383 QColor selectionColor = spinBoxColor.darker( 120 );
384
385 QColor spinBoxInactiveColor =
386 Skin::makeWidgetColorInactive( spinBoxColor );
387 QColor spinBoxTextInactiveColor =
388 Skin::makeTextColorInactive( spinBoxTextColor );
389 QColor selectionInactiveColor =
390 Skin::makeWidgetColorInactive( selectionColor );
391
392
393 setStyleSheet( QString( "\
394QAbstractSpinBox:enabled { \
395 color: %1; \
396 background-color: %2; \
397 selection-color: %1; \
398 selection-background-color: %3; \
399} \
400QAbstractSpinBox:disabled { \
401 color: %4; \
402 background-color: %5; \
403 selection-color: %4; \
404 selection-background-color: %6; \
405}" )
406 .arg( spinBoxTextColor.name() )
407 .arg( spinBoxColor.name() )
408 .arg( selectionColor.name() )
409 .arg( spinBoxTextInactiveColor.name() )
410 .arg( spinBoxInactiveColor.name() )
411 .arg( selectionInactiveColor.name() ) );
412}
413
420
421void LCDSpinBox::valueChanged( double fNewValue ) {
422 if ( m_type == Type::Int ) {
423 emit valueChanged( static_cast<int>(fNewValue) );
424 }
425}
#define ERRORLOG(x)
Definition Object.h:239
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
Definition Hydrogen.h:83
void setIsModified(bool bIsModified)
Wrapper around Song::setIsModified() that checks whether a song is set.
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.
void valueChanged(double fNewValue)
virtual void mouseMoveEvent(QMouseEvent *ev) override
double nextValueInPatternSizeDenominator(bool bUp, bool bAccelerated)
virtual void mousePressEvent(QMouseEvent *ev) override
virtual double valueFromText(const QString &sText) const override
QSize m_size
Definition LCDSpinBox.h:103
void setValue(double fValue)
void setType(Type type)
void onPreferencesChanged(H2Core::Preferences::Changes changes)
LCDSpinBox(QWidget *pParent, QSize size=QSize(), Type type=Type::Int, double fMin=0.0, double fMax=1.0, bool bModifyOnChange=false, bool bMinusOneAsOff=false)
bool m_bModifyOnChange
Whether Hydrogen::setIsModified() is invoked with true as soon as the value of the widget does change...
Definition LCDSpinBox.h:116
virtual QValidator::State validate(QString &text, int &pos) const override
bool m_bMinusOneAsOff
In some widgets the QString "off" will be displayed instead of -1.
Definition LCDSpinBox.h:112
virtual void leaveEvent(QEvent *ev) override
virtual void wheelEvent(QWheelEvent *ev) override
virtual void keyPressEvent(QKeyEvent *ev) override
virtual void mouseReleaseEvent(QMouseEvent *ev) override
void updateStyleSheet()
void setSize(QSize size)
virtual bool event(QEvent *ev) override
@ PatternSizeNumerator
The minimum value - a fractional one - can only be reached by entering it using the keyboard.
@ PatternSizeDenominator
Only a limited number of values is allowed.
bool m_bIsActive
Definition LCDSpinBox.h:108
virtual QString textFromValue(double fValue) const override
virtual void paintEvent(QPaintEvent *ev) override
void setIsActive(bool bIsActive)
void slashKeyPressed()
virtual void enterEvent(QEvent *ev) override
bool m_bEntered
Definition LCDSpinBox.h:107
static QColor makeTextColorInactive(QColor color)
If a widget is marked inactive the value of its text color are reduced by this factor.
Definition Skin.cpp:176
static QColor makeWidgetColorInactive(QColor color)
If a widget is marked inactive the value of its background color are reduced by this factor.
Definition Skin.cpp:167