2 * Piano.cpp - implementation of piano-widget used in instrument-track-window
3 * for testing + according model class
5 * Copyright (c) 2004-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
7 * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public
20 * License along with this program (see COPYING); if not, write to the
21 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301 USA.
27 * \brief A piano keyboard to play notes on in the instrument plugin window.
31 * \mainpage Instrument plugin keyboard display classes
33 * \section introduction Introduction
36 * \todo write isWhite inline function and replace throughout
40 #include <QtGui/QCursor>
41 #include <QtGui/QKeyEvent>
42 #include <QtGui/QMouseEvent>
43 #include <QtGui/QPainter>
44 #include <QtGui/QVBoxLayout>
47 #include "PianoView.h"
48 #include "caption_menu.h"
51 #include "gui_templates.h"
52 #include "InstrumentTrack.h"
54 #include "string_pair_drag.h"
55 #include "MainWindow.h"
57 #include "templates.h"
58 #include "update_event.h"
66 /*! The black / white order of keys as they appear on the keyboard.
68 const Piano::KeyTypes KEY_ORDER
[] =
71 Piano::WhiteKey
, Piano::BlackKey
, Piano::WhiteKey
, Piano::BlackKey
,
73 Piano::WhiteKey
, Piano::WhiteKey
, Piano::BlackKey
, Piano::WhiteKey
,
75 Piano::BlackKey
, Piano::WhiteKey
, Piano::BlackKey
, Piano::WhiteKey
79 /*! The scale of C Major - white keys only.
83 Key_C
, Key_D
, Key_E
, Key_F
, Key_G
, Key_A
, Key_H
87 QPixmap
* PianoView::s_whiteKeyPm
= NULL
; /*!< A white key released */
88 QPixmap
* PianoView::s_blackKeyPm
= NULL
; /*!< A black key released */
89 QPixmap
* PianoView::s_whiteKeyPressedPm
= NULL
; /*!< A white key pressed */
90 QPixmap
* PianoView::s_blackKeyPressedPm
= NULL
; /*!< A black key pressed */
93 const int PIANO_BASE
= 11; /*!< The height of the root note display */
94 const int PW_WHITE_KEY_WIDTH
= 10; /*!< The width of a white key */
95 const int PW_BLACK_KEY_WIDTH
= 8; /*!< The width of a black key */
96 const int PW_WHITE_KEY_HEIGHT
= 57; /*!< The height of a white key */
97 const int PW_BLACK_KEY_HEIGHT
= 38; /*!< The height of a black key */
98 const int LABEL_TEXT_SIZE
= 7; /*!< The height of the key label text */
103 /*! \brief Create a new keyboard display view
105 * \param _parent the parent instrument plugin window
106 * \todo are the descriptions of the m_startkey and m_lastkey properties correct?
108 PianoView::PianoView( QWidget
* _parent
) :
109 QWidget( _parent
), /*!< Our parent */
110 ModelView( NULL
, this ), /*!< Our view Model */
111 m_piano( NULL
), /*!< Our piano Model */
112 m_startKey( Key_C
+ Octave_3
*KeysPerOctave
), /*!< The first key displayed? */
113 m_lastKey( -1 ) /*!< The last key displayed? */
115 if( s_whiteKeyPm
== NULL
)
117 s_whiteKeyPm
= new QPixmap( embed::getIconPixmap( "white_key" ) );
119 if( s_blackKeyPm
== NULL
)
121 s_blackKeyPm
= new QPixmap( embed::getIconPixmap( "black_key" ) );
123 if( s_whiteKeyPressedPm
== NULL
)
125 s_whiteKeyPressedPm
= new QPixmap( embed::getIconPixmap( "white_key_pressed" ) );
127 if ( s_blackKeyPressedPm
== NULL
)
129 s_blackKeyPressedPm
= new QPixmap( embed::getIconPixmap( "black_key_pressed" ) );
132 setAttribute( Qt::WA_OpaquePaintEvent
, true );
133 setFocusPolicy( Qt::StrongFocus
);
134 setMaximumWidth( WhiteKeysPerOctave
* NumOctaves
* PW_WHITE_KEY_WIDTH
);
136 // create scrollbar at the bottom
137 m_pianoScroll
= new QScrollBar( Qt::Horizontal
, this );
138 m_pianoScroll
->setSingleStep( 1 );
139 m_pianoScroll
->setPageStep( 20 );
140 m_pianoScroll
->setValue( Octave_3
* WhiteKeysPerOctave
);
142 // and connect it to this widget
143 connect( m_pianoScroll
, SIGNAL( valueChanged( int ) ),
144 this, SLOT( pianoScrolled( int ) ) );
146 // create a layout for ourselves
147 QVBoxLayout
* layout
= new QVBoxLayout( this );
148 layout
->setSpacing( 0 );
149 layout
->setMargin( 0 );
150 layout
->addSpacing( PIANO_BASE
+PW_WHITE_KEY_HEIGHT
);
151 layout
->addWidget( m_pianoScroll
);
158 /*! \brief Destroy this piano display view
161 PianoView::~PianoView()
168 /*! \brief Map a keyboard key being pressed to a note in our keyboard view
170 * \param _k The keyboard scan code of the key being pressed.
171 * \todo check the scan codes for ',' = c, 'L' = c#, '.' = d, ':' = d#,
172 * '/' = d, '[' = f', '=' = f'#, ']' = g' - Paul's additions
174 int PianoView::getKeyFromKeyEvent( QKeyEvent
* _ke
)
176 #ifdef LMMS_BUILD_APPLE
177 const int k
= _ke
->nativeVirtualKey();
179 const int k
= _ke
->nativeScanCode();
182 #ifdef LMMS_BUILD_WIN32
185 case 44: return 0; // Z = C
186 case 31: return 1; // S = C#
187 case 45: return 2; // X = D
188 case 32: return 3; // D = D#
189 case 46: return 4; // C = E
190 case 47: return 5; // V = F
191 case 34: return 6; // G = F#
192 case 48: return 7; // B = G
193 case 35: return 8; // H = G#
194 case 49: return 9; // N = A
195 case 36: return 10; // J = A#
196 case 50: return 11; // M = B
197 case 51: return 12; // , = c
198 case 38: return 13; // L = c#
199 case 52: return 14; // . = d
200 case 39: return 15; // ; = d#
201 case 86: return 16; // / = e
202 case 16: return 12; // Q = c
203 case 3: return 13; // 2 = c#
204 case 17: return 14; // W = d
205 case 4: return 15; // 3 = d#
206 case 18: return 16; // E = e
207 case 19: return 17; // R = f
208 case 6: return 18; // 5 = f#
209 case 20: return 19; // T = g
210 case 7: return 20; // 6 = g#
211 case 21: return 21; // Y = a
212 case 8: return 22; // 7 = a#
213 case 22: return 23; // U = b
214 case 23: return 24; // I = c'
215 case 10: return 25; // 9 = c'#
216 case 24: return 26; // O = d'
217 case 11: return 27; // 0 = d'#
218 case 25: return 28; // P = e'
221 #ifdef LMMS_BUILD_LINUX
224 case 52: return 0; // Z = C
225 case 39: return 1; // S = C#
226 case 53: return 2; // X = D
227 case 40: return 3; // D = D#
228 case 54: return 4; // C = E
229 case 55: return 5; // V = F
230 case 42: return 6; // G = F#
231 case 56: return 7; // B = G
232 case 43: return 8; // H = G#
233 case 57: return 9; // N = A
234 case 44: return 10; // J = A#
235 case 58: return 11; // M = B
236 case 59: return 12; // , = c
237 case 46: return 13; // L = c#
238 case 60: return 14; // . = d
239 case 47: return 15; // ; = d#
240 case 61: return 16; // / = e
241 case 24: return 12; // Q = c
242 case 11: return 13; // 2 = c#
243 case 25: return 14; // W = d
244 case 12: return 15; // 3 = d#
245 case 26: return 16; // E = e
246 case 27: return 17; // R = f
247 case 14: return 18; // 5 = f#
248 case 28: return 19; // T = g
249 case 15: return 20; // 6 = g#
250 case 29: return 21; // Y = a
251 case 16: return 22; // 7 = a#
252 case 30: return 23; // U = b
253 case 31: return 24; // I = c'
254 case 18: return 25; // 9 = c'#
255 case 32: return 26; // O = d'
256 case 19: return 27; // 0 = d'#
257 case 33: return 28; // P = e'
260 #ifdef LMMS_BUILD_APPLE
263 case 6: return 0; // Z = C
264 case 1: return 1; // S = C#
265 case 7: return 2; // X = D
266 case 2: return 3; // D = D#
267 case 8: return 4; // C = E
268 case 9: return 5; // V = F
269 case 5: return 6; // G = F#
270 case 11: return 7; // B = G
271 case 4: return 8; // H = G#
272 case 45: return 9; // N = A
273 case 38: return 10; // J = A#
274 case 46: return 11; // M = B
275 case 43: return 12; // , = c
276 case 37: return 13; // L = c#
277 case 47: return 14; // . = d
278 case 41: return 15; // ; = d#
279 case 44: return 16; // / = e
280 case 12: return 12; // Q = c
281 case 19: return 13; // 2 = c#
282 case 13: return 14; // W = d
283 case 20: return 15; // 3 = d#
284 case 14: return 16; // E = e
285 case 15: return 17; // R = f
286 case 23: return 18; // 5 = f#
287 case 17: return 19; // T = g
288 case 22: return 20; // 6 = g#
289 case 16: return 21; // Y = a
290 case 26: return 22; // 7 = a#
291 case 32: return 23; // U = b
292 case 34: return 24; // I = c'
293 case 25: return 25; // 9 = c'#
294 case 31: return 26; // O = d'
295 case 29: return 27; // 0 = d'#
296 case 35: return 28; // P = e'
306 /*! \brief Register a change to this piano display view
309 void PianoView::modelChanged()
311 m_piano
= castModel
<Piano
>();
312 if( m_piano
!= NULL
)
314 connect( m_piano
->m_instrumentTrack
->baseNoteModel(),
315 SIGNAL( dataChanged() ), this, SLOT( update() ) );
323 // gets the key from the given mouse-position
324 /*! \brief Get the key from the mouse position in the piano display
326 * First we determine it roughly by the position of the point given in
327 * white key widths from our start. We then add in any black keys that
328 * might have been skipped over (they take a key number, but no 'white
329 * key' space). We then add in our starting key number.
331 * We then determine whether it was a black key that was pressed by
332 * checking whether it was within the vertical range of black keys.
333 * Black keys sit exactly between white keys on this keyboard, so
334 * we then shift the note down or up if we were in the left or right
335 * half of the white note. We only do this, of course, if the white
336 * note has a black key on that side, so to speak.
338 * This function returns const because there is a linear mapping from
339 * the point given to the key returned that never changes.
341 * \param _p The point that the mouse was pressed.
343 int PianoView::getKeyFromMouse( const QPoint
& _p
) const
345 int key_num
= (int)( (float) _p
.x() / (float) PW_WHITE_KEY_WIDTH
);
347 for( int i
= 0; i
<= key_num
; ++i
)
349 if( KEY_ORDER
[( m_startKey
+i
) % KeysPerOctave
] ==
356 key_num
+= m_startKey
;
358 // is it a black key?
359 if( _p
.y() < PIANO_BASE
+ PW_BLACK_KEY_HEIGHT
)
361 // then do extra checking whether the mouse-cursor is over
363 if( key_num
> 0 && KEY_ORDER
[(key_num
-1 ) % KeysPerOctave
] ==
365 _p
.x() % PW_WHITE_KEY_WIDTH
<=
366 ( PW_WHITE_KEY_WIDTH
/ 2 ) -
367 ( PW_BLACK_KEY_WIDTH
/ 2 ) )
371 if( key_num
< NumKeys
- 1 &&
372 KEY_ORDER
[( key_num
+ 1 ) % KeysPerOctave
] ==
374 _p
.x() % PW_WHITE_KEY_WIDTH
>=
375 ( PW_WHITE_KEY_WIDTH
-
376 PW_BLACK_KEY_WIDTH
/ 2 ) )
382 // some range-checking-stuff
383 return tLimit( key_num
, 0, NumKeys
- 1 );
389 // handler for scrolling-event
390 /*! \brief Handle the scrolling on the piano display view
392 * We need to update our start key position based on the new position.
394 * \param _new_pos the new key position.
396 void PianoView::pianoScrolled( int _new_pos
)
398 m_startKey
= WhiteKeys
[_new_pos
% WhiteKeysPerOctave
]+
399 ( _new_pos
/ WhiteKeysPerOctave
) * KeysPerOctave
;
407 /*! \brief Handle a context menu selection on the piano display view
409 * \param _me the ContextMenuEvent to handle.
410 * \todo Is this right, or does this create the context menu?
412 void PianoView::contextMenuEvent( QContextMenuEvent
* _me
)
414 if( _me
->pos().y() > PIANO_BASE
|| m_piano
== NULL
)
416 QWidget::contextMenuEvent( _me
);
420 captionMenu
contextMenu( tr( "Base note" ) );
421 AutomatableModelView
amv( m_piano
->m_instrumentTrack
->baseNoteModel(),
423 amv
.addDefaultActions( &contextMenu
);
424 contextMenu
.exec( QCursor::pos() );
430 // handler for mouse-click-event
431 /*! \brief Handle a mouse click on this piano display view
433 * We first determine the key number using the getKeyFromMouse() method.
435 * If we're below the 'root key selection' area,
436 * we set the volume of the note to be proportional to the vertical
437 * position on the keyboard - lower down the key is louder, within the
438 * boundaries of the (white or black) key pressed. We then tell the
439 * instrument to play that note, scaling for MIDI max loudness = 127.
441 * If we're in the 'root key selection' area, of course, we set the
442 * root key to be that key.
444 * We finally update ourselves to show the key press
446 * \param _me the mouse click to handle.
448 void PianoView::mousePressEvent( QMouseEvent
* _me
)
450 if( _me
->button() == Qt::LeftButton
&& m_piano
!= NULL
)
453 Uint32 key_num
= getKeyFromMouse( _me
->pos() );
454 if( _me
->pos().y() > PIANO_BASE
)
456 int y_diff
= _me
->pos().y() - PIANO_BASE
;
457 int velocity
= (int)( ( float ) y_diff
/
458 ( ( KEY_ORDER
[key_num
% KeysPerOctave
] ==
460 PW_WHITE_KEY_HEIGHT
: PW_BLACK_KEY_HEIGHT
) *
461 (float) MidiMaxVelocity
);
467 ( ( KEY_ORDER
[key_num
% KeysPerOctave
] ==
469 PW_WHITE_KEY_HEIGHT
: PW_BLACK_KEY_HEIGHT
) )
471 velocity
= MidiMaxVelocity
;
474 m_piano
->m_instrumentTrack
->processInEvent(
475 midiEvent( MidiNoteOn
, 0, key_num
,
478 m_piano
->m_pressedKeys
[key_num
] = true;
481 emit
keyPressed( key_num
);
485 if( _me
->modifiers() & Qt::ControlModifier
)
487 new stringPairDrag( "automatable_model",
488 QString::number( m_piano
->
490 baseNoteModel()->id() ),
496 m_piano
->m_instrumentTrack
->
498 setInitValue( (float) key_num
);
500 emit
baseNoteChanged();
504 // and let the user see that he pressed a key... :)
512 // handler for mouse-release-event
513 /*! \brief Handle a mouse release event on the piano display view
515 * If a key was pressed by the in the mousePressEvent() function, we
518 * \param _me the mousePressEvent to handle.
520 void PianoView::mouseReleaseEvent( QMouseEvent
* )
522 if( m_lastKey
!= -1 )
524 if( m_piano
!= NULL
)
526 m_piano
->m_midiEvProc
->processInEvent(
527 midiEvent( MidiNoteOff
, 0, m_lastKey
, 0 ),
529 m_piano
->m_pressedKeys
[m_lastKey
] = false;
532 // and let the user see that he released a key... :)
542 // handler for mouse-move-event
543 /*! \brief Handle a mouse move event on the piano display view
545 * This handles the user dragging the mouse across the keys. It uses
546 * code from mousePressEvent() and mouseReleaseEvent(), also correcting
547 * for if the mouse movement has stayed within one key and if the mouse
548 * has moved outside the vertical area of the keyboard (which is still
549 * allowed but won't make the volume go up to 11).
551 * \param _me the ContextMenuEvent to handle.
552 * \todo Paul Wayper thinks that this code should be refactored to
553 * reduce or remove the duplication between this, the mousePressEvent()
554 * and mouseReleaseEvent() methods.
556 void PianoView::mouseMoveEvent( QMouseEvent
* _me
)
558 if( m_piano
== NULL
)
563 int key_num
= getKeyFromMouse( _me
->pos() );
564 int y_diff
= _me
->pos().y() - PIANO_BASE
;
565 int velocity
= (int)( (float) y_diff
/
566 ( ( KEY_ORDER
[key_num
% KeysPerOctave
] == Piano::WhiteKey
) ?
567 PW_WHITE_KEY_HEIGHT
: PW_BLACK_KEY_HEIGHT
) *
568 (float) MidiMaxVelocity
);
569 // maybe the user moved the mouse-cursor above or under the
570 // piano-widget while holding left button so check that and
571 // correct volume if necessary
577 ( ( KEY_ORDER
[key_num
% KeysPerOctave
] == Piano::WhiteKey
) ?
578 PW_WHITE_KEY_HEIGHT
: PW_BLACK_KEY_HEIGHT
) )
580 velocity
= MidiMaxVelocity
;
583 // is the calculated key different from current key? (could be the
584 // user just moved the cursor one pixel left but on the same key)
585 if( key_num
!= m_lastKey
)
587 if( m_lastKey
!= -1 )
589 m_piano
->m_midiEvProc
->processInEvent(
590 midiEvent( MidiNoteOff
, 0, m_lastKey
, 0 ),
592 m_piano
->m_pressedKeys
[m_lastKey
] = false;
595 if( _me
->buttons() & Qt::LeftButton
)
597 if( _me
->pos().y() > PIANO_BASE
)
599 m_piano
->m_midiEvProc
->processInEvent(
600 midiEvent( MidiNoteOn
, 0, key_num
,
603 m_piano
->m_pressedKeys
[key_num
] = true;
608 m_piano
->m_instrumentTrack
->
610 setInitValue( (float) key_num
);
613 // and let the user see that he pressed a key... :)
616 else if( m_piano
->m_pressedKeys
[key_num
] == true )
618 m_piano
->m_midiEvProc
->processInEvent(
619 midiEvent( MidiKeyPressure
, 0, key_num
,
629 /*! \brief Handle a key press event on the piano display view
631 * We determine our key number from the getKeyFromKeyEvent() method,
632 * and pass the event on to the piano's handleKeyPress() method if
633 * auto-repeat is off.
635 * \param _ke the KeyEvent to handle.
637 void PianoView::keyPressEvent( QKeyEvent
* _ke
)
639 const int key_num
= getKeyFromKeyEvent( _ke
) +
640 ( DefaultOctave
- 1 ) * KeysPerOctave
;
642 if( _ke
->isAutoRepeat() == false && key_num
> -1 )
644 if( m_piano
!= NULL
)
646 m_piano
->handleKeyPress( key_num
);
659 /*! \brief Handle a key release event on the piano display view
661 * The same logic as the keyPressEvent() method.
663 * \param _ke the KeyEvent to handle.
665 void PianoView::keyReleaseEvent( QKeyEvent
* _ke
)
667 const int key_num
= getKeyFromKeyEvent( _ke
) +
668 ( DefaultOctave
- 1 ) * KeysPerOctave
;
669 if( _ke
->isAutoRepeat() == false && key_num
> -1 )
671 if( m_piano
!= NULL
)
673 m_piano
->handleKeyRelease( key_num
);
686 /*! \brief Handle the focus leaving the piano display view
688 * Turn off all notes if we lose focus.
690 * \todo Is there supposed to be a parameter given here?
692 void PianoView::focusOutEvent( QFocusEvent
* )
694 if( m_piano
== NULL
)
699 // focus just switched to another control inside the instrument track
700 // window we live in?
701 if( parentWidget()->parentWidget()->focusWidget() != this &&
702 parentWidget()->parentWidget()->focusWidget() != NULL
&&
703 !parentWidget()->parentWidget()->
704 focusWidget()->inherits( "QLineEdit" ) )
706 // then reclaim keyboard focus!
711 // if we loose focus, we HAVE to note off all running notes because
712 // we don't receive key-release-events anymore and so the notes would
714 for( int i
= 0; i
< NumKeys
; ++i
)
716 if( m_piano
->m_pressedKeys
[i
] == true )
718 m_piano
->m_midiEvProc
->processInEvent(
719 midiEvent( MidiNoteOff
, 0, i
, 0 ),
721 m_piano
->m_pressedKeys
[i
] = false;
730 /*! \brief update scrollbar range after resize
732 * After resizing we need to adjust range of scrollbar for not allowing
733 * to scroll too far to the right.
735 * \param _event resize-event object (unused)
737 void PianoView::resizeEvent( QResizeEvent
* _event
)
739 QWidget::resizeEvent( _event
);
740 m_pianoScroll
->setRange( 0, WhiteKeysPerOctave
* NumOctaves
-
741 (int) ceil( (float) width() /
742 PW_WHITE_KEY_WIDTH
) );
748 /*! \brief Convert a key number to an X coordinate in the piano display view
750 * We can immediately discard the trivial case of when the key number is
751 * less than our starting key. We then iterate through the keys from the
752 * start key to this key, adding the width of each key as we go. For
753 * black keys, and the first white key if there is no black key between
754 * two white keys, we add half a white key width; for that second white
755 * key, we add a whole width. That takes us to the boundary of a white
756 * key - subtract half a width to get to the middle.
758 * \param _key_num the keyboard key to translate
759 * \todo is this description of what the method does correct?
760 * \todo replace the final subtract with initialising x to width/2.
762 int PianoView::getKeyX( int _key_num
) const
765 if( _key_num
< m_startKey
)
767 return ( _key_num
- k
) * PW_WHITE_KEY_WIDTH
/ 2;
773 while( k
<= _key_num
)
775 if( KEY_ORDER
[k
% KeysPerOctave
] == Piano::WhiteKey
)
780 x
+= PW_WHITE_KEY_WIDTH
;
784 x
+= PW_WHITE_KEY_WIDTH
/2;
790 x
+= PW_WHITE_KEY_WIDTH
/2;
795 x
-= PW_WHITE_KEY_WIDTH
/ 2;
804 /*! \brief Paint the piano display view in response to an event
806 * This method draws the piano and the 'root note' base. It draws
807 * the base first, then all the white keys, then all the black keys.
809 * \todo Is there supposed to be a parameter given here?
811 void PianoView::paintEvent( QPaintEvent
* )
815 // set smaller font for printing number of every octave
816 p
.setFont( pointSize
<LABEL_TEXT_SIZE
>( p
.font() ) );
819 // draw blue bar above the actual keyboard (there will be the labels
821 QLinearGradient
g( 0, 0, 0, PIANO_BASE
-3 );
822 g
.setColorAt( 0, Qt::black
);
823 g
.setColorAt( 0.1, QColor( 96, 96, 96 ) );
824 g
.setColorAt( 1, Qt::black
);
825 p
.fillRect( QRect( 0, 1, width(), PIANO_BASE
-2 ), g
);
827 // draw stuff above the actual keyboard
828 p
.setPen( Qt::black
);
829 p
.drawLine( 0, 0, width(), 0 );
830 p
.drawLine( 0, PIANO_BASE
-1, width(), PIANO_BASE
-1 );
832 p
.setPen( Qt::white
);
834 const int base_key
= ( m_piano
!= NULL
) ?
835 m_piano
->m_instrumentTrack
->baseNoteModel()->value() : 0;
836 g
.setColorAt( 0, QColor( 0, 96, 0 ) );
837 g
.setColorAt( 0.1, QColor( 64, 255, 64 ) );
838 g
.setColorAt( 1, QColor( 0, 96, 0 ) );
839 if( KEY_ORDER
[base_key
% KeysPerOctave
] == Piano::WhiteKey
)
841 p
.fillRect( QRect( getKeyX( base_key
), 1, PW_WHITE_KEY_WIDTH
-1,
846 p
.fillRect( QRect( getKeyX( base_key
) + 1, 1,
847 PW_BLACK_KEY_WIDTH
- 1, PIANO_BASE
- 2 ), g
);
851 int cur_key
= m_startKey
;
853 // draw all white keys...
854 for( int x
= 0; x
< width(); )
856 while( KEY_ORDER
[cur_key
%KeysPerOctave
] != Piano::WhiteKey
)
861 // draw pressed or not pressed key, depending on state of
863 if( m_piano
&& m_piano
->m_pressedKeys
[cur_key
] == true )
865 p
.drawPixmap( x
, PIANO_BASE
, *s_whiteKeyPressedPm
);
869 p
.drawPixmap( x
, PIANO_BASE
, *s_whiteKeyPm
);
872 x
+= PW_WHITE_KEY_WIDTH
;
874 if( (Keys
) (cur_key
%KeysPerOctave
) == Key_C
)
876 // label key of note C with "C" and number of current
878 p
.drawText( x
- PW_WHITE_KEY_WIDTH
, LABEL_TEXT_SIZE
+ 2,
879 QString( "C" ) + QString::number(
880 cur_key
/ KeysPerOctave
, 10 ) );
886 // reset all values, because now we're going to draw all black keys
887 cur_key
= m_startKey
;
890 int s_key
= m_startKey
;
892 KEY_ORDER
[(Keys
)(--s_key
) % KeysPerOctave
] == Piano::BlackKey
)
894 if( m_piano
&& m_piano
->m_pressedKeys
[s_key
] == true )
896 p
.drawPixmap( 0 - PW_WHITE_KEY_WIDTH
/ 2, PIANO_BASE
,
897 *s_blackKeyPressedPm
);
901 p
.drawPixmap( 0 - PW_WHITE_KEY_WIDTH
/ 2, PIANO_BASE
,
906 // now draw all black keys...
907 for( int x
= 0; x
< width(); )
909 if( KEY_ORDER
[cur_key
%KeysPerOctave
] == Piano::BlackKey
)
911 // draw pressed or not pressed key, depending on
912 // state of current key
913 if( m_piano
&& m_piano
->m_pressedKeys
[cur_key
] == true )
915 p
.drawPixmap( x
+ PW_WHITE_KEY_WIDTH
/ 2,
917 *s_blackKeyPressedPm
);
921 p
.drawPixmap( x
+ PW_WHITE_KEY_WIDTH
/ 2,
922 PIANO_BASE
, *s_blackKeyPm
);
924 x
+= PW_WHITE_KEY_WIDTH
;
929 // simple workaround for increasing x if there were two
930 // white keys (e.g. between E and F)
934 x
+= PW_WHITE_KEY_WIDTH
;
944 #include "moc_PianoView.cxx"