19 #include <QApplication>
20 #include <QGraphicsSceneMouseEvent>
40 class PianoScene::PianoScenePrivate
57 m_keyboardEnabled( true ),
58 m_mouseEnabled( true ),
59 m_touchEnabled( true ),
60 m_mousePressed( false ),
63 m_velocityTint( true ),
65 m_keybdMap( nullptr ),
66 m_showColorScale( false ),
68 m_backgroundPalette(PianoPalette(
PAL_KEYS)),
69 m_foregroundPalette(PianoPalette(
PAL_FONT))
82 bool m_keyboardEnabled;
89 PianoHandler *m_handler;
91 QHash<int, PianoKey *> m_keys;
92 QMap<int, KeyLabel *> m_labels;
93 QStringList m_noteNames;
94 QStringList m_names_s;
95 QStringList m_names_f;
96 bool m_showColorScale;
97 PianoPalette m_hilightPalette;
98 PianoPalette m_backgroundPalette;
99 PianoPalette m_foregroundPalette;
102 const int KEYWIDTH = 180;
103 const int KEYHEIGHT = 720;
105 static qreal sceneWidth(
int keys) {
106 return KEYWIDTH * qCeil( keys * 7.0 / 12.0 );
120 const QColor& keyPressedColor,
122 :
QGraphicsScene( QRectF(0, 0, sceneWidth(numKeys), KEYHEIGHT), parent ),
123 d(new PianoScenePrivate(baseOctave, numKeys, startKey))
125 if (keyPressedColor.isValid()) {
130 if (view !=
nullptr) {
131 setFont(view->font());
133 int upperLimit = d->m_numKeys + d->m_startKey;
134 int adj = d->m_startKey % 12;
136 for(
int i = d->m_startKey; i < upperLimit; ++i)
139 PianoKey* key =
nullptr;
140 KeyLabel* lbl =
nullptr;
141 int ocs = i / 12 * 7;
145 x = (ocs + qFloor((j-adj) / 2.0)) * KEYWIDTH;
146 key =
new PianoKey( QRectF(x, 0, KEYWIDTH, KEYHEIGHT),
false, i );
147 lbl =
new KeyLabel(key);
148 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(0));
150 x = (ocs + qFloor((j-adj) / 2.0)) * KEYWIDTH + KEYWIDTH * 0.6 + 1;
151 key =
new PianoKey( QRectF( x, 0, KEYWIDTH * 0.8 - 1, KEYHEIGHT * 0.6 ),
true, i );
153 lbl =
new KeyLabel(key);
154 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(1));
157 lbl->setFont(font());
158 key->setAcceptTouchEvents(
true);
159 key->setPressedBrush(hilightBrush);
160 d->m_keys.insert(i, key);
161 d->m_labels.insert(i, lbl);
179 return {
static_cast<int>(sceneWidth(d->m_numKeys)), KEYHEIGHT};
197 return d->m_keybdMap;
222 d->m_handler = handler;
231 return d->m_hilightPalette;
240 key->setPressed(
true);
241 int n = key->getNote() + d->m_baseOctave*12 + d->m_transpose;
242 QString s = QString(
"#%1 (%2)").arg(n).arg(
noteName(key));
244 KeyLabel* lbl =
dynamic_cast<KeyLabel*
>(key->childItems().constFirst());
245 if (lbl !=
nullptr) {
246 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(key->isBlack() ? 3 : 2));
248 lbl->setVisible(
true);
261 if (d->m_velocityTint && vel >= 0 && color.isValid() ) {
262 QBrush hilightBrush(color.lighter(200 - vel));
263 key->setPressedBrush(hilightBrush);
287 key->setPressed(
false);
289 KeyLabel* lbl =
dynamic_cast<KeyLabel*
>(key->childItems().constFirst());
290 if (lbl !=
nullptr) {
293 lbl->setVisible(
false);
306 int n = note - d->m_baseOctave*12 - d->m_transpose;
307 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n) && color.isValid())
308 showKeyOn(d->m_keys.value(n), color, vel);
318 int n = note - d->m_baseOctave*12 - d->m_transpose;
319 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n)) {
331 int n = note - d->m_baseOctave*12 - d->m_transpose;
332 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n)) {
353 int n = d->m_baseOctave*12 + note + d->m_transpose;
354 if ((n >= d->m_minNote) && (n <= d->m_maxNote)) {
355 if (d->m_handler !=
nullptr) {
356 d->m_handler->noteOn(n, vel);
372 int n = d->m_baseOctave*12 + note + d->m_transpose;
373 if ((n >= d->m_minNote) && (n <= d->m_maxNote)) {
374 if (d->m_handler !=
nullptr) {
375 d->m_handler->noteOff(n, vel);
391 switch (d->m_hilightPalette.paletteId()) {
393 c = d->m_hilightPalette.getColor(0);
396 c = d->m_hilightPalette.getColor(key->getType());
399 c = d->m_hilightPalette.getColor(d->m_channel);
405 if (d->m_velocityTint) {
406 QBrush h(c.lighter(200 - vel));
407 key->setPressedBrush(h);
409 key->setPressedBrush(c);
441 int vel = d->m_velocity * pressure;
453 int vel = d->m_velocity * pressure;
464 if (d->m_keys.contains(note))
465 keyOn(d->m_keys.value(note));
476 if (d->m_keys.contains(note))
477 keyOff(d->m_keys.value(note));
498 PianoKey* key =
nullptr;
499 QList<QGraphicsItem *> ptitems = this->items(p, Qt::IntersectsItemShape, Qt::DescendingOrder);
500 foreach(QGraphicsItem *itm, ptitems) {
501 key =
dynamic_cast<PianoKey*
>(itm);
514 if (d->m_mouseEnabled) {
515 if (d->m_mousePressed) {
517 PianoKey* lastkey =
getKeyForPos(mouseEvent->lastScenePos());
518 if ((lastkey !=
nullptr) && (lastkey != key) && lastkey->isPressed()) {
521 if ((key !=
nullptr) && !key->isPressed()) {
524 mouseEvent->accept();
536 if (d->m_mouseEnabled) {
538 if (key !=
nullptr && !key->isPressed()) {
540 d->m_mousePressed =
true;
541 mouseEvent->accept();
553 if (d->m_mouseEnabled) {
554 d->m_mousePressed =
false;
556 if (key !=
nullptr && key->isPressed()) {
558 mouseEvent->accept();
571 if (d->m_keybdMap !=
nullptr) {
572 KeyboardMap::ConstIterator it = d->m_keybdMap->constFind(key);
573 if ((it != d->m_keybdMap->constEnd()) && (it.key() == key)) {
574 int note = it.value();
589 if (d->m_keys.contains(note))
590 return d->m_keys.value(note);
600 if ( d->m_keyboardEnabled) {
601 if ( !d->m_rawkbd && !keyEvent->isAutoRepeat() ) {
618 if (d->m_keyboardEnabled) {
619 if ( !d->m_rawkbd && !keyEvent->isAutoRepeat() ) {
637 switch(
event->type()) {
638 case QEvent::TouchBegin:
639 case QEvent::TouchEnd:
640 case QEvent::TouchUpdate:
642 QTouchEvent *touchEvent =
static_cast<QTouchEvent*
>(
event);
643 if (d->m_touchEnabled && touchEvent->device()->type() == QTouchDevice::DeviceType::TouchScreen) {
644 QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
645 foreach(
const QTouchEvent::TouchPoint& touchPoint, touchPoints) {
646 switch (touchPoint.state()) {
648 case Qt::TouchPointStationary:
650 case Qt::TouchPointReleased: {
652 if (key !=
nullptr && key->isPressed()) {
653 keyOff(key, touchPoint.pressure());
657 case Qt::TouchPointPressed: {
659 if (key !=
nullptr && !key->isPressed()) {
660 keyOn(key, touchPoint.pressure());
661 key->ensureVisible();
665 case Qt::TouchPointMoved: {
667 PianoKey* lastkey =
getKeyForPos(touchPoint.lastScenePos());
668 if ((lastkey !=
nullptr) && (lastkey != key) && lastkey->isPressed()) {
669 keyOff(lastkey, touchPoint.pressure());
671 if ((key !=
nullptr) && !key->isPressed()) {
672 keyOn(key, touchPoint.pressure());
691 return QGraphicsScene::event(
event);
699 foreach(PianoKey* key, d->m_keys) {
700 key->setPressed(
false);
712 if (color.isValid()) {
714 d->m_hilightPalette.setColor(0, color);
715 QBrush hilightBrush(color);
716 for (PianoKey* key : qAsConst(d->m_keys)) {
717 key->setPressedBrush(hilightBrush);
727 d->m_hilightPalette.resetColors();
729 for (PianoKey* key : qAsConst(d->m_keys)) {
730 key->setPressedBrush(hilightBrush);
748 for (PianoKey* key : qAsConst(d->m_keys)) {
749 int n = d->m_baseOctave*12 + key->getNote() + d->m_transpose;
750 bool b = !(n > d->m_maxNote) && !(n < d->m_minNote);
761 if (d->m_minNote != note) {
782 if (d->m_maxNote != note) {
794 return d->m_transpose;
803 if (d->m_baseOctave != base) {
804 d->m_baseOctave = base;
825 return d->m_startKey;
835 return (note + d->m_transpose + 12) % 12 == 0;
845 Q_ASSERT(key !=
nullptr);
846 int note = key->getNote();
847 int num = (note + d->m_transpose + 12) % 12;
848 int adj = ((note + d->m_transpose < 0) ? 2 : 1) - d->m_octave + 1;
849 int oct = d->m_baseOctave + ((note + d->m_transpose) / 12) - adj;
850 if (d->m_noteNames.isEmpty()) {
852 if (!d->m_names_f.isEmpty() && !d->m_names_s.isEmpty()) {
853 switch(d->m_alterations) {
855 name = d->m_names_f.value(num);
858 name = d->m_names_s.value(num);
861 if (key->isBlack()) {
864 name = d->m_names_s.value(num);
873 return QString(
"%1%2").arg(name).arg(oct);
876 if (d->m_noteNames.length() == 128) {
877 int n = d->m_baseOctave*12 + note + d->m_transpose;
879 if (n >= 0 && n < d->m_noteNames.length()) {
880 return d->m_noteNames.value(n);
882 }
else if (d->m_noteNames.length() >= 12) {
884 return d->m_noteNames.value(num);
886 return QString(
"%1%2").arg(d->m_noteNames.value(num)).arg(oct);
898 for (KeyLabel* lbl : qAsConst(d->m_labels)) {
899 PianoKey* key =
dynamic_cast<PianoKey*
>(lbl->parentItem());
900 if (key !=
nullptr) {
901 lbl->setVisible(
false);
902 lbl->setFont(font());
903 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(key->isBlack() ? 1 : 0));
904 lbl->setOrientation(d->m_orientation);
907 lbl->setVisible((d->m_showLabels ==
ShowAlways) ||
918 for (PianoKey* key : qAsConst(d->m_keys)) {
919 if (d->m_showColorScale && (d->m_backgroundPalette.paletteId() ==
PAL_SCALE)) {
920 int degree = key->getNote() % 12;
921 key->setBrush(d->m_backgroundPalette.getColor(degree));
923 key->setBrush(d->m_backgroundPalette.getColor(key->isBlack() ? 1 : 0));
925 key->setPressed(
false);
937 if (d->m_showLabels != show) {
938 d->m_showLabels = show;
950 return d->m_alterations;
960 if (d->m_alterations != use) {
961 d->m_alterations = use;
981 if (d->m_orientation != orientation) {
982 d->m_orientation = orientation;
987 bool PianoScene::isKeyboardEnabled()
const
989 return d->m_keyboardEnabled;
994 if (d->m_octave != octave) {
995 d->m_octave = octave;
1002 return d->m_orientation;
1011 if (d->m_transpose != transpose && transpose > -12 && transpose < 12) {
1012 d->m_transpose = transpose;
1025 return d->m_showLabels;
1034 if (d->m_rawkbd != b) {
1045 return d->m_noteNames;
1054 return d->m_names_s;
1063 return d->m_velocity;
1072 d->m_velocity = velocity;
1082 return d->m_channel;
1092 d->m_channel = channel;
1102 d->m_noteNames = names;
1112 d->m_noteNames.clear();
1122 if (enable != d->m_keyboardEnabled) {
1123 d->m_keyboardEnabled = enable;
1133 return d->m_mouseEnabled;
1142 if (enable != d->m_mouseEnabled) {
1143 d->m_mouseEnabled = enable;
1153 return d->m_touchEnabled;
1162 if (enable != d->m_touchEnabled) {
1163 d->m_touchEnabled = enable;
1173 return d->m_velocityTint;
1182 d->m_velocityTint = enable;
1190 d->m_names_s = QStringList{
1203 d->m_names_f = QStringList{
1225 if (d->m_showColorScale != show) {
1226 d->m_showColorScale = show;
1238 return d->m_hilightPalette.getColor(0);
1247 if (d->m_hilightPalette != p) {
1248 d->m_hilightPalette = p;
1260 return d->m_backgroundPalette;
1269 if (d->m_backgroundPalette != p) {
1270 d->m_backgroundPalette = p;
1282 return d->m_foregroundPalette;
1291 if (d->m_foregroundPalette != p) {
1292 d->m_foregroundPalette = p;
1304 return d->m_showColorScale;
The QEvent class is the base class of all event classes.
The QGraphicsScene class provides a surface for managing a large number of 2D graphical items.
The QObject class is the base class of all Qt objects.
PianoScene class declaration.