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 ),
81 m_octaveSubscript( true )
84 void saveData(QByteArray& buffer)
86 QDataStream ds(&buffer, QIODevice::WriteOnly);
95 ds << m_keyboardEnabled;
101 ds << m_velocityTint;
105 ds << m_showColorScale;
106 ds << m_hilightPalette;
107 ds << m_backgroundPalette;
108 ds << m_foregroundPalette;
112 ds << m_usingNativeFilter;
113 ds << m_octaveSubscript;
116 void loadData(QByteArray& buffer)
119 QDataStream ds(&buffer, QIODevice::ReadOnly);
128 ds >> m_keyboardEnabled;
129 ds >> m_mouseEnabled;
130 ds >> m_touchEnabled;
131 ds >> m_mousePressed;
134 ds >> m_velocityTint;
138 ds >> m_showColorScale;
139 ds >> m_hilightPalette;
140 ds >> m_backgroundPalette;
141 ds >> m_foregroundPalette;
145 ds >> m_usingNativeFilter;
146 ds >> m_octaveSubscript;
149 QString
noteName( PianoKey* key,
bool richText )
151 Q_ASSERT(key !=
nullptr);
152 int note = key->getNote();
153 int num = (note + m_transpose + 12) % 12;
154 int adj = ((note + m_transpose < 0) ? 2 : 1) - m_octave + 1;
155 int oct = m_baseOctave + ((note + m_transpose) / 12) - adj;
156 QString nameMask = QLatin1String(richText && m_octaveSubscript ?
"%1<sub>%2</sub>" :
"%1%2");
157 if (m_noteNames.isEmpty()) {
159 if (!m_names_f.isEmpty() && !m_names_s.isEmpty()) {
160 switch(m_alterations) {
162 name = m_names_f.value(num);
165 name = m_names_s.value(num);
168 if (key->isBlack()) {
171 name = m_names_s.value(num);
180 return nameMask.arg(name).arg(oct);
183 if (m_noteNames.length() == 128) {
184 int n = m_baseOctave*12 + note + m_transpose;
186 if (n >= 0 && n < m_noteNames.length()) {
187 return m_noteNames.value(n);
189 }
else if (m_noteNames.length() >= 12) {
191 return m_noteNames.value(num);
193 return nameMask.arg(m_noteNames.value(num)).arg(oct);
211 bool m_keyboardEnabled;
218 PianoHandler *m_handler;
220 QHash<int, PianoKey *> m_keys;
221 QMap<int, KeyLabel *> m_labels;
222 QStringList m_noteNames;
223 QStringList m_names_s;
224 QStringList m_names_f;
225 bool m_showColorScale;
226 PianoPalette m_hilightPalette;
227 PianoPalette m_backgroundPalette;
228 PianoPalette m_foregroundPalette;
231 bool m_usingNativeFilter;
232 bool m_octaveSubscript;
235 QMap<int, PianoKey *> m_touched;
238 const int KEYWIDTH = 180;
239 const int KEYHEIGHT = 720;
241 static qreal sceneWidth(
int keys) {
242 return KEYWIDTH * qCeil( keys * 7.0 / 12.0 );
256 const QColor& keyPressedColor,
258 :
QGraphicsScene( QRectF(0, 0, sceneWidth(numKeys), KEYHEIGHT), parent ),
259 d(new PianoScenePrivate(baseOctave, numKeys, startKey))
261 if (keyPressedColor.isValid()) {
265 d->m_view =
dynamic_cast<PianoKeybd*
>(parent);
266 if (d->m_view !=
nullptr) {
267 setFont(d->m_view->font());
269 int upperLimit = d->m_numKeys + d->m_startKey;
270 int adj = d->m_startKey % 12;
272 for(
int i = d->m_startKey; i < upperLimit; ++i)
275 PianoKey* key =
nullptr;
276 KeyLabel* lbl =
nullptr;
277 int ocs = i / 12 * 7;
281 x = (ocs + qFloor((j-adj) / 2.0)) * KEYWIDTH;
282 key =
new PianoKey( QRectF(x, 0, KEYWIDTH, KEYHEIGHT),
false, i );
283 lbl =
new KeyLabel(key);
284 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(0));
286 x = (ocs + qFloor((j-adj) / 2.0)) * KEYWIDTH + KEYWIDTH * 0.6 + 1;
287 key =
new PianoKey( QRectF( x, 0, KEYWIDTH * 0.8 - 1, KEYHEIGHT * 0.6 ),
true, i );
289 lbl =
new KeyLabel(key);
290 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(1));
293 lbl->setFont(font());
294 key->setAcceptTouchEvents(
true);
295 key->setPressedBrush(hilightBrush);
296 d->m_keys.insert(i, key);
297 d->m_labels.insert(i, lbl);
315 return {
static_cast<int>(sceneWidth(d->m_numKeys)), KEYHEIGHT};
333 return d->m_keybdMap;
358 d->m_handler = handler;
367 return d->m_hilightPalette;
376 key->setPressed(
true);
377 int n = key->getNote() + d->m_baseOctave*12 + d->m_transpose;
378 QString s = QString(
"#%1 (%2)").arg(n).arg(d->noteName(key,
false));
380 KeyLabel* lbl =
dynamic_cast<KeyLabel*
>(key->childItems().constFirst());
381 if (lbl !=
nullptr) {
382 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(key->isBlack() ? 3 : 2));
384 lbl->setVisible(
true);
398 if (d->m_velocityTint && (vel >= 0) && (vel < 128) && color.isValid() ) {
399 QBrush hilightBrush(color.lighter(200 - vel));
400 key->setPressedBrush(hilightBrush);
401 }
else if (color.isValid()) {
402 key->setPressedBrush(color);
426 key->setPressed(
false);
428 KeyLabel* lbl =
dynamic_cast<KeyLabel*
>(key->childItems().constFirst());
429 if (lbl !=
nullptr) {
432 lbl->setVisible(
false);
446 int n = note - d->m_baseOctave*12 - d->m_transpose;
447 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n) && color.isValid())
448 showKeyOn(d->m_keys.value(n), color, vel);
459 int n = note - d->m_baseOctave*12 - d->m_transpose;
460 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n)) {
472 int n = note - d->m_baseOctave*12 - d->m_transpose;
473 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n)) {
494 int n = d->m_baseOctave*12 + note + d->m_transpose;
495 if ((n >= d->m_minNote) && (n <= d->m_maxNote)) {
496 if (d->m_handler !=
nullptr) {
497 d->m_handler->noteOn(n, vel);
513 int n = d->m_baseOctave*12 + note + d->m_transpose;
514 if ((n >= d->m_minNote) && (n <= d->m_maxNote)) {
515 if (d->m_handler !=
nullptr) {
516 d->m_handler->noteOff(n, vel);
533 switch (d->m_hilightPalette.paletteId()) {
535 c = d->m_hilightPalette.getColor(0);
538 c = d->m_hilightPalette.getColor(key->getType());
541 c = d->m_hilightPalette.getColor(d->m_channel);
544 c = d->m_hilightPalette.getColor(key->getDegree());
550 if (d->m_velocityTint && (vel >= 0) && (vel < 128)) {
551 QBrush h(c.lighter(200 - vel));
552 key->setPressedBrush(h);
554 key->setPressedBrush(c);
586 int vel = d->m_velocity * pressure;
598 int vel = d->m_velocity * pressure;
609 if (d->m_keys.contains(note))
610 keyOn(d->m_keys.value(note));
621 if (d->m_keys.contains(note))
622 keyOff(d->m_keys.value(note));
643 PianoKey* key =
nullptr;
644 QList<QGraphicsItem *> ptitems = this->items(p, Qt::IntersectsItemShape, Qt::DescendingOrder);
645 foreach(QGraphicsItem *itm, ptitems) {
646 key =
dynamic_cast<PianoKey*
>(itm);
659 if (d->m_mouseEnabled && (mouseEvent->source() == Qt::MouseEventNotSynthesized)) {
660 if (d->m_mousePressed) {
662 PianoKey* lastkey =
getKeyForPos(mouseEvent->lastScenePos());
663 if ((lastkey !=
nullptr) && (lastkey != key) && lastkey->isPressed()) {
666 if ((key !=
nullptr) && !key->isPressed()) {
669 mouseEvent->accept();
681 if (d->m_mouseEnabled && (mouseEvent->source() == Qt::MouseEventNotSynthesized)) {
683 if (key !=
nullptr && !key->isPressed()) {
685 d->m_mousePressed =
true;
686 mouseEvent->accept();
698 if (d->m_mouseEnabled && (mouseEvent->source() == Qt::MouseEventNotSynthesized)) {
699 d->m_mousePressed =
false;
701 if (key !=
nullptr && key->isPressed()) {
703 mouseEvent->accept();
716 if (d->m_keybdMap !=
nullptr) {
717 KeyboardMap::ConstIterator it = d->m_keybdMap->constFind(key);
718 if ((it != d->m_keybdMap->constEnd()) && (it.key() == key)) {
719 int note = it.value();
734 if (d->m_keys.contains(note))
735 return d->m_keys.value(note);
745 if ( d->m_keyboardEnabled &&
746 !d->m_usingNativeFilter &&
747 !keyEvent->isAutoRepeat() )
749 int keyid = d->m_rawkbd ?
750 #if defined(Q_OS_MACOS) 751 keyEvent->nativeVirtualKey()
753 keyEvent->nativeScanCode()
772 if ( d->m_keyboardEnabled &&
773 !d->m_usingNativeFilter &&
774 !keyEvent->isAutoRepeat() )
776 int keyid = d->m_rawkbd ?
777 #if defined(Q_OS_MACOS) 778 keyEvent->nativeVirtualKey()
780 keyEvent->nativeScanCode()
801 return QGraphicsScene::event(
event);
809 foreach(PianoKey* key, d->m_keys) {
810 key->setPressed(
false);
822 if (color.isValid()) {
824 d->m_hilightPalette.setColor(0, color);
825 QBrush hilightBrush(color);
826 for (PianoKey *key : std::as_const(d->m_keys)) {
827 key->setPressedBrush(hilightBrush);
837 d->m_hilightPalette.resetColors();
839 for (PianoKey *key : std::as_const(d->m_keys)) {
840 key->setPressedBrush(hilightBrush);
858 for (PianoKey *key : std::as_const(d->m_keys)) {
859 int n = d->m_baseOctave*12 + key->getNote() + d->m_transpose;
860 bool b = !(n > d->m_maxNote) && !(n < d->m_minNote);
871 if (d->m_minNote != note) {
892 if (d->m_maxNote != note) {
904 return d->m_transpose;
913 if (d->m_baseOctave != base) {
914 d->m_baseOctave = base;
935 return d->m_startKey;
945 return (note + d->m_transpose + 12) % 12 == 0;
955 Q_ASSERT(key !=
nullptr);
956 return d->noteName(key,
true);
964 for (KeyLabel *lbl : std::as_const(d->m_labels)) {
965 PianoKey* key =
dynamic_cast<PianoKey*
>(lbl->parentItem());
966 if (key !=
nullptr) {
967 lbl->setVisible(
false);
968 lbl->setFont(font());
969 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(key->isBlack() ? 1 : 0));
970 lbl->setOrientation(d->m_orientation);
971 lbl->setHtml(d->noteName(key,
true));
973 lbl->setVisible((d->m_showLabels ==
ShowAlways) ||
984 for (PianoKey *key : std::as_const(d->m_keys)) {
985 if (d->m_showColorScale && (d->m_backgroundPalette.paletteId() ==
PAL_SCALE)) {
986 int degree = key->getNote() % 12;
987 key->setBrush(d->m_backgroundPalette.getColor(degree));
989 key->setBrush(d->m_backgroundPalette.getColor(key->isBlack() ? 1 : 0));
991 key->setPressed(
false);
1003 if (d->m_showLabels != show) {
1004 d->m_showLabels = show;
1016 return d->m_alterations;
1026 if (d->m_alterations != use) {
1027 d->m_alterations = use;
1047 if (d->m_orientation != orientation) {
1048 d->m_orientation = orientation;
1053 bool PianoScene::isKeyboardEnabled()
const 1055 return d->m_keyboardEnabled;
1060 if (d->m_octave != octave) {
1061 d->m_octave = octave;
1068 return d->m_orientation;
1077 if (d->m_transpose != transpose && transpose > -12 && transpose < 12) {
1078 d->m_transpose = transpose;
1091 return d->m_showLabels;
1100 if (d->m_rawkbd != b) {
1111 return d->m_noteNames;
1120 return d->m_names_s;
1129 return d->m_velocity;
1138 d->m_velocity = velocity;
1148 return d->m_channel;
1158 d->m_channel = channel;
1168 d->m_noteNames = names;
1178 d->m_noteNames.clear();
1188 if (enable != d->m_keyboardEnabled) {
1189 d->m_keyboardEnabled = enable;
1199 return d->m_mouseEnabled;
1208 if (enable != d->m_mouseEnabled) {
1209 d->m_mouseEnabled = enable;
1219 return d->m_touchEnabled;
1228 if (enable != d->m_touchEnabled) {
1229 d->m_touchEnabled = enable;
1239 return d->m_velocityTint;
1249 d->m_velocityTint = enable;
1257 d->m_names_s = QStringList{
1270 d->m_names_f = QStringList{
1292 if (d->m_showColorScale != show) {
1293 d->m_showColorScale = show;
1305 return d->m_hilightPalette.getColor(0);
1314 if (d->m_hilightPalette != p) {
1315 d->m_hilightPalette = p;
1327 return d->m_backgroundPalette;
1336 if (d->m_backgroundPalette != p) {
1337 d->m_backgroundPalette = p;
1349 return d->m_foregroundPalette;
1358 if (d->m_foregroundPalette != p) {
1359 d->m_foregroundPalette = p;
1371 return d->m_showColorScale;
1374 void PianoScene::setKeyPicture(
const bool natural,
const QPixmap &pix)
1376 d->m_keyPix[int(natural)] = pix;
1377 for (PianoKey *key : std::as_const(d->m_keys)) {
1378 if (key->isBlack() == !natural) {
1379 key->setPixmap(pix);
1384 QPixmap PianoScene::getKeyPicture(
const bool natural)
1386 return d->m_keyPix[int(natural)];
1389 void PianoScene::setUseKeyPictures(
const bool enable)
1391 d->m_useKeyPix = enable;
1392 for (PianoKey *key : std::as_const(d->m_keys)) {
1393 key->setUsePixmap(enable);
1397 bool PianoScene::getUseKeyPictures()
const 1399 return d->m_useKeyPix;
1402 void PianoScene::saveData(QByteArray &ba)
1407 void PianoScene::loadData(QByteArray &ba)
1419 switch(touchEvent->type()) {
1420 case QEvent::TouchEnd:
1421 case QEvent::TouchCancel:
1423 foreach(PianoKey *key, d->m_touched) {
1425 if (key->isPressed()) {
1429 d->m_touched.clear();
1430 touchEvent->accept();
1433 case QEvent::TouchBegin:
1434 case QEvent::TouchUpdate:
1436 QList<QTouchEvent::TouchPoint> touchPoints =
1437 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) 1438 touchEvent->touchPoints();
1440 touchEvent->points();
1443 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) 1444 touchEvent->device()->capabilities().testFlag(QTouchDevice::Pressure);
1446 touchEvent->device()->capabilities().testFlag(QInputDevice::Capability::Pressure);
1448 foreach(
const QTouchEvent::TouchPoint& touchPoint, touchPoints) {
1450 switch (touchPoint.state()) {
1451 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) 1452 case Qt::TouchPointReleased:
1454 case QEventPoint::Released:
1457 PianoKey* key = d->m_touched.value(touchPoint.id());
1458 if (key !=
nullptr) {
1460 if (key->isPressed()) {
1462 keyOff(key, touchPoint.pressure());
1467 d->m_touched.remove(touchPoint.id());
1471 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) 1472 case Qt::TouchPointPressed:
1474 case QEventPoint::Pressed:
1478 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
1479 touchPoint.pos().toPoint()
1481 touchPoint.position().toPoint()
1484 if (key !=
nullptr) {
1486 if (!key->isPressed()) {
1488 keyOn(key, touchPoint.pressure());
1492 key->ensureVisible();
1494 d->m_touched[touchPoint.id()] = key;
1498 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) 1499 case Qt::TouchPointMoved:
1501 case QEventPoint::Updated:
1505 #if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
1506 touchPoint.pos().toPoint()
1508 touchPoint.position().toPoint()
1511 PianoKey* lastkey = d->m_touched.value(touchPoint.id());
1512 if ((lastkey !=
nullptr) && (lastkey != key)) {
1514 if (lastkey->isPressed()) {
1516 keyOff(lastkey, touchPoint.pressure());
1521 d->m_touched.remove(touchPoint.id());
1523 if (key !=
nullptr) {
1525 if (!key->isPressed()) {
1527 keyOn(key, touchPoint.pressure());
1532 d->m_touched[touchPoint.id()] = key;
1540 touchEvent->accept();
1555 if (newState != d->m_usingNativeFilter) {
1556 d->m_usingNativeFilter = newState;
1566 return d->m_usingNativeFilter;
1575 if (d->m_octaveSubscript != enable) {
1576 d->m_octaveSubscript = enable;
1587 return d->m_octaveSubscript;
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.