| 
							- /*
 -  * Pixmap Keyboard, a custom Qt4 widget
 -  * Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.com>
 -  *
 -  * This program is free software; you can redistribute it and/or
 -  * modify it under the terms of the GNU General Public License as
 -  * published by the Free Software Foundation; either version 2 of
 -  * the License, or any later version.
 -  *
 -  * This program is distributed in the hope that it will be useful,
 -  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 -  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 -  * GNU General Public License for more details.
 -  *
 -  * For a full copy of the GNU General Public License see the doc/GPL.txt file.
 -  */
 - 
 - #include "pixmapkeyboard.hpp"
 - 
 - #include <QtCore/QTimer>
 - #include <QtGui/QKeyEvent>
 - #include <QtGui/QMouseEvent>
 - #include <QtGui/QPainter>
 - 
 - #ifndef HAVE_CPP11_SUPPORT
 - static std::map<int, QRectF> kMidiKey2RectMapHorizontal;
 - #else
 - static std::map<int, QRectF> kMidiKey2RectMapHorizontal = {
 -     {0,  QRectF(0,   0, 18, 64)}, // C
 -     {1,  QRectF(13,  0, 11, 42)}, // C#
 -     {2,  QRectF(18,  0, 25, 64)}, // D
 -     {3,  QRectF(37,  0, 11, 42)}, // D#
 -     {4,  QRectF(42,  0, 18, 64)}, // E
 -     {5,  QRectF(60,  0, 18, 64)}, // F
 -     {6,  QRectF(73,  0, 11, 42)}, // F#
 -     {7,  QRectF(78,  0, 25, 64)}, // G
 -     {8,  QRectF(97,  0, 11, 42)}, // G#
 -     {9,  QRectF(102, 0, 25, 64)}, // A
 -     {10, QRectF(121, 0, 11, 42)}, // A#
 -     {11, QRectF(126, 0, 18, 64)}  // B
 - };
 - #endif
 - 
 - #ifndef HAVE_CPP11_SUPPORT
 - static std::map<int, QRectF> kMidiKey2RectMapVertical;
 - #else
 - static std::map<int, QRectF> kMidiKey2RectMapVertical = {
 -     {11, QRectF(0,  0,  64, 18)}, // B
 -     {10, QRectF(0, 14,  42,  7)}, // A#
 -     {9,  QRectF(0, 18,  64, 24)}, // A
 -     {8,  QRectF(0, 38,  42,  7)}, // G#
 -     {7,  QRectF(0, 42,  64, 24)}, // G
 -     {6,  QRectF(0, 62,  42,  7)}, // F#
 -     {5,  QRectF(0, 66,  64, 18)}, // F
 -     {4,  QRectF(0, 84,  64, 18)}, // E
 -     {3,  QRectF(0, 98,  42,  7)}, // D#
 -     {2,  QRectF(0, 102, 64, 24)}, // D
 -     {1,  QRectF(0, 122, 42,  7)}, // C#
 -     {0,  QRectF(0, 126, 64, 18)}  // C
 - };
 - #endif
 - 
 - #ifndef HAVE_CPP11_SUPPORT
 - static std::map<int, int> kMidiKeyboard2KeyMap;
 - #else
 - static const std::map<int, int> kMidiKeyboard2KeyMap = {
 -     // 3th octave
 -     {Qt::Key_Z, 48},
 -     {Qt::Key_S, 49},
 -     {Qt::Key_X, 50},
 -     {Qt::Key_D, 51},
 -     {Qt::Key_C, 52},
 -     {Qt::Key_V, 53},
 -     {Qt::Key_G, 54},
 -     {Qt::Key_B, 55},
 -     {Qt::Key_H, 56},
 -     {Qt::Key_N, 57},
 -     {Qt::Key_J, 58},
 -     {Qt::Key_M, 59},
 -     // 4th octave
 -     {Qt::Key_Q, 60},
 -     {Qt::Key_2, 61},
 -     {Qt::Key_W, 62},
 -     {Qt::Key_3, 63},
 -     {Qt::Key_E, 64},
 -     {Qt::Key_R, 65},
 -     {Qt::Key_5, 66},
 -     {Qt::Key_T, 67},
 -     {Qt::Key_6, 68},
 -     {Qt::Key_Y, 69},
 -     {Qt::Key_7, 70},
 -     {Qt::Key_U, 71}
 - };
 - #endif
 - 
 - #ifndef HAVE_CPP11_SUPPORT
 - static QVector<int> kBlackNotes;
 - #else
 - static const QVector<int> kBlackNotes = {1, 3, 6, 8, 10};
 - #endif
 - 
 - #ifndef HAVE_CPP11_SUPPORT
 - static const struct PixmapKeyboardInit {
 -     PixmapKeyboardInit() {
 -         // kMidiKey2RectMapHorizontal
 -         kMidiKey2RectMapHorizontal[0]  = QRectF(0,   0, 18, 64); // C
 -         kMidiKey2RectMapHorizontal[1]  = QRectF(13,  0, 11, 42); // C#
 -         kMidiKey2RectMapHorizontal[2]  = QRectF(18,  0, 25, 64); // D
 -         kMidiKey2RectMapHorizontal[3]  = QRectF(37,  0, 11, 42); // D#
 -         kMidiKey2RectMapHorizontal[4]  = QRectF(42,  0, 18, 64); // E
 -         kMidiKey2RectMapHorizontal[5]  = QRectF(60,  0, 18, 64); // F
 -         kMidiKey2RectMapHorizontal[6]  = QRectF(73,  0, 11, 42); // F#
 -         kMidiKey2RectMapHorizontal[7]  = QRectF(78,  0, 25, 64); // G
 -         kMidiKey2RectMapHorizontal[8]  = QRectF(97,  0, 11, 42); // G#
 -         kMidiKey2RectMapHorizontal[9]  = QRectF(102, 0, 25, 64); // A
 -         kMidiKey2RectMapHorizontal[10] = QRectF(121, 0, 11, 42); // A#
 -         kMidiKey2RectMapHorizontal[11] = QRectF(126, 0, 18, 64); // B
 - 
 -         // kMidiKey2RectMapVertical
 -         kMidiKey2RectMapVertical[11] = QRectF(0,  0,  64, 18); // B
 -         kMidiKey2RectMapVertical[10] = QRectF(0, 14,  42,  7); // A#
 -         kMidiKey2RectMapVertical[9]  = QRectF(0, 18,  64, 24); // A
 -         kMidiKey2RectMapVertical[8]  = QRectF(0, 38,  42,  7); // G#
 -         kMidiKey2RectMapVertical[7]  = QRectF(0, 42,  64, 24); // G
 -         kMidiKey2RectMapVertical[6]  = QRectF(0, 62,  42,  7); // F#
 -         kMidiKey2RectMapVertical[5]  = QRectF(0, 66,  64, 18); // F
 -         kMidiKey2RectMapVertical[4]  = QRectF(0, 84,  64, 18); // E
 -         kMidiKey2RectMapVertical[3]  = QRectF(0, 98,  42,  7); // D#
 -         kMidiKey2RectMapVertical[2]  = QRectF(0, 102, 64, 24); // D
 -         kMidiKey2RectMapVertical[1]  = QRectF(0, 122, 42,  7); // C#
 -         kMidiKey2RectMapVertical[0]  = QRectF(0, 126, 64, 18); // C
 - 
 -         // kMidiKeyboard2KeyMap, 3th octave
 -         kMidiKeyboard2KeyMap[Qt::Key_Z] = 48;
 -         kMidiKeyboard2KeyMap[Qt::Key_S] = 49;
 -         kMidiKeyboard2KeyMap[Qt::Key_X] = 50;
 -         kMidiKeyboard2KeyMap[Qt::Key_D] = 51;
 -         kMidiKeyboard2KeyMap[Qt::Key_C] = 52;
 -         kMidiKeyboard2KeyMap[Qt::Key_V] = 53;
 -         kMidiKeyboard2KeyMap[Qt::Key_G] = 54;
 -         kMidiKeyboard2KeyMap[Qt::Key_B] = 55;
 -         kMidiKeyboard2KeyMap[Qt::Key_H] = 56;
 -         kMidiKeyboard2KeyMap[Qt::Key_N] = 57;
 -         kMidiKeyboard2KeyMap[Qt::Key_J] = 58;
 -         kMidiKeyboard2KeyMap[Qt::Key_M] = 59;
 -         // kMidiKeyboard2KeyMap, 4th octave
 -         kMidiKeyboard2KeyMap[Qt::Key_Q] = 60;
 -         kMidiKeyboard2KeyMap[Qt::Key_2] = 61;
 -         kMidiKeyboard2KeyMap[Qt::Key_W] = 62;
 -         kMidiKeyboard2KeyMap[Qt::Key_3] = 63;
 -         kMidiKeyboard2KeyMap[Qt::Key_E] = 64;
 -         kMidiKeyboard2KeyMap[Qt::Key_R] = 65;
 -         kMidiKeyboard2KeyMap[Qt::Key_5] = 66;
 -         kMidiKeyboard2KeyMap[Qt::Key_T] = 67;
 -         kMidiKeyboard2KeyMap[Qt::Key_6] = 68;
 -         kMidiKeyboard2KeyMap[Qt::Key_Y] = 69;
 -         kMidiKeyboard2KeyMap[Qt::Key_7] = 70;
 -         kMidiKeyboard2KeyMap[Qt::Key_U] = 71;
 - 
 -         // kBlackNotes
 -         kBlackNotes << 1;
 -         kBlackNotes << 3;
 -         kBlackNotes << 6;
 -         kBlackNotes << 8;
 -         kBlackNotes << 10;
 -     }
 - } _pixmapKeyboardInitInit;
 - #endif
 - 
 - PixmapKeyboard::PixmapKeyboard(QWidget* parent)
 -     : QWidget(parent),
 -       fPixmap(""),
 -       fPixmapMode(HORIZONTAL),
 -       fColorStr("orange"),
 -       fFont("Monospace", 7, QFont::Normal),
 -       fOctaves(6),
 -       fLastMouseNote(-1),
 -       fWidth(0),
 -       fHeight(0),
 -       fMidiMap(kMidiKey2RectMapHorizontal)
 - {
 -     setCursor(Qt::PointingHandCursor);
 -     setMode(HORIZONTAL);
 - }
 - 
 - void PixmapKeyboard::allNotesOff()
 - {
 -     fEnabledKeys.clear();
 - 
 -     emit notesOff();
 -     update();
 - }
 - 
 - void PixmapKeyboard::sendNoteOn(int note, bool sendSignal)
 - {
 -     if (0 <= note && note <= 127 && ! fEnabledKeys.contains(note))
 -     {
 -         fEnabledKeys.append(note);
 - 
 -         if (sendSignal)
 -             emit noteOn(note);
 - 
 -         update();
 -     }
 - 
 -     if (fEnabledKeys.count() == 1)
 -         emit notesOn();
 - }
 - 
 - void PixmapKeyboard::sendNoteOff(int note, bool sendSignal)
 - {
 -     if (note >= 0 && note <= 127 && fEnabledKeys.contains(note))
 -     {
 -         fEnabledKeys.removeOne(note);
 - 
 -         if (sendSignal)
 -             emit noteOff(note);
 - 
 -         update();
 -     }
 - 
 -     if (fEnabledKeys.count() == 0)
 -         emit notesOff();
 - }
 - 
 - void PixmapKeyboard::setMode(Orientation mode, Color color)
 - {
 -     if (color == COLOR_CLASSIC)
 -     {
 -         fColorStr = "classic";
 -     }
 -     else if (color == COLOR_ORANGE)
 -     {
 -         fColorStr = "orange";
 -     }
 -     else
 -     {
 -         qCritical("PixmapKeyboard::setMode(%i, %i) - invalid color", mode, color);
 -         return setMode(mode);
 -     }
 - 
 -     if (mode == HORIZONTAL)
 -     {
 -         fMidiMap = kMidiKey2RectMapHorizontal;
 -         fPixmap.load(QString(":/bitmaps/kbd_h_%1.png").arg(fColorStr));
 -         fPixmapMode = HORIZONTAL;
 -         fWidth  = fPixmap.width();
 -         fHeight = fPixmap.height() / 2;
 -     }
 -     else if (mode == VERTICAL)
 -     {
 -         fMidiMap = kMidiKey2RectMapVertical;
 -         fPixmap.load(QString(":/bitmaps/kbd_v_%1.png").arg(fColorStr));
 -         fPixmapMode = VERTICAL;
 -         fWidth  = fPixmap.width() / 2;
 -         fHeight = fPixmap.height();
 -     }
 -     else
 -     {
 -         qCritical("PixmapKeyboard::setMode(%i, %i) - invalid mode", mode, color);
 -         return setMode(HORIZONTAL);
 -     }
 - 
 -     setOctaves(fOctaves);
 - }
 - 
 - void PixmapKeyboard::setOctaves(int octaves)
 - {
 -     Q_ASSERT(octaves >= 1 && octaves <= 10);
 - 
 -     if (octaves < 1)
 -         octaves = 1;
 -     else if (octaves > 10)
 -         octaves = 10;
 - 
 -     fOctaves = octaves;
 - 
 -     if (fPixmapMode == HORIZONTAL)
 -     {
 -         setMinimumSize(fWidth * fOctaves, fHeight);
 -         setMaximumSize(fWidth * fOctaves, fHeight);
 -     }
 -     else if (fPixmapMode == VERTICAL)
 -     {
 -         setMinimumSize(fWidth, fHeight * fOctaves);
 -         setMaximumSize(fWidth, fHeight * fOctaves);
 -     }
 - 
 -     update();
 - }
 - 
 - void PixmapKeyboard::handleMousePos(const QPoint& pos)
 - {
 -     int note, octave;
 -     QPointF keyPos;
 - 
 -     if (fPixmapMode == HORIZONTAL)
 -     {
 -         if (pos.x() < 0 or pos.x() > fOctaves * 144)
 -             return;
 -         int posX = pos.x() - 1;
 -         octave = posX / fWidth;
 -         keyPos = QPointF(posX % fWidth, pos.y());
 -     }
 -     else if (fPixmapMode == VERTICAL)
 -     {
 -         if (pos.y() < 0 or pos.y() > fOctaves * 144)
 -             return;
 -         int posY = pos.y() - 1;
 -         octave = fOctaves - posY / fHeight;
 -         keyPos = QPointF(pos.x(), posY % fHeight);
 -     }
 -     else
 -         return;
 - 
 -     if (fMidiMap[1].contains(keyPos))      // C#
 -         note = 1;
 -     else if (fMidiMap[3].contains(keyPos)) // D#
 -         note = 3;
 -     else if (fMidiMap[6].contains(keyPos)) // F#
 -         note = 6;
 -     else if (fMidiMap[8].contains(keyPos)) // G#
 -         note = 8;
 -     else if (fMidiMap[10].contains(keyPos))// A#
 -         note = 10;
 -     else if (fMidiMap[0].contains(keyPos)) // C
 -         note = 0;
 -     else if (fMidiMap[2].contains(keyPos)) // D
 -         note = 2;
 -     else if (fMidiMap[4].contains(keyPos)) // E
 -         note = 4;
 -     else if (fMidiMap[5].contains(keyPos)) // F
 -         note = 5;
 -     else if (fMidiMap[7].contains(keyPos)) // G
 -         note = 7;
 -     else if (fMidiMap[9].contains(keyPos)) // A
 -         note = 9;
 -     else if (fMidiMap[11].contains(keyPos))// B
 -         note = 11;
 -     else
 -         note = -1;
 - 
 -     if (note != -1)
 -     {
 -         note += octave * 12;
 - 
 -         if (fLastMouseNote != note)
 -         {
 -             sendNoteOff(fLastMouseNote);
 -             sendNoteOn(note);
 -         }
 -     }
 -     else if (fLastMouseNote != -1)
 -         sendNoteOff(fLastMouseNote);
 - 
 -     fLastMouseNote = note;
 - }
 - 
 - void PixmapKeyboard::keyPressEvent(QKeyEvent* event)
 - {
 -     if (! event->isAutoRepeat())
 -     {
 -         int qKey = event->key();
 -         std::map<int, int>::const_iterator it = kMidiKeyboard2KeyMap.find(qKey);
 -         if (it != kMidiKeyboard2KeyMap.end())
 -             sendNoteOn(it->second);
 -     }
 -     QWidget::keyPressEvent(event);
 - }
 - 
 - void PixmapKeyboard::keyReleaseEvent(QKeyEvent* event)
 - {
 -     if (! event->isAutoRepeat())
 -     {
 -         int qKey = event->key();
 -         std::map<int, int>::const_iterator it = kMidiKeyboard2KeyMap.find(qKey);
 -         if (it != kMidiKeyboard2KeyMap.end())
 -             sendNoteOff(it->second);
 -     }
 -     QWidget::keyReleaseEvent(event);
 - }
 - 
 - void PixmapKeyboard::mousePressEvent(QMouseEvent* event)
 - {
 -     fLastMouseNote = -1;
 -     handleMousePos(event->pos());
 -     setFocus();
 -     QWidget::mousePressEvent(event);
 - }
 - 
 - void PixmapKeyboard::mouseMoveEvent(QMouseEvent* event)
 - {
 -     handleMousePos(event->pos());
 -     QWidget::mouseMoveEvent(event);
 - }
 - 
 - void PixmapKeyboard::mouseReleaseEvent(QMouseEvent* event)
 - {
 -     if (fLastMouseNote != -1)
 -     {
 -         sendNoteOff(fLastMouseNote);
 -         fLastMouseNote = -1;
 -     }
 -     QWidget::mouseReleaseEvent(event);
 - }
 - 
 - void PixmapKeyboard::paintEvent(QPaintEvent* event)
 - {
 -     QPainter painter(this);
 -     event->accept();
 - 
 -     // -------------------------------------------------------------
 -     // Paint clean keys (as background)
 - 
 -     for (int octave=0; octave < fOctaves; ++octave)
 -     {
 -         QRectF target;
 - 
 -         if (fPixmapMode == HORIZONTAL)
 -             target = QRectF(fWidth * octave, 0, fWidth, fHeight);
 -         else if (fPixmapMode == VERTICAL)
 -             target = QRectF(0, fHeight * octave, fWidth, fHeight);
 -         else
 -             return;
 - 
 -         QRectF source = QRectF(0, 0, fWidth, fHeight);
 -         painter.drawPixmap(target, fPixmap, source);
 -     }
 - 
 -     // -------------------------------------------------------------
 -     // Paint (white) pressed keys
 - 
 -     bool paintedWhite = false;
 - 
 -     for (int i=0, count=fEnabledKeys.count(); i < count; ++i)
 -     {
 -         int octave, note = fEnabledKeys[i];
 -         const QRectF& pos(_getRectFromMidiNote(note));
 - 
 -         if (_isNoteBlack(note))
 -             continue;
 - 
 -         if (note < 12)
 -             octave = 0;
 -         else if (note < 24)
 -             octave = 1;
 -         else if (note < 36)
 -             octave = 2;
 -         else if (note < 48)
 -             octave = 3;
 -         else if (note < 60)
 -             octave = 4;
 -         else if (note < 72)
 -             octave = 5;
 -         else if (note < 84)
 -             octave = 6;
 -         else if (note < 96)
 -             octave = 7;
 -         else if (note < 108)
 -             octave = 8;
 -         else if (note < 120)
 -             octave = 9;
 -         else if (note < 132)
 -             octave = 10;
 -         else
 -             // cannot paint this note
 -             continue;
 - 
 -         if (fPixmapMode == VERTICAL)
 -             octave = fOctaves - octave - 1;
 - 
 -         QRectF target, source;
 - 
 -         if (fPixmapMode == HORIZONTAL)
 -         {
 -             target = QRectF(pos.x() + (fWidth * octave), 0, pos.width(), pos.height());
 -             source = QRectF(pos.x(), fHeight, pos.width(), pos.height());
 -         }
 -         else if (fPixmapMode == VERTICAL)
 -         {
 -             target = QRectF(pos.x(), pos.y() + (fHeight * octave), pos.width(), pos.height());
 -             source = QRectF(fWidth, pos.y(), pos.width(), pos.height());
 -         }
 -         else
 -             return;
 - 
 -         paintedWhite = true;
 -         painter.drawPixmap(target, fPixmap, source);
 -     }
 - 
 -     // -------------------------------------------------------------
 -     // Clear white keys border
 - 
 -     if (paintedWhite)
 -     {
 -         for (int octave=0; octave < fOctaves; ++octave)
 -         {
 -             foreach (int note, kBlackNotes)
 -             {
 -                 QRectF target, source;
 -                 const QRectF& pos(_getRectFromMidiNote(note));
 - 
 -                 if (fPixmapMode == HORIZONTAL)
 -                 {
 -                     target = QRectF(pos.x() + (fWidth * octave), 0, pos.width(), pos.height());
 -                     source = QRectF(pos.x(), 0, pos.width(), pos.height());
 -                 }
 -                 else if (fPixmapMode == VERTICAL)
 -                 {
 -                     target = QRectF(pos.x(), pos.y() + (fHeight * octave), pos.width(), pos.height());
 -                     source = QRectF(0, pos.y(), pos.width(), pos.height());
 -                 }
 -                 else
 -                     return;
 - 
 -                 painter.drawPixmap(target, fPixmap, source);
 -             }
 -         }
 -     }
 - 
 -     // -------------------------------------------------------------
 -     // Paint (black) pressed keys
 - 
 -     for (int i=0, count=fEnabledKeys.count(); i < count; ++i)
 -     {
 -         int octave, note = fEnabledKeys[i];
 -         const QRectF& pos(_getRectFromMidiNote(note));
 - 
 -         if (! _isNoteBlack(note))
 -             continue;
 - 
 -         if (note < 12)
 -             octave = 0;
 -         else if (note < 24)
 -             octave = 1;
 -         else if (note < 36)
 -             octave = 2;
 -         else if (note < 48)
 -             octave = 3;
 -         else if (note < 60)
 -             octave = 4;
 -         else if (note < 72)
 -             octave = 5;
 -         else if (note < 84)
 -             octave = 6;
 -         else if (note < 96)
 -             octave = 7;
 -         else if (note < 108)
 -             octave = 8;
 -         else if (note < 120)
 -             octave = 9;
 -         else if (note < 132)
 -             octave = 10;
 -         else
 -             // cannot paint this note
 -             continue;
 - 
 -         if (fPixmapMode == VERTICAL)
 -             octave = fOctaves - octave - 1;
 - 
 -         QRectF target, source;
 - 
 -         if (fPixmapMode == HORIZONTAL)
 -         {
 -             target = QRectF(pos.x() + (fWidth * octave), 0, pos.width(), pos.height());
 -             source = QRectF(pos.x(), fHeight, pos.width(), pos.height());
 -         }
 -         else if (fPixmapMode == VERTICAL)
 -         {
 -             target = QRectF(pos.x(), pos.y() + (fHeight * octave), pos.width(), pos.height());
 -             source = QRectF(fWidth, pos.y(), pos.width(), pos.height());
 -         }
 -         else
 -             return;
 - 
 -         painter.drawPixmap(target, fPixmap, source);
 -     }
 - 
 -     // Paint C-number note info
 -     painter.setFont(fFont);
 -     painter.setPen(Qt::black);
 - 
 -     for (int i=0; i < fOctaves; ++i)
 -     {
 -         if (fPixmapMode == HORIZONTAL)
 -             painter.drawText(i * 144, 48, 18, 18, Qt::AlignCenter, QString("C%1").arg(i-1));
 -         else if (fPixmapMode == VERTICAL)
 -             painter.drawText(45, (fOctaves * 144) - (i * 144) - 16, 18, 18, Qt::AlignCenter, QString("C%1").arg(i-1));
 -     }
 - }
 - 
 - bool PixmapKeyboard::_isNoteBlack(int note) const
 - {
 -     const int baseNote = note % 12;
 -     return kBlackNotes.contains(baseNote);
 - }
 - 
 - const QRectF& PixmapKeyboard::_getRectFromMidiNote(int note) const
 - {
 -     const int baseNote = note % 12;
 -     return fMidiMap[baseNote];
 - }
 
 
  |