1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Rosegarden
5 A MIDI and audio sequencer and musical notation editor.
6 Copyright 2000-2021 the Rosegarden development team.
7
8 Other copyrights also apply to some parts of this work. Please
9 see the AUTHORS file and individual file headers for details.
10
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation; either version 2 of the
14 License, or (at your option) any later version. See the file
15 COPYING included with this distribution for more information.
16 */
17
18 #define RG_MODULE_STRING "[PercussionPitchRuler]"
19
20 #include <QMouseEvent>
21 #include "PercussionPitchRuler.h"
22
23 #include "misc/Debug.h"
24 #include "misc/Strings.h"
25 #include "base/MidiProgram.h"
26 #include "gui/editors/matrix/MatrixView.h"
27 #include "gui/general/MidiPitchLabel.h"
28 #include "PitchRuler.h"
29 #include <QColor>
30 #include <QEvent>
31 #include <QFont>
32 #include <QFontMetrics>
33 #include <QPainter>
34 #include <QSize>
35 #include <QWidget>
36
37
38 namespace Rosegarden
39 {
40
PercussionPitchRuler(QWidget * parent,QSharedPointer<const MidiKeyMapping> mapping,int lineSpacing)41 PercussionPitchRuler::PercussionPitchRuler(QWidget *parent,
42 QSharedPointer<const MidiKeyMapping> mapping,
43 int lineSpacing) :
44 PitchRuler(parent),
45 m_mapping(mapping),
46 m_lineSpacing(lineSpacing),
47 m_mouseDown(false),
48 m_highlightPitch(-1),
49 m_lastHighlightPitch( -1)
50 {
51 m_font = new QFont();
52 m_font->setPixelSize(9);
53 m_fontMetrics = new QFontMetrics(*m_font);
54 //: Note to the translators: Don't translate literally.
55 //: This string is never displayed but defines the largest width of the
56 //: text (pitch and intrument name) in the percussion ruler.
57 m_width =
58 m_fontMetrics->boundingRect(tr(" A#2 Acoustic Bass Drum ")).width();
59
60 setMouseTracking(true);
61 }
62
sizeHint() const63 QSize PercussionPitchRuler::sizeHint() const
64 {
65 return QSize(m_width,
66 (m_lineSpacing + 1) * m_mapping->getPitchExtent());
67 }
68
minimumSizeHint() const69 QSize PercussionPitchRuler::minimumSizeHint() const
70 {
71 return QSize(m_width, m_lineSpacing + 1);
72 }
73
paintEvent(QPaintEvent *)74 void PercussionPitchRuler::paintEvent(QPaintEvent*)
75 {
76 QPainter paint(this);
77
78 paint.setFont(*m_font);
79
80 int minPitch = m_mapping->getPitchForOffset(0);
81 int extent = m_mapping->getPitchExtent();
82
83 // Draw the ruler
84
85 for (int i = 0; i < extent; ++i) {
86 paint.drawLine(0, i * (m_lineSpacing + 1),
87 m_width, i * (m_lineSpacing + 1));
88 }
89
90 //: Note to the translators: Don't translate literally.
91 //: This string is never displayed but defines the largest width of the
92 //: pitch name in the percussion ruler text.
93 int lw = m_fontMetrics->boundingRect(tr("A#2")).width();
94 int offset = m_fontMetrics->ascent() + 1;
95
96 for (int i = 0; i < extent; ++i) {
97
98 MidiPitchLabel label(minPitch + i);
99 std::string key = m_mapping->getMapForKeyName(minPitch + i);
100 //RG_DEBUG << "PercussionPitchRuler::paintEvent()" << i << ": " << label.getQString() << ": " << key;
101
102 int yi = (extent - i - 1) * (m_lineSpacing + 1) + offset;
103 paint.drawText(2, yi, label.getQString());
104
105 if (i != m_highlightPitch) {
106 // Draw an unhighlighted note
107 paint.drawText(9 + lw, yi, strtoqstr(key));
108 } else {
109 // Highlight the note
110 int pitchDistance = m_highlightPitch - minPitch;
111 int y = (extent - pitchDistance - 1) * (m_lineSpacing + 1);
112 paint.save();
113 paint.setBrush(paint.pen().color());
114 paint.drawRect(lw + 7, y, m_width - lw, m_lineSpacing + 1);
115 paint.setPen(QColor(Qt::black));
116 std::string key = m_mapping->getMapForKeyName(m_highlightPitch);
117 paint.drawText(9 + lw, y + offset, strtoqstr(key));
118 paint.restore();
119 }
120 }
121
122 if (m_lastHighlightPitch != m_highlightPitch) {
123 m_lastHighlightPitch = m_highlightPitch;
124
125 // Un-highlight the last highlighted note
126 if (m_lastHighlightPitch >= 0) {
127 int lastPitchDistance = m_lastHighlightPitch - minPitch;
128 int y = (extent - lastPitchDistance - 1) * (m_lineSpacing + 1);
129 paint.drawRect(lw + 7, y + 1, m_width - lw, m_lineSpacing);
130 std::string key = m_mapping->getMapForKeyName(m_lastHighlightPitch);
131 paint.setPen(QColor(Qt::black));
132 paint.drawText(9 + lw, y + offset, strtoqstr(key));
133 }
134 }
135 }
136
137 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
enterEvent(QEnterEvent *)138 void PercussionPitchRuler::enterEvent(QEnterEvent *)
139 #else
140 void PercussionPitchRuler::enterEvent(QEvent *)
141 #endif
142 {}
143
leaveEvent(QEvent *)144 void PercussionPitchRuler::leaveEvent(QEvent*)
145 {
146 // Force currently highlighted note to be un-highlighted
147 m_highlightPitch = -1;
148 update();
149 }
150
showHighlight(int evPitch)151 void PercussionPitchRuler::showHighlight(int evPitch)
152 {
153 m_highlightPitch = evPitch;
154 update();
155 }
156
hideHighlight()157 void PercussionPitchRuler::hideHighlight()
158 {
159 // Force current highlighted note to be un-highlighted
160 m_highlightPitch = -1;
161 update();
162 }
163
mouseMoveEvent(QMouseEvent * e)164 void PercussionPitchRuler::mouseMoveEvent(QMouseEvent* e)
165 {
166 if (m_mouseDown)
167 if (m_selecting)
168 emit keySelected(e->pos().y(), true);
169 else
170 emit keyPressed(e->pos().y(), true); // we're swooshing
171 else
172 emit hoveredOverKeyChanged(e->pos().y());
173 }
174
mousePressEvent(QMouseEvent * e)175 void PercussionPitchRuler::mousePressEvent(QMouseEvent *e)
176 {
177 if (e->button() == Qt::LeftButton) {
178
179 m_mouseDown = true;
180 m_selecting = (e->modifiers() & Qt::ShiftModifier);
181
182 if (m_selecting)
183 emit keySelected(e->pos().y(), false);
184 else
185 emit keyPressed(e->pos().y(), false);
186 }
187 }
188
mouseReleaseEvent(QMouseEvent * e)189 void PercussionPitchRuler::mouseReleaseEvent(QMouseEvent *e)
190 {
191 if (e->button() == Qt::LeftButton) {
192 m_mouseDown = false;
193 m_selecting = false;
194 emit keyReleased(e->pos().y(), false);
195 }
196 }
197
198 }
199