19 #include <QApplication> 20 #include <QGraphicsSceneMouseEvent> 40 class PianoScene::PianoScenePrivate
57 m_keyboardEnabled( true ),
58 m_mouseEnabled( true ),
59 m_touchEnabled( true ),
60 m_mousePressed( false ),
63 m_velocityTint( true ),
65 m_keybdMap( nullptr ),
66 m_showColorScale( false ),
68 m_backgroundPalette(PianoPalette(
PAL_KEYS)),
69 m_foregroundPalette(PianoPalette(
PAL_FONT))
82 bool m_keyboardEnabled;
89 PianoHandler *m_handler;
91 QHash<int, PianoKey *> m_keys;
92 QMap<int, KeyLabel *> m_labels;
93 QStringList m_noteNames;
94 QStringList m_names_s;
95 QStringList m_names_f;
96 bool m_showColorScale;
97 PianoPalette m_hilightPalette;
98 PianoPalette m_backgroundPalette;
99 PianoPalette m_foregroundPalette;
102 const int KEYWIDTH = 180;
103 const int KEYHEIGHT = 720;
105 static qreal sceneWidth(
int keys) {
106 return KEYWIDTH * qCeil( keys * 7.0 / 12.0 );
120 const QColor& keyPressedColor,
122 :
QGraphicsScene( QRectF(0, 0, sceneWidth(numKeys), KEYHEIGHT), parent ),
123 d(new PianoScenePrivate(baseOctave, numKeys, startKey))
125 if (keyPressedColor.isValid()) {
130 if (view !=
nullptr) {
131 setFont(view->font());
133 int upperLimit = d->m_numKeys + d->m_startKey;
134 int adj = d->m_startKey % 12;
136 for(
int i = d->m_startKey; i < upperLimit; ++i)
139 PianoKey* key =
nullptr;
140 KeyLabel* lbl =
nullptr;
141 int ocs = i / 12 * 7;
145 x = (ocs + qFloor((j-adj) / 2.0)) * KEYWIDTH;
146 key =
new PianoKey( QRectF(x, 0, KEYWIDTH, KEYHEIGHT),
false, i );
147 lbl =
new KeyLabel(key);
148 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(0));
150 x = (ocs + qFloor((j-adj) / 2.0)) * KEYWIDTH + KEYWIDTH * 0.6 + 1;
151 key =
new PianoKey( QRectF( x, 0, KEYWIDTH * 0.8 - 1, KEYHEIGHT * 0.6 ),
true, i );
153 lbl =
new KeyLabel(key);
154 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(1));
157 lbl->setFont(font());
158 key->setAcceptTouchEvents(
true);
159 key->setPressedBrush(hilightBrush);
160 d->m_keys.insert(i, key);
161 d->m_labels.insert(i, lbl);
179 return {
static_cast<int>(sceneWidth(d->m_numKeys)), KEYHEIGHT};
197 return d->m_keybdMap;
222 d->m_handler = handler;
231 return d->m_hilightPalette;
240 key->setPressed(
true);
241 int n = key->getNote() + d->m_baseOctave*12 + d->m_transpose;
242 QString s = QString(
"#%1 (%2)").arg(n).arg(
noteName(key));
244 KeyLabel* lbl =
dynamic_cast<KeyLabel*
>(key->childItems().constFirst());
245 if (lbl !=
nullptr) {
246 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(key->isBlack() ? 3 : 2));
248 lbl->setVisible(
true);
261 if (d->m_velocityTint && vel >= 0 && color.isValid() ) {
262 QBrush hilightBrush(color.lighter(200 - vel));
263 key->setPressedBrush(hilightBrush);
287 key->setPressed(
false);
289 KeyLabel* lbl =
dynamic_cast<KeyLabel*
>(key->childItems().constFirst());
290 if (lbl !=
nullptr) {
293 lbl->setVisible(
false);
306 int n = note - d->m_baseOctave*12 - d->m_transpose;
307 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n) && color.isValid())
308 showKeyOn(d->m_keys.value(n), color, vel);
318 int n = note - d->m_baseOctave*12 - d->m_transpose;
319 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n)) {
331 int n = note - d->m_baseOctave*12 - d->m_transpose;
332 if ((note >= d->m_minNote) && (note <= d->m_maxNote) && d->m_keys.contains(n)) {
353 int n = d->m_baseOctave*12 + note + d->m_transpose;
354 if ((n >= d->m_minNote) && (n <= d->m_maxNote)) {
355 if (d->m_handler !=
nullptr) {
356 d->m_handler->noteOn(n, vel);
372 int n = d->m_baseOctave*12 + note + d->m_transpose;
373 if ((n >= d->m_minNote) && (n <= d->m_maxNote)) {
374 if (d->m_handler !=
nullptr) {
375 d->m_handler->noteOff(n, vel);
391 switch (d->m_hilightPalette.paletteId()) {
393 c = d->m_hilightPalette.getColor(0);
396 c = d->m_hilightPalette.getColor(key->getType());
399 c = d->m_hilightPalette.getColor(d->m_channel);
405 if (d->m_velocityTint) {
406 QBrush h(c.lighter(200 - vel));
407 key->setPressedBrush(h);
409 key->setPressedBrush(c);
441 int vel = d->m_velocity * pressure;
453 int vel = d->m_velocity * pressure;
464 if (d->m_keys.contains(note))
465 keyOn(d->m_keys.value(note));
476 if (d->m_keys.contains(note))
477 keyOff(d->m_keys.value(note));
498 PianoKey* key =
nullptr;
499 QList<QGraphicsItem *> ptitems = this->items(p, Qt::IntersectsItemShape, Qt::DescendingOrder);
500 foreach(QGraphicsItem *itm, ptitems) {
501 key =
dynamic_cast<PianoKey*
>(itm);
514 if (d->m_mouseEnabled) {
515 if (d->m_mousePressed) {
517 PianoKey* lastkey =
getKeyForPos(mouseEvent->lastScenePos());
518 if ((lastkey !=
nullptr) && (lastkey != key) && lastkey->isPressed()) {
521 if ((key !=
nullptr) && !key->isPressed()) {
524 mouseEvent->accept();
536 if (d->m_mouseEnabled) {
538 if (key !=
nullptr && !key->isPressed()) {
540 d->m_mousePressed =
true;
541 mouseEvent->accept();
553 if (d->m_mouseEnabled) {
554 d->m_mousePressed =
false;
556 if (key !=
nullptr && key->isPressed()) {
558 mouseEvent->accept();
571 if (d->m_keybdMap !=
nullptr) {
572 KeyboardMap::ConstIterator it = d->m_keybdMap->constFind(key);
573 if ((it != d->m_keybdMap->constEnd()) && (it.key() == key)) {
574 int note = it.value();
589 if (d->m_keys.contains(note))
590 return d->m_keys.value(note);
600 if ( d->m_keyboardEnabled) {
601 if ( !d->m_rawkbd && !keyEvent->isAutoRepeat() ) {
618 if (d->m_keyboardEnabled) {
619 if ( !d->m_rawkbd && !keyEvent->isAutoRepeat() ) {
637 switch(
event->type()) {
638 case QEvent::TouchBegin:
639 case QEvent::TouchEnd:
640 case QEvent::TouchUpdate:
642 QTouchEvent *touchEvent =
static_cast<QTouchEvent*
>(
event);
643 if (d->m_touchEnabled && touchEvent->device()->type() == QTouchDevice::DeviceType::TouchScreen) {
644 QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
645 foreach(
const QTouchEvent::TouchPoint& touchPoint, touchPoints) {
646 switch (touchPoint.state()) {
648 case Qt::TouchPointStationary:
650 case Qt::TouchPointReleased: {
652 if (key !=
nullptr && key->isPressed()) {
653 keyOff(key, touchPoint.pressure());
657 case Qt::TouchPointPressed: {
659 if (key !=
nullptr && !key->isPressed()) {
660 keyOn(key, touchPoint.pressure());
661 key->ensureVisible();
665 case Qt::TouchPointMoved: {
667 PianoKey* lastkey =
getKeyForPos(touchPoint.lastScenePos());
668 if ((lastkey !=
nullptr) && (lastkey != key) && lastkey->isPressed()) {
669 keyOff(lastkey, touchPoint.pressure());
671 if ((key !=
nullptr) && !key->isPressed()) {
672 keyOn(key, touchPoint.pressure());
691 return QGraphicsScene::event(
event);
699 foreach(PianoKey* key, d->m_keys) {
700 key->setPressed(
false);
712 if (color.isValid()) {
714 d->m_hilightPalette.setColor(0, color);
715 QBrush hilightBrush(color);
716 for (PianoKey* key : qAsConst(d->m_keys)) {
717 key->setPressedBrush(hilightBrush);
727 d->m_hilightPalette.resetColors();
729 for (PianoKey* key : qAsConst(d->m_keys)) {
730 key->setPressedBrush(hilightBrush);
748 for (PianoKey* key : qAsConst(d->m_keys)) {
749 int n = d->m_baseOctave*12 + key->getNote() + d->m_transpose;
750 bool b = !(n > d->m_maxNote) && !(n < d->m_minNote);
761 if (d->m_minNote != note) {
782 if (d->m_maxNote != note) {
794 return d->m_transpose;
803 if (d->m_baseOctave != base) {
804 d->m_baseOctave = base;
825 return d->m_startKey;
835 return (note + d->m_transpose + 12) % 12 == 0;
845 Q_ASSERT(key !=
nullptr);
846 int note = key->getNote();
847 int num = (note + d->m_transpose + 12) % 12;
848 int adj = ((note + d->m_transpose < 0) ? 2 : 1) - d->m_octave + 1;
849 int oct = d->m_baseOctave + ((note + d->m_transpose) / 12) - adj;
850 if (d->m_noteNames.isEmpty()) {
852 if (!d->m_names_f.isEmpty() && !d->m_names_s.isEmpty()) {
853 switch(d->m_alterations) {
855 name = d->m_names_f.value(num);
858 name = d->m_names_s.value(num);
861 if (key->isBlack()) {
864 name = d->m_names_s.value(num);
873 return QString(
"%1%2").arg(name).arg(oct);
876 if (d->m_noteNames.length() == 128) {
877 int n = d->m_baseOctave*12 + note + d->m_transpose;
879 if (n >= 0 && n < d->m_noteNames.length()) {
880 return d->m_noteNames.value(n);
882 }
else if (d->m_noteNames.length() >= 12) {
884 return d->m_noteNames.value(num);
886 return QString(
"%1%2").arg(d->m_noteNames.value(num)).arg(oct);
898 for (KeyLabel* lbl : qAsConst(d->m_labels)) {
899 PianoKey* key =
dynamic_cast<PianoKey*
>(lbl->parentItem());
900 if (key !=
nullptr) {
901 lbl->setVisible(
false);
902 lbl->setFont(font());
903 lbl->setDefaultTextColor(d->m_foregroundPalette.getColor(key->isBlack() ? 1 : 0));
904 lbl->setOrientation(d->m_orientation);
907 lbl->setVisible((d->m_showLabels ==
ShowAlways) ||
918 for (PianoKey* key : qAsConst(d->m_keys)) {
919 if (d->m_showColorScale && (d->m_backgroundPalette.paletteId() ==
PAL_SCALE)) {
920 int degree = key->getNote() % 12;
921 key->setBrush(d->m_backgroundPalette.getColor(degree));
923 key->setBrush(d->m_backgroundPalette.getColor(key->isBlack() ? 1 : 0));
925 key->setPressed(
false);
937 if (d->m_showLabels != show) {
938 d->m_showLabels = show;
950 return d->m_alterations;
960 if (d->m_alterations != use) {
961 d->m_alterations = use;
981 if (d->m_orientation != orientation) {
982 d->m_orientation = orientation;
987 bool PianoScene::isKeyboardEnabled()
const 989 return d->m_keyboardEnabled;
994 if (d->m_octave != octave) {
995 d->m_octave = octave;
1002 return d->m_orientation;
1011 if (d->m_transpose != transpose && transpose > -12 && transpose < 12) {
1012 d->m_transpose = transpose;
1025 return d->m_showLabels;
1034 if (d->m_rawkbd != b) {
1045 return d->m_noteNames;
1054 return d->m_names_s;
1063 return d->m_velocity;
1072 d->m_velocity = velocity;
1082 return d->m_channel;
1092 d->m_channel = channel;
1102 d->m_noteNames = names;
1112 d->m_noteNames.clear();
1122 if (enable != d->m_keyboardEnabled) {
1123 d->m_keyboardEnabled = enable;
1133 return d->m_mouseEnabled;
1142 if (enable != d->m_mouseEnabled) {
1143 d->m_mouseEnabled = enable;
1153 return d->m_touchEnabled;
1162 if (enable != d->m_touchEnabled) {
1163 d->m_touchEnabled = enable;
1173 return d->m_velocityTint;
1182 d->m_velocityTint = enable;
1190 d->m_names_s = QStringList{
1203 d->m_names_f = QStringList{
1225 if (d->m_showColorScale != show) {
1226 d->m_showColorScale = show;
1238 return d->m_hilightPalette.getColor(0);
1247 if (d->m_hilightPalette != p) {
1248 d->m_hilightPalette = p;
1260 return d->m_backgroundPalette;
1269 if (d->m_backgroundPalette != p) {
1270 d->m_backgroundPalette = p;
1282 return d->m_foregroundPalette;
1291 if (d->m_foregroundPalette != p) {
1292 d->m_foregroundPalette = p;
1304 return d->m_showColorScale;
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.