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 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.