19 #include <QApplication>
20 #include <QDataStream>
22 #include <QGraphicsSceneMouseEvent>
27 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
28 #include <QTouchDevice>
30 #include <QInputDevice>
48 class PianoScene::PianoScenePrivate
65 m_keyboardEnabled( true ),
66 m_mouseEnabled( true ),
67 m_touchEnabled( true ),
68 m_mousePressed( false ),
71 m_velocityTint( true ),
73 m_keybdMap( nullptr ),
74 m_showColorScale( false ),
76 m_backgroundPalette(PianoPalette(
PAL_KEYS)),
77 m_foregroundPalette(PianoPalette(
PAL_FONT)),
81 void saveData(QByteArray& buffer)
83 QDataStream ds(&buffer, QIODevice::WriteOnly);
92 ds << m_keyboardEnabled;
102 ds << m_showColorScale;
103 ds << m_hilightPalette;
104 ds << m_backgroundPalette;
105 ds << m_foregroundPalette;
111 void loadData(QByteArray& buffer)
114 QDataStream ds(&buffer, QIODevice::ReadOnly);
123 ds >> m_keyboardEnabled;
124 ds >> m_mouseEnabled;
125 ds >> m_touchEnabled;
126 ds >> m_mousePressed;
129 ds >> m_velocityTint;
133 ds >> m_showColorScale;
134 ds >> m_hilightPalette;
135 ds >> m_backgroundPalette;
136 ds >> m_foregroundPalette;
153 bool m_keyboardEnabled;
160 PianoHandler *m_handler;
162 QHash<int, PianoKey *> m_keys;
163 QMap<int, KeyLabel *> m_labels;
164 QStringList m_noteNames;
165 QStringList m_names_s;
166 QStringList m_names_f;
167 bool m_showColorScale;
168 PianoPalette m_hilightPalette;
169 PianoPalette m_backgroundPalette;
170 PianoPalette m_foregroundPalette;
175 const int KEYWIDTH = 180;
176 const int KEYHEIGHT = 720;
178 static qreal sceneWidth(
int keys) {
179 return KEYWIDTH * qCeil( keys * 7.0 / 12.0 );
193 const QColor& keyPressedColor,
195 :
QGraphicsScene( QRectF(0, 0, sceneWidth(numKeys), KEYHEIGHT), parent ),
196 d(new PianoScenePrivate(baseOctave, numKeys, startKey))
198 if (keyPressedColor.isValid()) {
203 if (view !=
nullptr) {
204 setFont(view->font());
206 int upperLimit = d->m_numKeys + d->m_startKey;
207 int adj = d->m_startKey % 12;
209 for(
int i = d->m_startKey; i < upperLimit; ++i)
212 PianoKey* key =
nullptr;
213 KeyLabel* lbl =
nullptr;
214 int ocs = i / 12 * 7;
218 x = (ocs + qFloor((j-adj) / 2.0)) * KEYWIDTH;
219 key =
new PianoKey( QRectF(x, 0, KEYWIDTH, KEYHEIGHT),
false, i );
220 lbl =
new KeyLabel(key);
221 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(0));
223 x = (ocs + qFloor((j-adj) / 2.0)) * KEYWIDTH + KEYWIDTH * 0.6 + 1;
224 key =
new PianoKey( QRectF( x, 0, KEYWIDTH * 0.8 - 1, KEYHEIGHT * 0.6 ),
true, i );
226 lbl =
new KeyLabel(key);
227 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(1));
230 lbl->setFont(font());
231 key->setAcceptTouchEvents(
true);
232 key->setPressedBrush(hilightBrush);
233 d->m_keys.insert(i, key);
234 d->m_labels.insert(i, lbl);
252 return {
static_cast<int>(sceneWidth(d->m_numKeys)), KEYHEIGHT};
270 return d->m_keybdMap;
295 d->m_handler = handler;
304 return d->m_hilightPalette;
313 key->setPressed(
true);
314 int n = key->getNote() + d->m_baseOctave*12 + d->m_transpose;
315 QString s = QString(
"#%1 (%2)").arg(n).arg(
noteName(key));
317 KeyLabel* lbl =
dynamic_cast<KeyLabel*
>(key->childItems().constFirst());
318 if (lbl !=
nullptr) {
319 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(key->isBlack() ? 3 : 2));
321 lbl->setVisible(
true);
335 if (d->m_velocityTint && (vel >= 0) && (vel < 128) && color.isValid() ) {
336 QBrush hilightBrush(color.lighter(200 - vel));
337 key->setPressedBrush(hilightBrush);
338 }
else if (color.isValid()) {
339 key->setPressedBrush(color);
363 key->setPressed(
false);
365 KeyLabel* lbl =
dynamic_cast<KeyLabel*
>(key->childItems().constFirst());
366 if (lbl !=
nullptr) {
369 lbl->setVisible(
false);
383 int n = note - d->m_baseOctave*12 - d->m_transpose;
384 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n) && color.isValid())
385 showKeyOn(d->m_keys.value(n), color, vel);
396 int n = note - d->m_baseOctave*12 - d->m_transpose;
397 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n)) {
409 int n = note - d->m_baseOctave*12 - d->m_transpose;
410 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n)) {
431 int n = d->m_baseOctave*12 + note + d->m_transpose;
432 if ((n >= d->m_minNote) && (n <= d->m_maxNote)) {
433 if (d->m_handler !=
nullptr) {
434 d->m_handler->noteOn(n, vel);
450 int n = d->m_baseOctave*12 + note + d->m_transpose;
451 if ((n >= d->m_minNote) && (n <= d->m_maxNote)) {
452 if (d->m_handler !=
nullptr) {
453 d->m_handler->noteOff(n, vel);
470 switch (d->m_hilightPalette.paletteId()) {
472 c = d->m_hilightPalette.getColor(0);
475 c = d->m_hilightPalette.getColor(key->getType());
478 c = d->m_hilightPalette.getColor(d->m_channel);
481 c = d->m_hilightPalette.getColor(key->getDegree());
487 if (d->m_velocityTint && (vel >= 0) && (vel < 128)) {
488 QBrush h(c.lighter(200 - vel));
489 key->setPressedBrush(h);
491 key->setPressedBrush(c);
523 int vel = d->m_velocity * pressure;
535 int vel = d->m_velocity * pressure;
546 if (d->m_keys.contains(note))
547 keyOn(d->m_keys.value(note));
558 if (d->m_keys.contains(note))
559 keyOff(d->m_keys.value(note));
580 PianoKey* key =
nullptr;
581 QList<QGraphicsItem *> ptitems = this->items(p, Qt::IntersectsItemShape, Qt::DescendingOrder);
582 foreach(QGraphicsItem *itm, ptitems) {
583 key =
dynamic_cast<PianoKey*
>(itm);
596 if (d->m_mouseEnabled) {
597 if (d->m_mousePressed) {
599 PianoKey* lastkey =
getKeyForPos(mouseEvent->lastScenePos());
600 if ((lastkey !=
nullptr) && (lastkey != key) && lastkey->isPressed()) {
603 if ((key !=
nullptr) && !key->isPressed()) {
606 mouseEvent->accept();
618 if (d->m_mouseEnabled) {
620 if (key !=
nullptr && !key->isPressed()) {
622 d->m_mousePressed =
true;
623 mouseEvent->accept();
635 if (d->m_mouseEnabled) {
636 d->m_mousePressed =
false;
638 if (key !=
nullptr && key->isPressed()) {
640 mouseEvent->accept();
653 if (d->m_keybdMap !=
nullptr) {
654 KeyboardMap::ConstIterator it = d->m_keybdMap->constFind(key);
655 if ((it != d->m_keybdMap->constEnd()) && (it.key() == key)) {
656 int note = it.value();
671 if (d->m_keys.contains(note))
672 return d->m_keys.value(note);
682 if ( d->m_keyboardEnabled) {
683 if ( !d->m_rawkbd && !keyEvent->isAutoRepeat() ) {
700 if (d->m_keyboardEnabled) {
701 if ( !d->m_rawkbd && !keyEvent->isAutoRepeat() ) {
719 switch(
event->type()) {
720 case QEvent::TouchBegin:
721 case QEvent::TouchEnd:
722 case QEvent::TouchUpdate:
724 QTouchEvent *touchEvent =
static_cast<QTouchEvent*
>(
event);
725 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
726 const auto touchScreen = QTouchDevice::DeviceType::TouchScreen;
728 const auto touchScreen = QInputDevice::DeviceType::TouchScreen;
730 if (d->m_touchEnabled && touchEvent->device()->type() == touchScreen) {
731 QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
733 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
734 touchEvent->device()->capabilities().testFlag(QTouchDevice::Pressure);
736 touchEvent->device()->capabilities().testFlag(QInputDevice::Capability::Pressure);
738 foreach(
const QTouchEvent::TouchPoint& touchPoint, touchPoints) {
739 switch (touchPoint.state()) {
741 case Qt::TouchPointStationary:
743 case Qt::TouchPointReleased: {
745 if (key !=
nullptr && key->isPressed()) {
747 keyOff(key, touchPoint.pressure());
754 case Qt::TouchPointPressed: {
756 if (key !=
nullptr && !key->isPressed()) {
758 keyOn(key, touchPoint.pressure());
762 key->ensureVisible();
766 case Qt::TouchPointMoved: {
768 PianoKey* lastkey =
getKeyForPos(touchPoint.lastScenePos());
769 if ((lastkey !=
nullptr) && (lastkey != key) && lastkey->isPressed()) {
771 keyOff(lastkey, touchPoint.pressure());
776 if ((key !=
nullptr) && !key->isPressed()) {
778 keyOn(key, touchPoint.pressure());
800 return QGraphicsScene::event(
event);
808 foreach(PianoKey* key, d->m_keys) {
809 key->setPressed(
false);
821 if (color.isValid()) {
823 d->m_hilightPalette.setColor(0, color);
824 QBrush hilightBrush(color);
825 for (PianoKey* key : qAsConst(d->m_keys)) {
826 key->setPressedBrush(hilightBrush);
836 d->m_hilightPalette.resetColors();
838 for (PianoKey* key : qAsConst(d->m_keys)) {
839 key->setPressedBrush(hilightBrush);
857 for (PianoKey* key : qAsConst(d->m_keys)) {
858 int n = d->m_baseOctave*12 + key->getNote() + d->m_transpose;
859 bool b = !(n > d->m_maxNote) && !(n < d->m_minNote);
870 if (d->m_minNote != note) {
891 if (d->m_maxNote != note) {
903 return d->m_transpose;
912 if (d->m_baseOctave != base) {
913 d->m_baseOctave = base;
934 return d->m_startKey;
944 return (note + d->m_transpose + 12) % 12 == 0;
954 Q_ASSERT(key !=
nullptr);
955 int note = key->getNote();
956 int num = (note + d->m_transpose + 12) % 12;
957 int adj = ((note + d->m_transpose < 0) ? 2 : 1) - d->m_octave + 1;
958 int oct = d->m_baseOctave + ((note + d->m_transpose) / 12) - adj;
959 if (d->m_noteNames.isEmpty()) {
961 if (!d->m_names_f.isEmpty() && !d->m_names_s.isEmpty()) {
962 switch(d->m_alterations) {
964 name = d->m_names_f.value(num);
967 name = d->m_names_s.value(num);
970 if (key->isBlack()) {
973 name = d->m_names_s.value(num);
982 return QString(
"%1%2").arg(name).arg(oct);
985 if (d->m_noteNames.length() == 128) {
986 int n = d->m_baseOctave*12 + note + d->m_transpose;
988 if (n >= 0 && n < d->m_noteNames.length()) {
989 return d->m_noteNames.value(n);
991 }
else if (d->m_noteNames.length() >= 12) {
993 return d->m_noteNames.value(num);
995 return QString(
"%1%2").arg(d->m_noteNames.value(num)).arg(oct);
1007 for (KeyLabel* lbl : qAsConst(d->m_labels)) {
1008 PianoKey* key =
dynamic_cast<PianoKey*
>(lbl->parentItem());
1009 if (key !=
nullptr) {
1010 lbl->setVisible(
false);
1011 lbl->setFont(font());
1012 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(key->isBlack() ? 1 : 0));
1013 lbl->setOrientation(d->m_orientation);
1016 lbl->setVisible((d->m_showLabels ==
ShowAlways) ||
1027 for (PianoKey* key : qAsConst(d->m_keys)) {
1028 if (d->m_showColorScale && (d->m_backgroundPalette.paletteId() ==
PAL_SCALE)) {
1029 int degree = key->getNote() % 12;
1030 key->setBrush(d->m_backgroundPalette.getColor(degree));
1032 key->setBrush(d->m_backgroundPalette.getColor(key->isBlack() ? 1 : 0));
1034 key->setPressed(
false);
1046 if (d->m_showLabels != show) {
1047 d->m_showLabels = show;
1059 return d->m_alterations;
1069 if (d->m_alterations != use) {
1070 d->m_alterations = use;
1090 if (d->m_orientation != orientation) {
1091 d->m_orientation = orientation;
1096 bool PianoScene::isKeyboardEnabled()
const
1098 return d->m_keyboardEnabled;
1103 if (d->m_octave != octave) {
1104 d->m_octave = octave;
1111 return d->m_orientation;
1120 if (d->m_transpose != transpose && transpose > -12 && transpose < 12) {
1121 d->m_transpose = transpose;
1134 return d->m_showLabels;
1143 if (d->m_rawkbd != b) {
1154 return d->m_noteNames;
1163 return d->m_names_s;
1172 return d->m_velocity;
1181 d->m_velocity = velocity;
1191 return d->m_channel;
1201 d->m_channel = channel;
1211 d->m_noteNames = names;
1221 d->m_noteNames.clear();
1231 if (enable != d->m_keyboardEnabled) {
1232 d->m_keyboardEnabled = enable;
1242 return d->m_mouseEnabled;
1251 if (enable != d->m_mouseEnabled) {
1252 d->m_mouseEnabled = enable;
1262 return d->m_touchEnabled;
1271 if (enable != d->m_touchEnabled) {
1272 d->m_touchEnabled = enable;
1282 return d->m_velocityTint;
1292 d->m_velocityTint = enable;
1300 d->m_names_s = QStringList{
1313 d->m_names_f = QStringList{
1335 if (d->m_showColorScale != show) {
1336 d->m_showColorScale = show;
1348 return d->m_hilightPalette.getColor(0);
1357 if (d->m_hilightPalette != p) {
1358 d->m_hilightPalette = p;
1370 return d->m_backgroundPalette;
1379 if (d->m_backgroundPalette != p) {
1380 d->m_backgroundPalette = p;
1392 return d->m_foregroundPalette;
1401 if (d->m_foregroundPalette != p) {
1402 d->m_foregroundPalette = p;
1414 return d->m_showColorScale;
1417 void PianoScene::setKeyPicture(
const bool natural,
const QPixmap &pix)
1419 d->m_keyPix[int(natural)] = pix;
1420 for (PianoKey* key : qAsConst(d->m_keys)) {
1421 if (key->isBlack() == !natural) {
1422 key->setPixmap(pix);
1427 QPixmap PianoScene::getKeyPicture(
const bool natural)
1429 return d->m_keyPix[int(natural)];
1432 void PianoScene::setUseKeyPictures(
const bool enable)
1434 d->m_useKeyPix = enable;
1435 for (PianoKey* key : qAsConst(d->m_keys)) {
1436 key->setUsePixmap(enable);
1440 bool PianoScene::getUseKeyPictures()
const
1442 return d->m_useKeyPix;
1445 void PianoScene::saveData(QByteArray &ba)
1450 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.