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