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);
334 }
else if (color.isValid()) {
335 key->setPressedBrush(color);
359 key->setPressed(
false);
361 KeyLabel* lbl =
dynamic_cast<KeyLabel*
>(key->childItems().constFirst());
362 if (lbl !=
nullptr) {
365 lbl->setVisible(
false);
379 int n = note - d->m_baseOctave*12 - d->m_transpose;
380 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n) && color.isValid())
381 showKeyOn(d->m_keys.value(n), color, vel);
392 int n = note - d->m_baseOctave*12 - d->m_transpose;
393 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n)) {
405 int n = note - d->m_baseOctave*12 - d->m_transpose;
406 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n)) {
427 int n = d->m_baseOctave*12 + note + d->m_transpose;
428 if ((n >= d->m_minNote) && (n <= d->m_maxNote)) {
429 if (d->m_handler !=
nullptr) {
430 d->m_handler->noteOn(n, vel);
446 int n = d->m_baseOctave*12 + note + d->m_transpose;
447 if ((n >= d->m_minNote) && (n <= d->m_maxNote)) {
448 if (d->m_handler !=
nullptr) {
449 d->m_handler->noteOff(n, vel);
466 switch (d->m_hilightPalette.paletteId()) {
468 c = d->m_hilightPalette.getColor(0);
471 c = d->m_hilightPalette.getColor(key->getType());
474 c = d->m_hilightPalette.getColor(d->m_channel);
477 c = d->m_hilightPalette.getColor(key->getDegree());
483 if (d->m_velocityTint && (vel >= 0) && (vel < 128)) {
484 QBrush h(c.lighter(200 - vel));
485 key->setPressedBrush(h);
487 key->setPressedBrush(c);
519 int vel = d->m_velocity * pressure;
531 int vel = d->m_velocity * pressure;
542 if (d->m_keys.contains(note))
543 keyOn(d->m_keys.value(note));
554 if (d->m_keys.contains(note))
555 keyOff(d->m_keys.value(note));
576 PianoKey* key =
nullptr;
577 QList<QGraphicsItem *> ptitems = this->items(p, Qt::IntersectsItemShape, Qt::DescendingOrder);
578 foreach(QGraphicsItem *itm, ptitems) {
579 key =
dynamic_cast<PianoKey*
>(itm);
592 if (d->m_mouseEnabled) {
593 if (d->m_mousePressed) {
595 PianoKey* lastkey =
getKeyForPos(mouseEvent->lastScenePos());
596 if ((lastkey !=
nullptr) && (lastkey != key) && lastkey->isPressed()) {
599 if ((key !=
nullptr) && !key->isPressed()) {
602 mouseEvent->accept();
614 if (d->m_mouseEnabled) {
616 if (key !=
nullptr && !key->isPressed()) {
618 d->m_mousePressed =
true;
619 mouseEvent->accept();
631 if (d->m_mouseEnabled) {
632 d->m_mousePressed =
false;
634 if (key !=
nullptr && key->isPressed()) {
636 mouseEvent->accept();
649 if (d->m_keybdMap !=
nullptr) {
650 KeyboardMap::ConstIterator it = d->m_keybdMap->constFind(key);
651 if ((it != d->m_keybdMap->constEnd()) && (it.key() == key)) {
652 int note = it.value();
667 if (d->m_keys.contains(note))
668 return d->m_keys.value(note);
678 if ( d->m_keyboardEnabled) {
679 if ( !d->m_rawkbd && !keyEvent->isAutoRepeat() ) {
696 if (d->m_keyboardEnabled) {
697 if ( !d->m_rawkbd && !keyEvent->isAutoRepeat() ) {
715 switch(
event->type()) {
716 case QEvent::TouchBegin:
717 case QEvent::TouchEnd:
718 case QEvent::TouchUpdate:
720 QTouchEvent *touchEvent =
static_cast<QTouchEvent*
>(
event);
721 if (d->m_touchEnabled && touchEvent->device()->type() == QTouchDevice::DeviceType::TouchScreen) {
722 QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
723 foreach(
const QTouchEvent::TouchPoint& touchPoint, touchPoints) {
724 switch (touchPoint.state()) {
726 case Qt::TouchPointStationary:
728 case Qt::TouchPointReleased: {
730 if (key !=
nullptr && key->isPressed()) {
731 keyOff(key, touchPoint.pressure());
735 case Qt::TouchPointPressed: {
737 if (key !=
nullptr && !key->isPressed()) {
738 keyOn(key, touchPoint.pressure());
739 key->ensureVisible();
743 case Qt::TouchPointMoved: {
745 PianoKey* lastkey =
getKeyForPos(touchPoint.lastScenePos());
746 if ((lastkey !=
nullptr) && (lastkey != key) && lastkey->isPressed()) {
747 keyOff(lastkey, touchPoint.pressure());
749 if ((key !=
nullptr) && !key->isPressed()) {
750 keyOn(key, touchPoint.pressure());
769 return QGraphicsScene::event(
event);
777 foreach(PianoKey* key, d->m_keys) {
778 key->setPressed(
false);
790 if (color.isValid()) {
792 d->m_hilightPalette.setColor(0, color);
793 QBrush hilightBrush(color);
794 for (PianoKey* key : qAsConst(d->m_keys)) {
795 key->setPressedBrush(hilightBrush);
805 d->m_hilightPalette.resetColors();
807 for (PianoKey* key : qAsConst(d->m_keys)) {
808 key->setPressedBrush(hilightBrush);
826 for (PianoKey* key : qAsConst(d->m_keys)) {
827 int n = d->m_baseOctave*12 + key->getNote() + d->m_transpose;
828 bool b = !(n > d->m_maxNote) && !(n < d->m_minNote);
839 if (d->m_minNote != note) {
860 if (d->m_maxNote != note) {
872 return d->m_transpose;
881 if (d->m_baseOctave != base) {
882 d->m_baseOctave = base;
903 return d->m_startKey;
913 return (note + d->m_transpose + 12) % 12 == 0;
923 Q_ASSERT(key !=
nullptr);
924 int note = key->getNote();
925 int num = (note + d->m_transpose + 12) % 12;
926 int adj = ((note + d->m_transpose < 0) ? 2 : 1) - d->m_octave + 1;
927 int oct = d->m_baseOctave + ((note + d->m_transpose) / 12) - adj;
928 if (d->m_noteNames.isEmpty()) {
930 if (!d->m_names_f.isEmpty() && !d->m_names_s.isEmpty()) {
931 switch(d->m_alterations) {
933 name = d->m_names_f.value(num);
936 name = d->m_names_s.value(num);
939 if (key->isBlack()) {
942 name = d->m_names_s.value(num);
951 return QString(
"%1%2").arg(name).arg(oct);
954 if (d->m_noteNames.length() == 128) {
955 int n = d->m_baseOctave*12 + note + d->m_transpose;
957 if (n >= 0 && n < d->m_noteNames.length()) {
958 return d->m_noteNames.value(n);
960 }
else if (d->m_noteNames.length() >= 12) {
962 return d->m_noteNames.value(num);
964 return QString(
"%1%2").arg(d->m_noteNames.value(num)).arg(oct);
976 for (KeyLabel* lbl : qAsConst(d->m_labels)) {
977 PianoKey* key =
dynamic_cast<PianoKey*
>(lbl->parentItem());
978 if (key !=
nullptr) {
979 lbl->setVisible(
false);
980 lbl->setFont(font());
981 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(key->isBlack() ? 1 : 0));
982 lbl->setOrientation(d->m_orientation);
985 lbl->setVisible((d->m_showLabels ==
ShowAlways) ||
996 for (PianoKey* key : qAsConst(d->m_keys)) {
997 if (d->m_showColorScale && (d->m_backgroundPalette.paletteId() ==
PAL_SCALE)) {
998 int degree = key->getNote() % 12;
999 key->setBrush(d->m_backgroundPalette.getColor(degree));
1001 key->setBrush(d->m_backgroundPalette.getColor(key->isBlack() ? 1 : 0));
1003 key->setPressed(
false);
1015 if (d->m_showLabels != show) {
1016 d->m_showLabels = show;
1028 return d->m_alterations;
1038 if (d->m_alterations != use) {
1039 d->m_alterations = use;
1059 if (d->m_orientation != orientation) {
1060 d->m_orientation = orientation;
1065 bool PianoScene::isKeyboardEnabled()
const
1067 return d->m_keyboardEnabled;
1072 if (d->m_octave != octave) {
1073 d->m_octave = octave;
1080 return d->m_orientation;
1089 if (d->m_transpose != transpose && transpose > -12 && transpose < 12) {
1090 d->m_transpose = transpose;
1103 return d->m_showLabels;
1112 if (d->m_rawkbd != b) {
1123 return d->m_noteNames;
1132 return d->m_names_s;
1141 return d->m_velocity;
1150 d->m_velocity = velocity;
1160 return d->m_channel;
1170 d->m_channel = channel;
1180 d->m_noteNames = names;
1190 d->m_noteNames.clear();
1200 if (enable != d->m_keyboardEnabled) {
1201 d->m_keyboardEnabled = enable;
1211 return d->m_mouseEnabled;
1220 if (enable != d->m_mouseEnabled) {
1221 d->m_mouseEnabled = enable;
1231 return d->m_touchEnabled;
1240 if (enable != d->m_touchEnabled) {
1241 d->m_touchEnabled = enable;
1251 return d->m_velocityTint;
1261 d->m_velocityTint = enable;
1269 d->m_names_s = QStringList{
1282 d->m_names_f = QStringList{
1304 if (d->m_showColorScale != show) {
1305 d->m_showColorScale = show;
1317 return d->m_hilightPalette.getColor(0);
1326 if (d->m_hilightPalette != p) {
1327 d->m_hilightPalette = p;
1339 return d->m_backgroundPalette;
1348 if (d->m_backgroundPalette != p) {
1349 d->m_backgroundPalette = p;
1361 return d->m_foregroundPalette;
1370 if (d->m_foregroundPalette != p) {
1371 d->m_foregroundPalette = p;
1383 return d->m_showColorScale;
1386 void PianoScene::setKeyPicture(
const bool natural,
const QPixmap &pix)
1388 d->m_keyPix[int(natural)] = pix;
1389 for (PianoKey* key : qAsConst(d->m_keys)) {
1390 if (key->isBlack() == !natural) {
1391 key->setPixmap(pix);
1396 QPixmap PianoScene::getKeyPicture(
const bool natural)
1398 return d->m_keyPix[int(natural)];
1401 void PianoScene::setUseKeyPictures(
const bool enable)
1403 d->m_useKeyPix = enable;
1404 for (PianoKey* key : qAsConst(d->m_keys)) {
1405 key->setUsePixmap(enable);
1409 bool PianoScene::getUseKeyPictures()
const
1411 return d->m_useKeyPix;
1414 void PianoScene::saveData(QByteArray &ba)
1419 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.