You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
298 lines
8.1 KiB
298 lines
8.1 KiB
/*
|
|
Rosegarden
|
|
A MIDI and audio sequencer and musical notation editor.
|
|
|
|
This program is Copyright 2000-2008
|
|
Guillaume Laurent <glaurent@telegraph-road.org>,
|
|
Chris Cannam <cannam@all-day-breakfast.com>,
|
|
Richard Bown <richard.bown@ferventsoftware.com>
|
|
|
|
The moral rights of Guillaume Laurent, Chris Cannam, and Richard
|
|
Bown to claim authorship of this work have been asserted.
|
|
|
|
Other copyrights also apply to some parts of this work. Please
|
|
see the AUTHORS file and individual file headers for details.
|
|
|
|
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 (at your option) any later version. See the file
|
|
COPYING included with this distribution for more information.
|
|
*/
|
|
|
|
|
|
#include "PianoKeyboard.h"
|
|
#include "misc/Debug.h"
|
|
|
|
#include "gui/general/GUIPalette.h"
|
|
#include "gui/general/MidiPitchLabel.h"
|
|
#include "gui/rulers/PitchRuler.h"
|
|
#include "MatrixStaff.h"
|
|
#include "MatrixView.h"
|
|
#include <tqcolor.h>
|
|
#include <tqcursor.h>
|
|
#include <tqevent.h>
|
|
#include <tqfont.h>
|
|
#include <tqpainter.h>
|
|
#include <tqsize.h>
|
|
#include <tqwidget.h>
|
|
|
|
|
|
namespace Rosegarden
|
|
{
|
|
|
|
const unsigned int _smallWhiteKeyHeight = 14;
|
|
const unsigned int _whiteKeyHeight = 18;
|
|
|
|
PianoKeyboard::PianoKeyboard(TQWidget *parent, int keys)
|
|
: PitchRuler(parent),
|
|
m_keySize(48, 18),
|
|
m_blackKeySize(24, 8),
|
|
m_nbKeys(keys),
|
|
m_mouseDown(false),
|
|
m_hoverHighlight(new TQWidget(this)),
|
|
m_lastHoverHighlight(0),
|
|
m_lastKeyPressed(0)
|
|
{
|
|
m_hoverHighlight->hide();
|
|
m_hoverHighlight->setPaletteBackgroundColor(GUIPalette::getColour(GUIPalette::MatrixKeyboardFocus));
|
|
|
|
setPaletteBackgroundColor(TQColor(238, 238, 224));
|
|
|
|
computeKeyPos();
|
|
setMouseTracking(true);
|
|
}
|
|
|
|
TQSize PianoKeyboard::sizeHint() const
|
|
{
|
|
return TQSize(m_keySize.width(),
|
|
m_keySize.height() * m_nbKeys);
|
|
}
|
|
|
|
TQSize PianoKeyboard::minimumSizeHint() const
|
|
{
|
|
return m_keySize;
|
|
}
|
|
|
|
void PianoKeyboard::computeKeyPos()
|
|
{
|
|
// int y = -9;
|
|
int y = -4;
|
|
|
|
unsigned int posInOctave = 0,
|
|
keyHeight = _smallWhiteKeyHeight;
|
|
|
|
for (unsigned int i = 0; i < m_nbKeys; ++i) {
|
|
posInOctave = (i + 5) % 7;
|
|
|
|
if (y >= 0) {
|
|
m_whiteKeyPos.push_back(y);
|
|
m_allKeyPos.push_back(y);
|
|
}
|
|
|
|
if (posInOctave == 2)
|
|
m_labelKeyPos.push_back(y + (keyHeight * 3 / 4) - 2);
|
|
|
|
if (posInOctave == 0 ||
|
|
posInOctave == 2 ||
|
|
posInOctave == 6 ||
|
|
posInOctave == 3) { // draw shorter white key
|
|
|
|
|
|
keyHeight = _smallWhiteKeyHeight;
|
|
|
|
if (posInOctave == 2 ||
|
|
posInOctave == 6)
|
|
--keyHeight;
|
|
|
|
} else {
|
|
|
|
keyHeight = _whiteKeyHeight;
|
|
}
|
|
|
|
if (posInOctave != 2 && posInOctave != 6) { // draw black key
|
|
|
|
unsigned int bY = y + keyHeight - m_blackKeySize.height() / 2;
|
|
|
|
m_blackKeyPos.push_back(bY);
|
|
m_allKeyPos.push_back(bY);
|
|
|
|
}
|
|
|
|
y += keyHeight;
|
|
}
|
|
}
|
|
|
|
void PianoKeyboard::paintEvent(TQPaintEvent*)
|
|
{
|
|
static TQFont *pFont = 0;
|
|
if (!pFont) {
|
|
pFont = new TQFont();
|
|
pFont->setPixelSize(9);
|
|
}
|
|
|
|
TQPainter paint(this);
|
|
|
|
paint.setFont(*pFont);
|
|
|
|
for (unsigned int i = 0; i < m_whiteKeyPos.size(); ++i)
|
|
paint.drawLine(0, m_whiteKeyPos[i],
|
|
m_keySize.width(), m_whiteKeyPos[i]);
|
|
|
|
for (unsigned int i = 0; i < m_labelKeyPos.size(); ++i) {
|
|
|
|
int pitch = (m_labelKeyPos.size() - i) * 12;
|
|
|
|
// for some reason I don't immediately comprehend,
|
|
// m_labelKeyPos contains two more octaves than we need
|
|
pitch -= 24;
|
|
|
|
MidiPitchLabel label(pitch);
|
|
paint.drawText(m_blackKeySize.width(), m_labelKeyPos[i],
|
|
label.getTQString());
|
|
}
|
|
|
|
paint.setBrush(colorGroup().foreground());
|
|
|
|
for (unsigned int i = 0; i < m_blackKeyPos.size(); ++i)
|
|
paint.drawRect(0, m_blackKeyPos[i],
|
|
m_blackKeySize.width(), m_blackKeySize.height());
|
|
}
|
|
|
|
void PianoKeyboard::enterEvent(TQEvent *)
|
|
{
|
|
//drawHoverNote(e->y());
|
|
}
|
|
|
|
void PianoKeyboard::leaveEvent(TQEvent*)
|
|
{
|
|
m_hoverHighlight->hide();
|
|
|
|
int pos = mapFromGlobal( cursor().pos() ).x();
|
|
if ( pos > m_keySize.width() - 5 || pos < 0 ) { // bit of a hack
|
|
emit keyReleased(m_lastKeyPressed, false);
|
|
}
|
|
}
|
|
|
|
void PianoKeyboard::drawHoverNote(int evPitch)
|
|
{
|
|
if (m_lastHoverHighlight != evPitch) {
|
|
//MATRIX_DEBUG << "PianoKeyboard::drawHoverNote : note = " << evPitch << endl;
|
|
m_lastHoverHighlight = evPitch;
|
|
|
|
int count = 0;
|
|
std::vector<unsigned int>::iterator it;
|
|
for (it = m_allKeyPos.begin(); it != m_allKeyPos.end(); ++it, ++count) {
|
|
if (126 - evPitch == count) {
|
|
int width = m_keySize.width() - 8;
|
|
int yPos = *it + 5;
|
|
|
|
// check if this is a black key
|
|
//
|
|
std::vector<unsigned int>::iterator bIt;
|
|
bool isBlack = false;
|
|
for (bIt = m_blackKeyPos.begin(); bIt != m_blackKeyPos.end(); ++bIt) {
|
|
if (*bIt == *it) {
|
|
isBlack = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Adjust for black note
|
|
//
|
|
if (isBlack) {
|
|
width = m_blackKeySize.width() - 8;
|
|
yPos -= 3;
|
|
} else {
|
|
// If a white note then ensure that we allow for short/tall ones
|
|
//
|
|
std::vector<unsigned int>::iterator wIt = m_whiteKeyPos.begin(), tIt;
|
|
|
|
while (wIt != m_whiteKeyPos.end()) {
|
|
if (*wIt == *it) {
|
|
tIt = wIt;
|
|
|
|
if (++tIt != m_whiteKeyPos.end()) {
|
|
//MATRIX_DEBUG << "WHITE KEY HEIGHT = " << *tIt - *wIt << endl;
|
|
if (*tIt - *wIt == _whiteKeyHeight) {
|
|
yPos += 2;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
++wIt;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
m_hoverHighlight->setFixedSize(width, 4);
|
|
m_hoverHighlight->move(3, yPos);
|
|
m_hoverHighlight->show();
|
|
|
|
return ;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void PianoKeyboard::mouseMoveEvent(TQMouseEvent* e)
|
|
{
|
|
// The routine to work out where this should appear doesn't coincide with the note
|
|
// that we send to the sequencer - hence this is a bit pointless and crap at the moment.
|
|
// My own fault it's so crap but there you go.
|
|
//
|
|
// RWB (20040220)
|
|
//
|
|
MatrixView *matrixView = dynamic_cast<MatrixView*>(topLevelWidget());
|
|
if (matrixView) {
|
|
MatrixStaff *staff = matrixView->getStaff(0);
|
|
|
|
if (staff) {
|
|
drawHoverNote(staff->getHeightAtCanvasCoords(e->x(), e->y()));
|
|
}
|
|
}
|
|
|
|
if (e->state() & TQt::LeftButton) {
|
|
if (m_selecting)
|
|
emit keySelected(e->y(), true);
|
|
else
|
|
emit keyPressed(e->y(), true); // we're swooshing
|
|
|
|
emit keyReleased(m_lastKeyPressed, true);
|
|
m_lastKeyPressed = e->y();
|
|
} else
|
|
emit hoveredOverKeyChanged(e->y());
|
|
}
|
|
|
|
void PianoKeyboard::mousePressEvent(TQMouseEvent *e)
|
|
{
|
|
TQt::ButtonState bs = e->state();
|
|
|
|
if (e->button() == TQt::LeftButton) {
|
|
m_mouseDown = true;
|
|
m_selecting = (bs & TQt::ShiftButton);
|
|
m_lastKeyPressed = e->y();
|
|
|
|
if (m_selecting)
|
|
emit keySelected(e->y(), false);
|
|
else
|
|
emit keyPressed(e->y(), false);
|
|
}
|
|
}
|
|
|
|
void PianoKeyboard::mouseReleaseEvent(TQMouseEvent *e)
|
|
{
|
|
if (e->button() == TQt::LeftButton) {
|
|
m_mouseDown = false;
|
|
m_selecting = false;
|
|
emit keyReleased(e->y(), false);
|
|
}
|
|
}
|
|
|
|
}
|
|
#include "PianoKeyboard.moc"
|