hydrogen 1.2.3
Button.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#include "Button.h"
24
25#include "../Skin.h"
26#include "../HydrogenApp.h"
27#include "../CommonStrings.h"
28#include "MidiSenseWidget.h"
29
30#include <qglobal.h> // for QT_VERSION
31
32#include <core/Globals.h>
35#include <core/Hydrogen.h>
36
37Button::Button( QWidget *pParent, QSize size, Type type, const QString& sIcon, const QString& sText, bool bUseRedBackground, QSize iconSize, QString sBaseTooltip, bool bColorful, bool bModifyOnChange, int nBorderRadius )
38 : QPushButton( pParent )
39 , m_size( size )
40 , m_type( type )
41 , m_iconSize( iconSize )
42 , m_sBaseTooltip( sBaseTooltip )
43 , m_bColorful( bColorful )
44 , m_bLastCheckedState( false )
45 , m_sIcon( sIcon )
46 , m_bIsActive( true )
47 , m_bUseRedBackground( bUseRedBackground )
48 , m_nFixedFontSize( -1 )
49 , m_bModifyOnChange( bModifyOnChange )
50 , m_nBorderRadius( nBorderRadius )
51{
52 setFocusPolicy( Qt::NoFocus );
53
54 if ( size.isNull() || size.isEmpty() ) {
55 m_size = sizeHint();
56 }
57 adjustSize();
58 setFixedSize( m_size );
59 resize( m_size );
60
61 if ( ! sIcon.isEmpty() ) {
62 updateIcon();
63 } else {
64 setText( sText );
65 }
66
67 if ( m_nBorderRadius == -1 ) {
68 if ( size.width() <= 12 || size.height() <= 12 ) {
70 } else if ( size.width() <= 20 || size.height() <= 20 ) {
72 } else {
74 }
75 }
76
77 if ( type == Type::Toggle ) {
78 setCheckable( true );
79 } else {
80 setCheckable( false );
81 }
82
83 if ( type == Type::Icon ) {
84 setFlat( true );
85 }
86
87 updateFont();
90
92
93 connect( this, SIGNAL(clicked()), this, SLOT(onClick()));
94}
95
98
99void Button::setIsActive( bool bIsActive ) {
100 m_bIsActive = bIsActive;
101
102 setEnabled( bIsActive );
103
104 update();
105}
106
107
109 if ( m_bColorful ) {
110 setIcon( QIcon( Skin::getSvgImagePath() + "/icons/" + m_sIcon ) );
111 } else {
112 if ( H2Core::Preferences::get_instance()->getIconColor() ==
114 setIcon( QIcon( Skin::getSvgImagePath() + "/icons/white/" + m_sIcon ) );
115 } else {
116 setIcon( QIcon( Skin::getSvgImagePath() + "/icons/black/" + m_sIcon ) );
117 }
118 }
119 setIconSize( m_iconSize );
120}
121
122void Button::setUseRedBackground( bool bUseRedBackground ) {
123 m_bUseRedBackground = bUseRedBackground;
124
126 update();
127}
128
130
131 if ( m_type == Type::Icon ) {
132 // Make background transparent
133 setStyleSheet( "QPushButton { background-color: none; }" );
134 return;
135 }
136
138
139 int nFactorGradient = 126;
140 int nFactorGradientShadow = 225;
141 int nHover = 12;
142 float fStop1 = 0.2;
143 float fStop2 = 0.85;
144 float x1 = 0;
145 float x2 = 1;
146 float y1 = 0;
147 float y2 = 1;
148
149 QColor baseColorBackground = pPref->getColorTheme()->m_widgetColor;
150 QColor backgroundLight = baseColorBackground.lighter( nFactorGradient );
151 QColor backgroundDark = baseColorBackground.darker( nFactorGradient );
152 QColor backgroundLightHover = baseColorBackground.lighter( nFactorGradient + nHover );
153 QColor backgroundDarkHover = baseColorBackground.darker( nFactorGradient + nHover );
154 QColor backgroundShadowLight = baseColorBackground.lighter( nFactorGradientShadow );
155 QColor backgroundShadowDark = baseColorBackground.darker( nFactorGradientShadow );
156 QColor backgroundShadowLightHover = baseColorBackground.lighter( nFactorGradientShadow + nHover );
157 QColor backgroundShadowDarkHover = baseColorBackground.darker( nFactorGradientShadow + nHover );
158 QColor border = Qt::black;
159
160 QColor baseColorBackgroundChecked, textChecked;
161 if ( ! m_bUseRedBackground ) {
162 baseColorBackgroundChecked = pPref->getColorTheme()->m_accentColor;
163 textChecked = pPref->getColorTheme()->m_accentTextColor;
164 } else {
165 baseColorBackgroundChecked = pPref->getColorTheme()->m_buttonRedColor;
166 textChecked = pPref->getColorTheme()->m_buttonRedTextColor;
167 }
168
169 QColor backgroundCheckedLight = baseColorBackgroundChecked.lighter( nFactorGradient );
170 QColor backgroundCheckedDark = baseColorBackgroundChecked.darker( nFactorGradient );
171 QColor backgroundCheckedLightHover = baseColorBackgroundChecked.lighter( nFactorGradient + nHover );
172 QColor backgroundCheckedDarkHover = baseColorBackgroundChecked.darker( nFactorGradient + nHover );
173 QColor backgroundShadowCheckedLight = baseColorBackgroundChecked.lighter( nFactorGradientShadow );
174 QColor backgroundShadowCheckedDark = baseColorBackgroundChecked.darker( nFactorGradientShadow );
175 QColor backgroundShadowCheckedLightHover = baseColorBackgroundChecked.lighter( nFactorGradientShadow + nHover );
176 QColor backgroundShadowCheckedDarkHover = baseColorBackgroundChecked.darker( nFactorGradientShadow + nHover );
177
178 QColor textColor = pPref->getColorTheme()->m_widgetTextColor;
179
180 QColor backgroundInactiveLight =
181 Skin::makeWidgetColorInactive( backgroundLight );
182 QColor backgroundInactiveLightHover = backgroundInactiveLight;
183 QColor backgroundInactiveCheckedLight =
184 Skin::makeWidgetColorInactive( backgroundCheckedLight );
185 QColor backgroundInactiveCheckedLightHover = backgroundInactiveCheckedLight;
186 QColor backgroundInactiveDark =
187 Skin::makeWidgetColorInactive( backgroundDark );
188 QColor backgroundInactiveDarkHover = backgroundInactiveDark;
189 QColor backgroundInactiveCheckedDark =
190 Skin::makeWidgetColorInactive( backgroundCheckedDark );
191 QColor backgroundInactiveCheckedDarkHover = backgroundInactiveCheckedDark;
192 QColor backgroundShadowInactiveLight =
193 Skin::makeWidgetColorInactive( backgroundShadowLight );
194 QColor backgroundShadowInactiveLightHover = backgroundShadowInactiveLight;
195 QColor backgroundShadowInactiveCheckedLight =
196 Skin::makeWidgetColorInactive( backgroundShadowCheckedLight );
197 QColor backgroundShadowInactiveCheckedLightHover = backgroundShadowInactiveCheckedLight;
198 QColor backgroundShadowInactiveDark =
199 Skin::makeWidgetColorInactive( backgroundShadowDark );
200 QColor backgroundShadowInactiveDarkHover = backgroundShadowInactiveDark;
201 QColor backgroundShadowInactiveCheckedDark =
202 Skin::makeWidgetColorInactive( backgroundShadowCheckedDark );
203 QColor backgroundShadowInactiveCheckedDarkHover = backgroundShadowInactiveCheckedDark;
204 QColor textInactiveColor = Skin::makeTextColorInactive( textColor );
205
206 setStyleSheet( QString( "\
207QPushButton:enabled { \
208 color: %1; \
209 border: 1px solid %12; \
210 border-radius: %2px; \
211 padding: 0px; \
212 background-color: qlineargradient(x1: %41, y1: %43, x2: %42, y2: %44, \
213 stop: 0 %23, stop: %39 %3, \
214 stop: %40 %4, stop: 1 %24); \
215} \
216QPushButton:enabled:hover { \
217 background-color: qlineargradient(x1: %41, y1: %43, x2: %42, y2: %44, \
218 stop: 0 %25, stop: %39 %5, \
219 stop: %40 %6, stop: 1 %26); \
220} \
221QPushButton:enabled:checked { \
222 color: %7; \
223 border: 1px solid %12; \
224 border-radius: %2px; \
225 padding: 0px; \
226 background-color: qlineargradient(x1: %41, y1: %43, x2: %42, y2: %44, \
227 stop: 0 %27, stop: %39 %8, \
228 stop: %40 %9, stop: 1 %28); \
229} \
230QPushButton:enabled:checked:hover { \
231 background-color: qlineargradient(x1: %41, y1: %43, x2: %42, y2: %44, \
232 stop: 0 %29, stop: %39 %10, \
233 stop: %40 %11, stop: 1 %30); \
234} \
235QPushButton:disabled { \
236 color: %13; \
237 border: 1px solid %12; \
238 border-radius: %2px; \
239 padding: 0px; \
240 background-color: qlineargradient(x1: %41, y1: %43, x2: %42, y2: %44, \
241 stop: 0 %31, stop: %39 %14, \
242 stop: %40 %15, stop: 1 %32); \
243} \
244QPushButton:disabled:hover { \
245 background-color: qlineargradient(x1: %41, y1: %43, x2: %42, y2: %44, \
246 stop: 0 %33, stop: %39 %16, \
247 stop: %40 %17, stop: 1 %34); \
248} \
249QPushButton:disabled:checked { \
250 color: %18; \
251 border: 1px solid %12; \
252 border-radius: %2px; \
253 padding: 0px; \
254 background-color: qlineargradient(x1: %41, y1: %43, x2: %42, y2: %44, \
255 stop: 0 %35, stop: %39 %19, \
256 stop: %40 %20, stop: 1 %36); \
257} \
258QPushButton:disabled:checked:hover { \
259 background-color: qlineargradient(x1: %41, y1: %43, x2: %42, y2: %44, \
260 stop: 0 %37, stop: %39 %21, \
261 stop: %40 %22, stop: 1 %38); \
262}"
263 )
264 .arg( textColor.name() )
265 .arg( m_nBorderRadius )
266 .arg( backgroundLight.name() )
267 .arg( backgroundDark.name() )
268 .arg( backgroundLightHover.name() )
269 .arg( backgroundDarkHover.name() )
270 .arg( textChecked.name() )
271 .arg( backgroundCheckedLight.name() )
272 .arg( backgroundCheckedDark.name() )
273 .arg( backgroundCheckedLightHover.name() )
274 .arg( backgroundCheckedDarkHover.name() )
275 .arg( border.name() )
276 .arg( textInactiveColor.name() )
277 .arg( backgroundInactiveLight.name() )
278 .arg( backgroundInactiveDark.name() )
279 .arg( backgroundInactiveLightHover.name() )
280 .arg( backgroundInactiveDarkHover.name() )
281 .arg( textChecked.name() )
282 .arg( backgroundInactiveCheckedLight.name() )
283 .arg( backgroundInactiveCheckedDark.name() )
284 .arg( backgroundInactiveCheckedLightHover.name() )
285 .arg( backgroundInactiveCheckedDarkHover.name() )
286 .arg( backgroundShadowLight.name() )
287 .arg( backgroundShadowDark.name() )
288 .arg( backgroundShadowLightHover.name() )
289 .arg( backgroundShadowDarkHover.name() )
290 .arg( backgroundShadowCheckedLight.name() )
291 .arg( backgroundShadowCheckedDark.name() )
292 .arg( backgroundShadowCheckedLightHover.name() )
293 .arg( backgroundShadowCheckedDarkHover.name() )
294 .arg( backgroundShadowInactiveLight.name() )
295 .arg( backgroundShadowInactiveDark.name() )
296 .arg( backgroundShadowInactiveLightHover.name() )
297 .arg( backgroundShadowInactiveDarkHover.name() )
298 .arg( backgroundShadowInactiveCheckedLight.name() )
299 .arg( backgroundShadowInactiveCheckedDark.name() )
300 .arg( backgroundShadowInactiveCheckedLightHover.name() )
301 .arg( backgroundShadowInactiveCheckedDarkHover.name() )
302 .arg( fStop1 ).arg( fStop2 ).arg( x1 ).arg( x2 )
303 .arg( y1 ).arg( y2 ) );
304}
305
306void Button::setBaseToolTip( const QString& sNewTip ) {
307 m_sBaseTooltip = sNewTip;
309}
310
311void Button::mousePressEvent(QMouseEvent*ev) {
312 if ( ev->button() == Qt::RightButton ) {
313 emit rightClicked();
314 }
315
316 /*
317 * Shift + Left-Click activate the midi learn widget
318 */
319
320 if ( ev->button() == Qt::LeftButton && ( ev->modifiers() & Qt::ShiftModifier ) ){
321 MidiSenseWidget midiSense( this, true, this->getAction() );
322 midiSense.exec();
323 return;
324 }
325
326 QPushButton::mousePressEvent( ev );
327}
328
330
331 auto pCommonStrings = HydrogenApp::get_instance()->getCommonStrings();
332
333 QString sTip = QString("%1" ).arg( m_sBaseTooltip );
334
335 // Add the associated MIDI action.
336 if ( m_pAction != nullptr ) {
337 sTip.append( QString( "\n%1: %2 " ).arg( pCommonStrings->getMidiTooltipHeading() )
338 .arg( m_pAction->getType() ) );
339 if ( m_registeredMidiEvents.size() > 0 ) {
340 for ( const auto& [event, nnParam] : m_registeredMidiEvents ) {
341 if ( event == H2Core::MidiMessage::Event::Note ||
343 sTip.append( QString( "\n%1 [%2 : %3]" )
344 .arg( pCommonStrings->getMidiTooltipBound() )
346 .arg( nnParam ) );
347 }
348 else {
349 // PC and MMC_x do not have a parameter.
350 sTip.append( QString( "\n%1 [%2]" )
351 .arg( pCommonStrings->getMidiTooltipBound() )
352 .arg( H2Core::MidiMessage::EventToQString( event ) ) );
353 }
354 }
355 }
356 else {
357 sTip.append( QString( "%1" ).arg( pCommonStrings->getMidiTooltipUnbound() ) );
358 }
359 }
360
361 setToolTip( sTip );
362}
363
364void Button::setSize( QSize size ) {
365 m_size = size;
366
367 adjustSize();
368 if ( ! size.isNull() ) {
369 setFixedSize( size );
370 resize( size );
371 }
372
373 updateFont();
374}
375
376void Button::setType( Type type ) {
377
378 if ( type == Type::Toggle ) {
379 setCheckable( true );
380 } else {
381 setCheckable( false );
382 }
383
384 if ( type == Type::Icon ) {
385 setFlat( true );
386 } else {
387 setFlat( false );
388 }
389
390 m_type = type;
391
393 update();
394}
395
397
399
400 float fScalingFactor = 1.0;
401 switch ( pPref->getFontSize() ) {
403 fScalingFactor = 1.2;
404 break;
406 fScalingFactor = 1.0;
407 break;
409 fScalingFactor = 0.75;
410 break;
411 }
412
413 int nPixelSize;
414 if ( m_nFixedFontSize < 0 ) {
415
416 int nMargin;
417 if ( m_size.width() <= 12 || m_size.height() <= 12 ) {
418 nMargin = 1;
419 } else if ( m_size.width() <= 19 || m_size.height() <= 19 ) {
420 nMargin = 5;
421 } else if ( m_size.width() <= 22 || m_size.height() <= 22 ) {
422 nMargin = 7;
423 } else {
424 nMargin = 9;
425 }
426
427 if ( m_size.width() >= m_size.height() ) {
428 nPixelSize = m_size.height() - std::round( fScalingFactor * nMargin );
429 } else {
430 nPixelSize = m_size.width() - std::round( fScalingFactor * nMargin );
431 }
432 } else {
433 nPixelSize = m_nFixedFontSize;
434 }
435
436 QFont font( pPref->getLevel3FontFamily() );
437 font.setPixelSize( nPixelSize );
438
439 if ( m_size.width() > m_size.height() ) {
440 // Check whether the width of the text fits the available frame
441 // width of the button.
442 while ( QFontMetrics( font ).size( Qt::TextSingleLine, text() ).width() >
443 width() && nPixelSize > 1 ) {
444 nPixelSize--;
445 font.setPixelSize( nPixelSize );
446 }
447 }
448
449 // This method must not be called more than once in this routine. Otherwise,
450 // a repaint of the widget is triggered, which calls `updateFont()` again
451 // and we are trapped in an infinite loop.
452 setFont( font );
453}
454
455void Button::paintEvent( QPaintEvent* ev )
456{
457 QPushButton::paintEvent( ev );
458
459 updateFont();
460
461 // Grey-out the widget some more if it is not enabled
462 if ( ! isEnabled() ) {
463 QPainter( this ).fillRect( ev->rect(), QColor( 128, 128, 128, 48 ) );
464 }
465
466}
467
480
482 if ( m_bModifyOnChange ) {
484 }
485}
486
487void Button::setBorderRadius( int nBorderRadius ) {
488 m_nBorderRadius = nBorderRadius;
490}
QString getType() const
Definition MidiAction.h:76
Type m_type
Definition Button.h:156
@ Icon
Button is both flat and has a transparent background.
@ Toggle
Button is set checkable.
virtual void mousePressEvent(QMouseEvent *ev) override
Definition Button.cpp:311
QSize m_size
Definition Button.h:157
void setUseRedBackground(bool bUseRedBackground)
Definition Button.cpp:122
void setBorderRadius(int nBorderRadius)
Definition Button.cpp:487
void updateTooltip() override
Indicates child class to recalculate its tool tip in case m_registeredMidiEvents changed.
Definition Button.cpp:329
void setType(Type type)
Definition Button.cpp:376
void setBaseToolTip(const QString &sNewTip)
Definition Button.cpp:306
void onPreferencesChanged(H2Core::Preferences::Changes changes)
Definition Button.cpp:468
bool m_bModifyOnChange
Whether Hydrogen::setIsModified() is invoked with true as soon as the value of the widget does change...
Definition Button.h:172
void onClick()
Definition Button.cpp:481
virtual ~Button()
Definition Button.cpp:96
void updateStyleSheet()
Definition Button.cpp:129
void setSize(QSize size)
Definition Button.cpp:364
QString m_sBaseTooltip
Definition Button.h:159
QString m_sIcon
Definition Button.h:160
bool m_bColorful
Definition Button.h:165
int m_nFixedFontSize
Definition Button.h:161
bool m_bIsActive
Definition Button.h:168
void rightClicked()
virtual void paintEvent(QPaintEvent *ev) override
Definition Button.cpp:455
bool m_bUseRedBackground
Definition Button.h:155
void updateIcon()
Definition Button.cpp:108
void setIsActive(bool bIsActive)
Definition Button.cpp:99
int m_nBorderRadius
Definition Button.h:163
QSize m_iconSize
Definition Button.h:158
Button(QWidget *pParent, QSize size=QSize(), Type type=Type::Toggle, const QString &sIcon="", const QString &sText="", bool bUseRedBackground=false, QSize iconSize=QSize(0, 0), QString sBaseTooltip="", bool bColorful=false, bool bModifyOnChange=false, int nBorderRadius=-1)
Either the path to a SVG image or a text to be displayed has to be provided.
Definition Button.cpp:37
void updateFont()
Definition Button.cpp:396
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 QString EventToQString(Event event)
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...
@ AppearanceTab
Any option in the Appearance tab excluding colors, font size, or font family.
@ Font
Either the font size or font family have changed.
@ Colors
At least one of the colors has changed.
static HydrogenApp * get_instance()
Returns the instance of HydrogenApp class.
std::shared_ptr< CommonStrings > getCommonStrings()
void preferencesChanged(H2Core::Preferences::Changes changes)
Propagates a change in the Preferences through the GUI.
std::vector< std::pair< H2Core::MidiMessage::Event, int > > m_registeredMidiEvents
Stores all MIDI events mapped to m_pAction.
std::shared_ptr< Action > m_pAction
std::shared_ptr< Action > getAction() const
static QString getSvgImagePath()
Definition Skin.h:40
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