-
Notifications
You must be signed in to change notification settings - Fork 2.6k
/
pianorollview.h
257 lines (217 loc) · 8.7 KB
/
pianorollview.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2021 MuseScore BVBA and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef MU_PIANOROLL_PIANOROLLVIEW_H
#define MU_PIANOROLL_PIANOROLLVIEW_H
#include <QQuickPaintedItem>
#include <QIcon>
#include <QColor>
#include "async/asyncable.h"
#include "context/iglobalcontext.h"
#include "pianoroll/ipianorollcontroller.h"
#include "audio/iplayback.h"
#include "notation/inotationinteraction.h"
namespace mu::pianoroll {
enum class NoteSelectType
{
REPLACE = 0,
XOR,
ADD,
SUBTRACT,
FIRST
};
enum class DragStyle
{
NONE = 0,
CANCELLED,
SELECTION_RECT,
NOTE_POSITION,
NOTE_LENGTH_START,
NOTE_LENGTH_END,
DRAW_NOTE,
EVENT_ONTIME,
EVENT_MOVE,
EVENT_LENGTH
};
struct BarPattern
{
QString name;
char isWhiteKey[12]; //Set to 1 for white keys, 0 for black
};
struct NoteBlock
{
Ms::Note* note;
int voice;
int staffIdx;
};
class PianorollView : public QQuickPaintedItem, public async::Asyncable
{
Q_OBJECT
public:
enum class PianorollTool : char {
SELECT, ADD, CUT, ERASE, EVENT_ADJUST
};
Q_ENUM(PianorollTool)
static const BarPattern barPatterns[];
private:
INJECT(pianoroll, context::IGlobalContext, globalContext)
INJECT(pianoroll, IPianorollController, controller)
INJECT(pianoroll, audio::IPlayback, playback)
Q_PROPERTY(double wholeNoteWidth READ wholeNoteWidth WRITE setWholeNoteWidth NOTIFY wholeNoteWidthChanged)
Q_PROPERTY(double noteHeight READ noteHeight WRITE setNoteHeight NOTIFY noteHeightChanged)
Q_PROPERTY(PianorollTool tool READ tool WRITE setTool NOTIFY toolChanged)
Q_PROPERTY(int tuplet READ tuplet WRITE setTuplet NOTIFY tupletChanged)
Q_PROPERTY(int subdivision READ subdivision WRITE setSubdivision NOTIFY subdivisionChanged)
Q_PROPERTY(double centerX READ centerX WRITE setCenterX NOTIFY centerXChanged)
Q_PROPERTY(double centerY READ centerY WRITE setCenterY NOTIFY centerYChanged)
Q_PROPERTY(double displayObjectWidth READ displayObjectWidth WRITE setDisplayObjectWidth NOTIFY displayObjectWidthChanged)
Q_PROPERTY(double displayObjectHeight READ displayObjectHeight WRITE setDisplayObjectHeight NOTIFY displayObjectHeightChanged)
public:
static const int NUM_PITCHES = 128;
static const int VOICES = 4;
PianorollView(QQuickItem* parent = nullptr);
Q_INVOKABLE void load();
bool displayEventAdjustment() { return m_tool == PianorollTool::EVENT_ADJUST; }
double wholeNoteWidth() const { return m_wholeNoteWidth; }
void setWholeNoteWidth(double value);
int noteHeight() const { return m_noteHeight; }
void setNoteHeight(double value);
PianorollTool tool() const { return m_tool; }
void setTool(PianorollTool value);
int tuplet() const { return m_tuplet; }
void setTuplet(int value);
int subdivision() const { return m_subdivision; }
void setSubdivision(int value);
double centerX() const { return m_centerX; }
void setCenterX(double value);
double centerY() const { return m_centerY; }
void setCenterY(double value);
double displayObjectWidth() const { return m_displayObjectWidth; }
void setDisplayObjectWidth(double value);
double displayObjectHeight() const { return m_displayObjectHeight; }
void setDisplayObjectHeight(double value);
Ms::Fraction playbackPosition() { return m_playbackPosition; }
void setPlaybackPosition(Ms::Fraction value);
void paint(QPainter*) override;
void keyReleaseEvent(QKeyEvent* event) override;
void mousePressEvent(QMouseEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
void mouseMoveEvent(QMouseEvent* event) override;
void hoverMoveEvent(QHoverEvent* event) override;
int wholeNoteToPixelX(Ms::Fraction tick) const { return wholeNoteToPixelX(tick.numerator() / (double)tick.denominator()); }
int wholeNoteToPixelX(double tick) const;
double pixelXToWholeNote(int pixelX) const;
int pitchToPixelY(double pitch) const;
double pixelYToPitch(int tick) const;
void finishNoteGroupDrag();
void finishNoteEventAdjustDrag();
void selectNotes(double startTick, double endTick, double lowPitch, double highPitch, NoteSelectType selType);
void handleSelectionClick();
signals:
void wholeNoteWidthChanged();
void noteHeightChanged();
void toolChanged();
void tweaksChanged();
void tupletChanged();
void subdivisionChanged();
void centerXChanged();
void centerYChanged();
void displayObjectWidthChanged();
void displayObjectHeightChanged();
void playbackPositionChanged();
private:
void onNotationChanged();
void onCurrentNotationChanged();
void onSelectionChanged();
void updateBoundingSize();
QRect boundingRect(Ms::Note* note, bool applyEvents = false);
QRect boundingRect(Ms::Note* note, Ms::NoteEvent* evt, bool applyEvents = false);
QString serializeSelectedNotes();
void buildNoteData();
void addChord(Ms::Chord* chrd, int voice, int staffIdx);
void drawNoteBlock(QPainter* p, NoteBlock* block);
void drawDraggedNotes(QPainter* painter);
void drawDraggedNote(QPainter* painter, Ms::Fraction startTick, Ms::Fraction frac, int pitch, int track, QColor color);
NoteBlock* pickNote(int pixX, int pixY);
bool intersects(NoteBlock* block, int pixX, int pixY);
bool intersectsPixel(NoteBlock* block, int x, int y, int width, int height);
void insertNote(int modifiers);
void cutChord(const QPointF& pos);
void eraseNote(const QPointF& pos);
Ms::Fraction roundToSubdivision(double wholeNote, bool down = true);
void pasteNotes(const QString& copiedNotes, Ms::Fraction pasteStartTick, Ms::Fraction lengthOffset, int pitchOffset, bool xIsOffset);
std::vector<Ms::Note*> addNote(Ms::Fraction startTick, Ms::Fraction duration, int pitch, int track);
bool cutChordRest(Ms::ChordRest* targetCr, int track, Ms::Fraction cutTick, Ms::ChordRest*& cr0, Ms::ChordRest*& cr1);
std::vector<Ms::Note*> getSegmentNotes(Ms::Segment* seg, int track);
static void append(std::vector<Ms::Note*>& a, const std::vector<Ms::Note*>& b)
{
a.insert(a.end(), b.begin(), b.end());
}
Ms::Score* score();
Ms::Staff* activeStaff();
notation::INotationPtr m_notation;
QList<NoteBlock*> m_noteList;
std::vector<int> m_selectedStaves;
int m_activeStaff;
double m_centerX = 0; //fraction of note grid camera is focused on
double m_centerY = 0; //fraction of note grid camera is focused on
double m_displayObjectWidth = 0; //Set to note grid in pixels
double m_displayObjectHeight = 0; //Set to note grid in pixels
double m_wholeNoteWidth;
double m_noteHeight;
int m_tuplet = 1;
int m_subdivision = 0;
PianorollTool m_tool = PianorollTool::SELECT;
int m_barPattern = 0;
int m_editNoteVoice = 0; //Voice to use when adding notes
Ms::Fraction m_editNoteLength = Ms::Fraction(1, 4); //Length of note used when adding notes
bool m_mouseDown;
bool m_dragStarted;
QString m_dragNoteCache;
QPointF m_mouseDownPos;
QPointF m_lastMousePos;
QPointF m_popupMenuPos;
DragStyle m_dragStyle;
int m_dragStartPitch;
Ms::Fraction m_dragStartTick;
Ms::Fraction m_dragEndTick;
int m_dragNoteLengthMargin = 4;
bool m_inProgressUndoEvent;
Ms::Fraction m_playbackPosition;
QColor m_colorBackground = Qt::gray;
QColor m_colorKeyWhite = QColor(0xffffff);
QColor m_colorKeyBlack = QColor(0xe6e6e6);
QColor m_colorKeyHighlight = QColor(0xaaaaff);
QColor m_colorSelectionBox = QColor(0x2085c3);
QColor m_colorPlaybackLine = QColor(0xff0000);
QColor m_colorGridLine = QColor(0xa2a2a6);
QColor m_colorNoteSel = QColor(0xffff00);
QColor m_colorNoteVoice1 = QColor(0x9bcdff);
QColor m_colorNoteVoice2 = QColor(0x80d580);
QColor m_colorNoteVoice3 = QColor(0xffac85);
QColor m_colorNoteVoice4 = QColor(0xff94db);
QColor m_colorTweaks = QColor(0xfd63fcc);
QColor m_colorNoteDrag = QColor(0xffbb33);
QColor m_colorText = QColor(0x111111);
QColor m_colorTie = QColor(0xff0000);
};
}
#endif // MU_PIANOROLL_PIANOROLLVIEW_H