20 #include <QApplication> 21 #include <QDataStream> 23 #include <QGraphicsSceneMouseEvent> 28 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) 29 #include <QTouchDevice> 31 #include <QInputDevice> 49 class PianoScene::PianoScenePrivate
66 m_keyboardEnabled( true ),
67 m_mouseEnabled( true ),
68 m_touchEnabled( true ),
69 m_mousePressed( false ),
72 m_velocityTint( true ),
74 m_keybdMap( nullptr ),
75 m_showColorScale( false ),
77 m_backgroundPalette(PianoPalette(
PAL_KEYS)),
78 m_foregroundPalette(PianoPalette(
PAL_FONT)),
80 m_usingNativeFilter( false )
83 void saveData(QByteArray& buffer)
85 QDataStream ds(&buffer, QIODevice::WriteOnly);
94 ds << m_keyboardEnabled;
100 ds << m_velocityTint;
104 ds << m_showColorScale;
105 ds << m_hilightPalette;
106 ds << m_backgroundPalette;
107 ds << m_foregroundPalette;
111 ds << m_usingNativeFilter;
114 void loadData(QByteArray& buffer)
117 QDataStream ds(&buffer, QIODevice::ReadOnly);
126 ds >> m_keyboardEnabled;
127 ds >> m_mouseEnabled;
128 ds >> m_touchEnabled;
129 ds >> m_mousePressed;
132 ds >> m_velocityTint;
136 ds >> m_showColorScale;
137 ds >> m_hilightPalette;
138 ds >> m_backgroundPalette;
139 ds >> m_foregroundPalette;
143 ds >> m_usingNativeFilter;
157 bool m_keyboardEnabled;
164 PianoHandler *m_handler;
166 QHash<int, PianoKey *> m_keys;
167 QMap<int, KeyLabel *> m_labels;
168 QStringList m_noteNames;
169 QStringList m_names_s;
170 QStringList m_names_f;
171 bool m_showColorScale;
172 PianoPalette m_hilightPalette;
173 PianoPalette m_backgroundPalette;
174 PianoPalette m_foregroundPalette;
177 bool m_usingNativeFilter;
180 QMap<int, PianoKey *> m_touched;
183 const int KEYWIDTH = 180;
184 const int KEYHEIGHT = 720;
186 static qreal sceneWidth(
int keys) {
187 return KEYWIDTH * qCeil( keys * 7.0 / 12.0 );
201 const QColor& keyPressedColor,
203 :
QGraphicsScene( QRectF(0, 0, sceneWidth(numKeys), KEYHEIGHT), parent ),
204 d(new PianoScenePrivate(baseOctave, numKeys, startKey))
206 if (keyPressedColor.isValid()) {
210 d->m_view =
dynamic_cast<PianoKeybd*
>(parent);
211 if (d->m_view !=
nullptr) {
212 setFont(d->m_view->font());
214 int upperLimit = d->m_numKeys + d->m_startKey;
215 int adj = d->m_startKey % 12;
217 for(
int i = d->m_startKey; i < upperLimit; ++i)
220 PianoKey* key =
nullptr;
221 KeyLabel* lbl =
nullptr;
222 int ocs = i / 12 * 7;
226 x = (ocs + qFloor((j-adj) / 2.0)) * KEYWIDTH;
227 key =
new PianoKey( QRectF(x, 0, KEYWIDTH, KEYHEIGHT),
false, i );
228 lbl =
new KeyLabel(key);
229 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(0));
231 x = (ocs + qFloor((j-adj) / 2.0)) * KEYWIDTH + KEYWIDTH * 0.6 + 1;
232 key =
new PianoKey( QRectF( x, 0, KEYWIDTH * 0.8 - 1, KEYHEIGHT * 0.6 ),
true, i );
234 lbl =
new KeyLabel(key);
235 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(1));
238 lbl->setFont(font());
239 key->setAcceptTouchEvents(
true);
240 key->setPressedBrush(hilightBrush);
241 d->m_keys.insert(i, key);
242 d->m_labels.insert(i, lbl);
260 return {
static_cast<int>(sceneWidth(d->m_numKeys)), KEYHEIGHT};
278 return d->m_keybdMap;
303 d->m_handler = handler;
312 return d->m_hilightPalette;
321 key->setPressed(
true);
322 int n = key->getNote() + d->m_baseOctave*12 + d->m_transpose;
323 QString s = QString(
"#%1 (%2)").arg(n).arg(
noteName(key));
325 KeyLabel* lbl =
dynamic_cast<KeyLabel*
>(key->childItems().constFirst());
326 if (lbl !=
nullptr) {
327 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(key->isBlack() ? 3 : 2));
329 lbl->setVisible(
true);
343 if (d->m_velocityTint && (vel >= 0) && (vel < 128) && color.isValid() ) {
344 QBrush hilightBrush(color.lighter(200 - vel));
345 key->setPressedBrush(hilightBrush);
346 }
else if (color.isValid()) {
347 key->setPressedBrush(color);
371 key->setPressed(
false);
373 KeyLabel* lbl =
dynamic_cast<KeyLabel*
>(key->childItems().constFirst());
374 if (lbl !=
nullptr) {
377 lbl->setVisible(
false);
391 int n = note - d->m_baseOctave*12 - d->m_transpose;
392 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n) && color.isValid())
393 showKeyOn(d->m_keys.value(n), color, vel);
404 int n = note - d->m_baseOctave*12 - d->m_transpose;
405 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n)) {
417 int n = note - d->m_baseOctave*12 - d->m_transpose;
418 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n)) {
439 int n = d->m_baseOctave*12 + note + d->m_transpose;
440 if ((n >= d->m_minNote) && (n <= d->m_maxNote)) {
441 if (d->m_handler !=
nullptr) {
442 d->m_handler->noteOn(n, vel);
458 int n = d->m_baseOctave*12 + note + d->m_transpose;
459 if ((n >= d->m_minNote) && (n <= d->m_maxNote)) {
460 if (d->m_handler !=
nullptr) {
461 d->m_handler->noteOff(n, vel);
478 switch (d->m_hilightPalette.paletteId()) {
480 c = d->m_hilightPalette.getColor(0);
483 c = d->m_hilightPalette.getColor(key->getType());
486 c = d->m_hilightPalette.getColor(d->m_channel);
489 c = d->m_hilightPalette.getColor(key->getDegree());
495 if (d->m_velocityTint && (vel >= 0) && (vel < 128)) {
496 QBrush h(c.lighter(200 - vel));
497 key->setPressedBrush(h);
499 key->setPressedBrush(c);
531 int vel = d->m_velocity * pressure;
543 int vel = d->m_velocity * pressure;
554 if (d->m_keys.contains(note))
555 keyOn(d->m_keys.value(note));
566 if (d->m_keys.contains(note))
567 keyOff(d->m_keys.value(note));
588 PianoKey* key =
nullptr;
589 QList<QGraphicsItem *> ptitems = this->items(p, Qt::IntersectsItemShape, Qt::DescendingOrder);
590 foreach(QGraphicsItem *itm, ptitems) {
591 key =
dynamic_cast<PianoKey*
>(itm);
604 if (d->m_mouseEnabled && (mouseEvent->source() == Qt::MouseEventNotSynthesized)) {
605 if (d->m_mousePressed) {
607 PianoKey* lastkey =
getKeyForPos(mouseEvent->lastScenePos());
608 if ((lastkey !=
nullptr) && (lastkey != key) && lastkey->isPressed()) {
611 if ((key !=
nullptr) && !key->isPressed()) {
614 mouseEvent->accept();
626 if (d->m_mouseEnabled && (mouseEvent->source() == Qt::MouseEventNotSynthesized)) {
628 if (key !=
nullptr && !key->isPressed()) {
630 d->m_mousePressed =
true;
631 mouseEvent->accept();
643 if (d->m_mouseEnabled && (mouseEvent->source() == Qt::MouseEventNotSynthesized)) {
644 d->m_mousePressed =
false;
646 if (key !=
nullptr && key->isPressed()) {
648 mouseEvent->accept();
661 if (d->m_keybdMap !=
nullptr) {
662 KeyboardMap::ConstIterator it = d->m_keybdMap->constFind(key);
663 if ((it != d->m_keybdMap->constEnd()) && (it.key() == key)) {
664 int note = it.value();
679 if (d->m_keys.contains(note))
680 return d->m_keys.value(note);
690 if ( d->m_keyboardEnabled &&
691 !d->m_usingNativeFilter &&
692 !keyEvent->isAutoRepeat() )
694 int keyid = d->m_rawkbd ?
695 #if defined(Q_OS_MACOS) 696 keyEvent->nativeVirtualKey()
698 keyEvent->nativeScanCode()
717 if ( d->m_keyboardEnabled &&
718 !d->m_usingNativeFilter &&
719 !keyEvent->isAutoRepeat() )
721 int keyid = d->m_rawkbd ?
722 #if defined(Q_OS_MACOS) 723 keyEvent->nativeVirtualKey()
725 keyEvent->nativeScanCode()
746 return QGraphicsScene::event(
event);
754 foreach(PianoKey* key, d->m_keys) {
755 key->setPressed(
false);
767 if (color.isValid()) {
769 d->m_hilightPalette.setColor(0, color);
770 QBrush hilightBrush(color);
771 for (PianoKey* key : qAsConst(d->m_keys)) {
772 key->setPressedBrush(hilightBrush);
782 d->m_hilightPalette.resetColors();
784 for (PianoKey* key : qAsConst(d->m_keys)) {
785 key->setPressedBrush(hilightBrush);
803 for (PianoKey* key : qAsConst(d->m_keys)) {
804 int n = d->m_baseOctave*12 + key->getNote() + d->m_transpose;
805 bool b = !(n > d->m_maxNote) && !(n < d->m_minNote);
816 if (d->m_minNote != note) {
837 if (d->m_maxNote != note) {
849 return d->m_transpose;
858 if (d->m_baseOctave != base) {
859 d->m_baseOctave = base;
880 return d->m_startKey;
890 return (note + d->m_transpose + 12) % 12 == 0;
900 Q_ASSERT(key !=
nullptr);
901 int note = key->getNote();
902 int num = (note + d->m_transpose + 12) % 12;
903 int adj = ((note + d->m_transpose < 0) ? 2 : 1) - d->m_octave + 1;
904 int oct = d->m_baseOctave + ((note + d->m_transpose) / 12) - adj;
905 if (d->m_noteNames.isEmpty()) {
907 if (!d->m_names_f.isEmpty() && !d->m_names_s.isEmpty()) {
908 switch(d->m_alterations) {
910 name = d->m_names_f.value(num);
913 name = d->m_names_s.value(num);
916 if (key->isBlack()) {
919 name = d->m_names_s.value(num);
928 return QString(
"%1%2").arg(name).arg(oct);
931 if (d->m_noteNames.length() == 128) {
932 int n = d->m_baseOctave*12 + note + d->m_transpose;
934 if (n >= 0 && n < d->m_noteNames.length()) {
935 return d->m_noteNames.value(n);
937 }
else if (d->m_noteNames.length() >= 12) {
939 return d->m_noteNames.value(num);
941 return QString(
"%1%2").arg(d->m_noteNames.value(num)).arg(oct);
953 for (KeyLabel* lbl : qAsConst(d->m_labels)) {
954 PianoKey* key =
dynamic_cast<PianoKey*
>(lbl->parentItem());
955 if (key !=
nullptr) {
956 lbl->setVisible(
false);
957 lbl->setFont(font());
958 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(key->isBlack() ? 1 : 0));
959 lbl->setOrientation(d->m_orientation);
962 lbl->setVisible((d->m_showLabels ==
ShowAlways) ||
973 for (PianoKey* key : qAsConst(d->m_keys)) {
974 if (d->m_showColorScale && (d->m_backgroundPalette.paletteId() ==
PAL_SCALE)) {
975 int degree = key->getNote() % 12;
976 key->setBrush(d->m_backgroundPalette.getColor(degree));
978 key->setBrush(d->m_backgroundPalette.getColor(key->isBlack() ? 1 : 0));
980 key->setPressed(
false);
992 if (d->m_showLabels != show) {
993 d->m_showLabels = show;
1005 return d->m_alterations;
1015 if (d->m_alterations != use) {
1016 d->m_alterations = use;
1036 if (d->m_orientation != orientation) {
1037 d->m_orientation = orientation;
1042 bool PianoScene::isKeyboardEnabled()
const 1044 return d->m_keyboardEnabled;
1049 if (d->m_octave != octave) {
1050 d->m_octave = octave;
1057 return d->m_orientation;
1066 if (d->m_transpose != transpose && transpose > -12 && transpose < 12) {
1067 d->m_transpose = transpose;
1080 return d->m_showLabels;
1089 if (d->m_rawkbd != b) {
1100 return d->m_noteNames;
1109 return d->m_names_s;
1118 return d->m_velocity;
1127 d->m_velocity = velocity;
1137 return d->m_channel;
1147 d->m_channel = channel;
1157 d->m_noteNames = names;
1167 d->m_noteNames.clear();
1177 if (enable != d->m_keyboardEnabled) {
1178 d->m_keyboardEnabled = enable;
1188 return d->m_mouseEnabled;
1197 if (enable != d->m_mouseEnabled) {
1198 d->m_mouseEnabled = enable;
1208 return d->m_touchEnabled;
1217 if (enable != d->m_touchEnabled) {
1218 d->m_touchEnabled = enable;
1228 return d->m_velocityTint;
1238 d->m_velocityTint = enable;
1246 d->m_names_s = QStringList{
1259 d->m_names_f = QStringList{
1281 if (d->m_showColorScale != show) {
1282 d->m_showColorScale = show;
1294 return d->m_hilightPalette.getColor(0);
1303 if (d->m_hilightPalette != p) {
1304 d->m_hilightPalette = p;
1316 return d->m_backgroundPalette;
1325 if (d->m_backgroundPalette != p) {
1326 d->m_backgroundPalette = p;
1338 return d->m_foregroundPalette;
1347 if (d->m_foregroundPalette != p) {
1348 d->m_foregroundPalette = p;
1360 return d->m_showColorScale;
1363 void PianoScene::setKeyPicture(
const bool natural,
const QPixmap &pix)
1365 d->m_keyPix[int(natural)] = pix;
1366 for (PianoKey* key : qAsConst(d->m_keys)) {
1367 if (key->isBlack() == !natural) {
1368 key->setPixmap(pix);
1373 QPixmap PianoScene::getKeyPicture(
const bool natural)
1375 return d->m_keyPix[int(natural)];
1378 void PianoScene::setUseKeyPictures(
const bool enable)
1380 d->m_useKeyPix = enable;
1381 for (PianoKey* key : qAsConst(d->m_keys)) {
1382 key->setUsePixmap(enable);
1386 bool PianoScene::getUseKeyPictures()
const 1388 return d->m_useKeyPix;
1391 void PianoScene::saveData(QByteArray &ba)
1396 void PianoScene::loadData(QByteArray &ba)
1408 switch(touchEvent->type()) {
1409 case QEvent::TouchEnd:
1410 case QEvent::TouchCancel:
1412 foreach(PianoKey *key, d->m_touched) {
1414 if (key->isPressed()) {
1418 d->m_touched.clear();
1419 touchEvent->accept();
1422 case QEvent::TouchBegin:
1423 case QEvent::TouchUpdate:
1425 QList<QTouchEvent::TouchPoint> touchPoints =
1426 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) 1427 touchEvent->touchPoints();
1429 touchEvent->points();
1432 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) 1433 touchEvent->device()->capabilities().testFlag(QTouchDevice::Pressure);
1435 touchEvent->device()->capabilities().testFlag(QInputDevice::Capability::Pressure);
1437 foreach(
const QTouchEvent::TouchPoint& touchPoint, touchPoints) {
1439 switch (touchPoint.state()) {
1440 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) 1441 case Qt::TouchPointReleased:
1443 case QEventPoint::Released:
1446 PianoKey* key = d->m_touched.value(touchPoint.id());
1447 if (key !=
nullptr) {
1449 if (key->isPressed()) {
1451 keyOff(key, touchPoint.pressure());
1456 d->m_touched.remove(touchPoint.id());
1460 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) 1461 case Qt::TouchPointPressed:
1463 case QEventPoint::Pressed:
1467 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
1468 touchPoint.pos().toPoint()
1470 touchPoint.position().toPoint()
1473 if (key !=
nullptr) {
1475 if (!key->isPressed()) {
1477 keyOn(key, touchPoint.pressure());
1481 key->ensureVisible();
1483 d->m_touched[touchPoint.id()] = key;
1487 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) 1488 case Qt::TouchPointMoved:
1490 case QEventPoint::Updated:
1494 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
1495 touchPoint.pos().toPoint()
1497 touchPoint.position().toPoint()
1500 PianoKey* lastkey = d->m_touched.value(touchPoint.id());
1501 if ((lastkey !=
nullptr) && (lastkey != key)) {
1503 if (lastkey->isPressed()) {
1505 keyOff(lastkey, touchPoint.pressure());
1510 d->m_touched.remove(touchPoint.id());
1512 if (key !=
nullptr) {
1514 if (!key->isPressed()) {
1516 keyOn(key, touchPoint.pressure());
1521 d->m_touched[touchPoint.id()] = key;
1529 touchEvent->accept();
1544 if (newState != d->m_usingNativeFilter) {
1545 d->m_usingNativeFilter = newState;
1555 return d->m_usingNativeFilter;
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.
The QEvent class is the base class of all event classes.