19 #include <QApplication>
20 #include <QDataStream>
22 #include <QGraphicsSceneMouseEvent>
44 class PianoScene::PianoScenePrivate
61 m_keyboardEnabled( true ),
62 m_mouseEnabled( true ),
63 m_touchEnabled( true ),
64 m_mousePressed( false ),
67 m_velocityTint( true ),
69 m_keybdMap( nullptr ),
70 m_showColorScale( false ),
72 m_backgroundPalette(PianoPalette(
PAL_KEYS)),
73 m_foregroundPalette(PianoPalette(
PAL_FONT)),
77 void saveData(QByteArray& buffer)
79 QDataStream ds(&buffer, QIODevice::WriteOnly);
88 ds << m_keyboardEnabled;
98 ds << m_showColorScale;
99 ds << m_hilightPalette;
100 ds << m_backgroundPalette;
101 ds << m_foregroundPalette;
107 void loadData(QByteArray& buffer)
110 QDataStream ds(&buffer, QIODevice::ReadOnly);
119 ds >> m_keyboardEnabled;
120 ds >> m_mouseEnabled;
121 ds >> m_touchEnabled;
122 ds >> m_mousePressed;
125 ds >> m_velocityTint;
129 ds >> m_showColorScale;
130 ds >> m_hilightPalette;
131 ds >> m_backgroundPalette;
132 ds >> m_foregroundPalette;
149 bool m_keyboardEnabled;
156 PianoHandler *m_handler;
158 QHash<int, PianoKey *> m_keys;
159 QMap<int, KeyLabel *> m_labels;
160 QStringList m_noteNames;
161 QStringList m_names_s;
162 QStringList m_names_f;
163 bool m_showColorScale;
164 PianoPalette m_hilightPalette;
165 PianoPalette m_backgroundPalette;
166 PianoPalette m_foregroundPalette;
171 const int KEYWIDTH = 180;
172 const int KEYHEIGHT = 720;
174 static qreal sceneWidth(
int keys) {
175 return KEYWIDTH * qCeil( keys * 7.0 / 12.0 );
189 const QColor& keyPressedColor,
191 :
QGraphicsScene( QRectF(0, 0, sceneWidth(numKeys), KEYHEIGHT), parent ),
192 d(new PianoScenePrivate(baseOctave, numKeys, startKey))
194 if (keyPressedColor.isValid()) {
199 if (view !=
nullptr) {
200 setFont(view->font());
202 int upperLimit = d->m_numKeys + d->m_startKey;
203 int adj = d->m_startKey % 12;
205 for(
int i = d->m_startKey; i < upperLimit; ++i)
208 PianoKey* key =
nullptr;
209 KeyLabel* lbl =
nullptr;
210 int ocs = i / 12 * 7;
214 x = (ocs + qFloor((j-adj) / 2.0)) * KEYWIDTH;
215 key =
new PianoKey( QRectF(x, 0, KEYWIDTH, KEYHEIGHT),
false, i );
216 lbl =
new KeyLabel(key);
217 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(0));
219 x = (ocs + qFloor((j-adj) / 2.0)) * KEYWIDTH + KEYWIDTH * 0.6 + 1;
220 key =
new PianoKey( QRectF( x, 0, KEYWIDTH * 0.8 - 1, KEYHEIGHT * 0.6 ),
true, i );
222 lbl =
new KeyLabel(key);
223 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(1));
226 lbl->setFont(font());
227 key->setAcceptTouchEvents(
true);
228 key->setPressedBrush(hilightBrush);
229 d->m_keys.insert(i, key);
230 d->m_labels.insert(i, lbl);
248 return {
static_cast<int>(sceneWidth(d->m_numKeys)), KEYHEIGHT};
266 return d->m_keybdMap;
291 d->m_handler = handler;
300 return d->m_hilightPalette;
309 key->setPressed(
true);
310 int n = key->getNote() + d->m_baseOctave*12 + d->m_transpose;
311 QString s = QString(
"#%1 (%2)").arg(n).arg(
noteName(key));
313 KeyLabel* lbl =
dynamic_cast<KeyLabel*
>(key->childItems().constFirst());
314 if (lbl !=
nullptr) {
315 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(key->isBlack() ? 3 : 2));
317 lbl->setVisible(
true);
331 if (d->m_velocityTint && (vel >= 0) && (vel < 128) && color.isValid() ) {
332 QBrush hilightBrush(color.lighter(200 - vel));
333 key->setPressedBrush(hilightBrush);
357 key->setPressed(
false);
359 KeyLabel* lbl =
dynamic_cast<KeyLabel*
>(key->childItems().constFirst());
360 if (lbl !=
nullptr) {
363 lbl->setVisible(
false);
377 int n = note - d->m_baseOctave*12 - d->m_transpose;
378 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n) && color.isValid())
379 showKeyOn(d->m_keys.value(n), color, vel);
390 int n = note - d->m_baseOctave*12 - d->m_transpose;
391 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n)) {
403 int n = note - d->m_baseOctave*12 - d->m_transpose;
404 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n)) {
425 int n = d->m_baseOctave*12 + note + d->m_transpose;
426 if ((n >= d->m_minNote) && (n <= d->m_maxNote)) {
427 if (d->m_handler !=
nullptr) {
428 d->m_handler->noteOn(n, vel);
444 int n = d->m_baseOctave*12 + note + d->m_transpose;
445 if ((n >= d->m_minNote) && (n <= d->m_maxNote)) {
446 if (d->m_handler !=
nullptr) {
447 d->m_handler->noteOff(n, vel);
464 switch (d->m_hilightPalette.paletteId()) {
466 c = d->m_hilightPalette.getColor(0);
469 c = d->m_hilightPalette.getColor(key->getType());
472 c = d->m_hilightPalette.getColor(d->m_channel);
475 c = d->m_hilightPalette.getColor(key->getDegree());
481 if (d->m_velocityTint && (vel >= 0) && (vel < 128)) {
482 QBrush h(c.lighter(200 - vel));
483 key->setPressedBrush(h);
485 key->setPressedBrush(c);
517 int vel = d->m_velocity * pressure;
529 int vel = d->m_velocity * pressure;
540 if (d->m_keys.contains(note))
541 keyOn(d->m_keys.value(note));
552 if (d->m_keys.contains(note))
553 keyOff(d->m_keys.value(note));
574 PianoKey* key =
nullptr;
575 QList<QGraphicsItem *> ptitems = this->items(p, Qt::IntersectsItemShape, Qt::DescendingOrder);
576 foreach(QGraphicsItem *itm, ptitems) {
577 key =
dynamic_cast<PianoKey*
>(itm);
590 if (d->m_mouseEnabled) {
591 if (d->m_mousePressed) {
593 PianoKey* lastkey =
getKeyForPos(mouseEvent->lastScenePos());
594 if ((lastkey !=
nullptr) && (lastkey != key) && lastkey->isPressed()) {
597 if ((key !=
nullptr) && !key->isPressed()) {
600 mouseEvent->accept();
612 if (d->m_mouseEnabled) {
614 if (key !=
nullptr && !key->isPressed()) {
616 d->m_mousePressed =
true;
617 mouseEvent->accept();
629 if (d->m_mouseEnabled) {
630 d->m_mousePressed =
false;
632 if (key !=
nullptr && key->isPressed()) {
634 mouseEvent->accept();
647 if (d->m_keybdMap !=
nullptr) {
648 KeyboardMap::ConstIterator it = d->m_keybdMap->constFind(key);
649 if ((it != d->m_keybdMap->constEnd()) && (it.key() == key)) {
650 int note = it.value();
665 if (d->m_keys.contains(note))
666 return d->m_keys.value(note);
676 if ( d->m_keyboardEnabled) {
677 if ( !d->m_rawkbd && !keyEvent->isAutoRepeat() ) {
694 if (d->m_keyboardEnabled) {
695 if ( !d->m_rawkbd && !keyEvent->isAutoRepeat() ) {
713 switch(
event->type()) {
714 case QEvent::TouchBegin:
715 case QEvent::TouchEnd:
716 case QEvent::TouchUpdate:
718 QTouchEvent *touchEvent =
static_cast<QTouchEvent*
>(
event);
719 if (d->m_touchEnabled && touchEvent->device()->type() == QTouchDevice::DeviceType::TouchScreen) {
720 QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
721 foreach(
const QTouchEvent::TouchPoint& touchPoint, touchPoints) {
722 switch (touchPoint.state()) {
724 case Qt::TouchPointStationary:
726 case Qt::TouchPointReleased: {
728 if (key !=
nullptr && key->isPressed()) {
729 keyOff(key, touchPoint.pressure());
733 case Qt::TouchPointPressed: {
735 if (key !=
nullptr && !key->isPressed()) {
736 keyOn(key, touchPoint.pressure());
737 key->ensureVisible();
741 case Qt::TouchPointMoved: {
743 PianoKey* lastkey =
getKeyForPos(touchPoint.lastScenePos());
744 if ((lastkey !=
nullptr) && (lastkey != key) && lastkey->isPressed()) {
745 keyOff(lastkey, touchPoint.pressure());
747 if ((key !=
nullptr) && !key->isPressed()) {
748 keyOn(key, touchPoint.pressure());
767 return QGraphicsScene::event(
event);
775 foreach(PianoKey* key, d->m_keys) {
776 key->setPressed(
false);
788 if (color.isValid()) {
790 d->m_hilightPalette.setColor(0, color);
791 QBrush hilightBrush(color);
792 for (PianoKey* key : qAsConst(d->m_keys)) {
793 key->setPressedBrush(hilightBrush);
803 d->m_hilightPalette.resetColors();
805 for (PianoKey* key : qAsConst(d->m_keys)) {
806 key->setPressedBrush(hilightBrush);
824 for (PianoKey* key : qAsConst(d->m_keys)) {
825 int n = d->m_baseOctave*12 + key->getNote() + d->m_transpose;
826 bool b = !(n > d->m_maxNote) && !(n < d->m_minNote);
837 if (d->m_minNote != note) {
858 if (d->m_maxNote != note) {
870 return d->m_transpose;
879 if (d->m_baseOctave != base) {
880 d->m_baseOctave = base;
901 return d->m_startKey;
911 return (note + d->m_transpose + 12) % 12 == 0;
921 Q_ASSERT(key !=
nullptr);
922 int note = key->getNote();
923 int num = (note + d->m_transpose + 12) % 12;
924 int adj = ((note + d->m_transpose < 0) ? 2 : 1) - d->m_octave + 1;
925 int oct = d->m_baseOctave + ((note + d->m_transpose) / 12) - adj;
926 if (d->m_noteNames.isEmpty()) {
928 if (!d->m_names_f.isEmpty() && !d->m_names_s.isEmpty()) {
929 switch(d->m_alterations) {
931 name = d->m_names_f.value(num);
934 name = d->m_names_s.value(num);
937 if (key->isBlack()) {
940 name = d->m_names_s.value(num);
949 return QString(
"%1%2").arg(name).arg(oct);
952 if (d->m_noteNames.length() == 128) {
953 int n = d->m_baseOctave*12 + note + d->m_transpose;
955 if (n >= 0 && n < d->m_noteNames.length()) {
956 return d->m_noteNames.value(n);
958 }
else if (d->m_noteNames.length() >= 12) {
960 return d->m_noteNames.value(num);
962 return QString(
"%1%2").arg(d->m_noteNames.value(num)).arg(oct);
974 for (KeyLabel* lbl : qAsConst(d->m_labels)) {
975 PianoKey* key =
dynamic_cast<PianoKey*
>(lbl->parentItem());
976 if (key !=
nullptr) {
977 lbl->setVisible(
false);
978 lbl->setFont(font());
979 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(key->isBlack() ? 1 : 0));
980 lbl->setOrientation(d->m_orientation);
983 lbl->setVisible((d->m_showLabels ==
ShowAlways) ||
994 for (PianoKey* key : qAsConst(d->m_keys)) {
995 if (d->m_showColorScale && (d->m_backgroundPalette.paletteId() ==
PAL_SCALE)) {
996 int degree = key->getNote() % 12;
997 key->setBrush(d->m_backgroundPalette.getColor(degree));
999 key->setBrush(d->m_backgroundPalette.getColor(key->isBlack() ? 1 : 0));
1001 key->setPressed(
false);
1013 if (d->m_showLabels != show) {
1014 d->m_showLabels = show;
1026 return d->m_alterations;
1036 if (d->m_alterations != use) {
1037 d->m_alterations = use;
1057 if (d->m_orientation != orientation) {
1058 d->m_orientation = orientation;
1063 bool PianoScene::isKeyboardEnabled()
const
1065 return d->m_keyboardEnabled;
1070 if (d->m_octave != octave) {
1071 d->m_octave = octave;
1078 return d->m_orientation;
1087 if (d->m_transpose != transpose && transpose > -12 && transpose < 12) {
1088 d->m_transpose = transpose;
1101 return d->m_showLabels;
1110 if (d->m_rawkbd != b) {
1121 return d->m_noteNames;
1130 return d->m_names_s;
1139 return d->m_velocity;
1148 d->m_velocity = velocity;
1158 return d->m_channel;
1168 d->m_channel = channel;
1178 d->m_noteNames = names;
1188 d->m_noteNames.clear();
1198 if (enable != d->m_keyboardEnabled) {
1199 d->m_keyboardEnabled = enable;
1209 return d->m_mouseEnabled;
1218 if (enable != d->m_mouseEnabled) {
1219 d->m_mouseEnabled = enable;
1229 return d->m_touchEnabled;
1238 if (enable != d->m_touchEnabled) {
1239 d->m_touchEnabled = enable;
1249 return d->m_velocityTint;
1259 d->m_velocityTint = enable;
1267 d->m_names_s = QStringList{
1280 d->m_names_f = QStringList{
1302 if (d->m_showColorScale != show) {
1303 d->m_showColorScale = show;
1315 return d->m_hilightPalette.getColor(0);
1324 if (d->m_hilightPalette != p) {
1325 d->m_hilightPalette = p;
1337 return d->m_backgroundPalette;
1346 if (d->m_backgroundPalette != p) {
1347 d->m_backgroundPalette = p;
1359 return d->m_foregroundPalette;
1368 if (d->m_foregroundPalette != p) {
1369 d->m_foregroundPalette = p;
1381 return d->m_showColorScale;
1384 void PianoScene::setKeyPicture(
const bool natural,
const QPixmap &pix)
1386 d->m_keyPix[int(natural)] = pix;
1387 for (PianoKey* key : qAsConst(d->m_keys)) {
1388 if (key->isBlack() == !natural) {
1389 key->setPixmap(pix);
1394 QPixmap PianoScene::getKeyPicture(
const bool natural)
1396 return d->m_keyPix[int(natural)];
1399 void PianoScene::setUseKeyPictures(
const bool enable)
1401 d->m_useKeyPix = enable;
1402 for (PianoKey* key : qAsConst(d->m_keys)) {
1403 key->setUsePixmap(enable);
1407 bool PianoScene::getUseKeyPictures()
const
1409 return d->m_useKeyPix;
1412 void PianoScene::saveData(QByteArray &ba)
1417 void PianoScene::loadData(QByteArray &ba)
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.