1 /*
2  * PianoRoll.h - declaration of class PianoRoll which is a window where you
3  *               can set and edit notes in an easy way
4  *
5  * Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
6  * Copyright (c) 2008 Andrew Kelley <superjoe30/at/gmail/dot/com>
7  *
8  * This file is part of LMMS - https://lmms.io
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public
21  * License along with this program (see COPYING); if not, write to the
22  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301 USA.
24  *
25  */
26 
27 #ifndef PIANO_ROLL_H
28 #define PIANO_ROLL_H
29 
30 #include <QVector>
31 #include <QWidget>
32 #include <QInputDialog>
33 
34 #include "Editor.h"
35 #include "ComboBoxModel.h"
36 #include "SerializingObject.h"
37 #include "Note.h"
38 #include "lmms_basics.h"
39 #include "Song.h"
40 #include "ToolTip.h"
41 
42 class QPainter;
43 class QPixmap;
44 class QScrollBar;
45 class QString;
46 class QMenu;
47 class QSignalMapper;
48 
49 class ComboBox;
50 class NotePlayHandle;
51 class Pattern;
52 class TimeLineWidget;
53 
54 class PianoRoll : public QWidget
55 {
56 	Q_OBJECT
57 	Q_PROPERTY( QColor barLineColor READ barLineColor WRITE setBarLineColor )
58 	Q_PROPERTY( QColor beatLineColor READ beatLineColor WRITE setBeatLineColor )
59 	Q_PROPERTY( QColor lineColor READ lineColor WRITE setLineColor )
60 	Q_PROPERTY( QColor noteModeColor READ noteModeColor WRITE setNoteModeColor )
61 	Q_PROPERTY( QColor noteColor READ noteColor WRITE setNoteColor )
62 	Q_PROPERTY( QColor barColor READ barColor WRITE setBarColor )
63 	Q_PROPERTY( QColor selectedNoteColor READ selectedNoteColor WRITE setSelectedNoteColor )
64 	Q_PROPERTY( QColor textColor READ textColor WRITE setTextColor )
65 	Q_PROPERTY( QColor textColorLight READ textColorLight WRITE setTextColorLight )
66 	Q_PROPERTY( QColor textShadow READ textShadow WRITE setTextShadow )
67 	Q_PROPERTY( QColor markedSemitoneColor READ markedSemitoneColor WRITE setMarkedSemitoneColor )
68 	Q_PROPERTY( int noteOpacity READ noteOpacity WRITE setNoteOpacity )
69 	Q_PROPERTY( bool noteBorders READ noteBorders WRITE setNoteBorders )
70 	Q_PROPERTY( QColor backgroundShade READ backgroundShade WRITE setBackgroundShade )
71 public:
72 	enum EditModes
73 	{
74 		ModeDraw,
75 		ModeErase,
76 		ModeSelect,
77 		ModeEditDetuning,
78 	};
79 
80 	/*! \brief Resets settings to default when e.g. creating a new project */
81 	void reset();
82 
83 	// functions to display the hover-text labeling a note's volume/panning
84 	void showTextFloat(const QString &text, const QPoint &pos, int timeout=-1);
85 	void showVolTextFloat(volume_t vol, const QPoint &pos, int timeout=-1);
86 	void showPanTextFloat(panning_t pan, const QPoint &pos, int timeout=-1);
87 
88 	void setCurrentPattern( Pattern* newPattern );
89 
stopRecording()90 	inline void stopRecording()
91 	{
92 		m_recording = false;
93 	}
94 
isRecording()95 	inline bool isRecording() const
96 	{
97 		return m_recording;
98 	}
99 
currentPattern()100 	const Pattern* currentPattern() const
101 	{
102 		return m_pattern;
103 	}
104 
hasValidPattern()105 	bool hasValidPattern() const
106 	{
107 		return m_pattern != NULL;
108 	}
109 
110 	Song::PlayModes desiredPlayModeForAccompany() const;
111 
112 	int quantization() const;
113 
114 	// qproperty access functions
115 	QColor barLineColor() const;
116 	void setBarLineColor( const QColor & c );
117 	QColor beatLineColor() const;
118 	void setBeatLineColor( const QColor & c );
119 	QColor lineColor() const;
120 	void setLineColor( const QColor & c );
121 	QColor noteModeColor() const;
122 	void setNoteModeColor( const QColor & c );
123 	QColor noteColor() const;
124 	void setNoteColor( const QColor & c );
125 	QColor barColor() const;
126 	void setBarColor( const QColor & c );
127 	QColor selectedNoteColor() const;
128 	void setSelectedNoteColor( const QColor & c );
129 	QColor textColor() const;
130 	void setTextColor( const QColor & c );
131 	QColor textColorLight() const;
132 	void setTextColorLight( const QColor & c );
133 	QColor textShadow() const;
134 	void setTextShadow( const QColor & c );
135 	QColor markedSemitoneColor() const;
136 	void setMarkedSemitoneColor( const QColor & c );
137 	int noteOpacity() const;
138 	void setNoteOpacity( const int i );
139 	bool noteBorders() const;
140 	void setNoteBorders( const bool b );
141 	QColor backgroundShade() const;
142 	void setBackgroundShade( const QColor & c );
143 
144 
145 protected:
146 	virtual void keyPressEvent( QKeyEvent * ke );
147 	virtual void keyReleaseEvent( QKeyEvent * ke );
148 	virtual void leaveEvent( QEvent * e );
149 	virtual void mousePressEvent( QMouseEvent * me );
150 	virtual void mouseDoubleClickEvent( QMouseEvent * me );
151 	virtual void mouseReleaseEvent( QMouseEvent * me );
152 	virtual void mouseMoveEvent( QMouseEvent * me );
153 	virtual void paintEvent( QPaintEvent * pe );
154 	virtual void resizeEvent( QResizeEvent * re );
155 	virtual void wheelEvent( QWheelEvent * we );
156 	virtual void focusOutEvent( QFocusEvent * );
157 
158 	int getKey( int y ) const;
159 	static void drawNoteRect( QPainter & p, int x, int y,
160 					int  width, const Note * n, const QColor & noteCol,
161 					const QColor & selCol, const int noteOpc, const bool borderless );
162 	void removeSelection();
163 	void selectAll();
164 	NoteVector getSelectedNotes();
165 	void selectNotesOnKey();
166 	int xCoordOfTick( int tick );
167 
168 	// for entering values with dblclick in the vol/pan bars
169 	void enterValue( NoteVector* nv );
170 
171 protected slots:
172 	void play();
173 	void record();
174 	void recordAccompany();
175 	void stop();
176 
177 	void startRecordNote( const Note & n );
178 	void finishRecordNote( const Note & n );
179 
180 	void horScrolled( int new_pos );
181 	void verScrolled( int new_pos );
182 
183 	void setEditMode(int mode);
184 
185 	void copySelectedNotes();
186 	void cutSelectedNotes();
187 	void pasteNotes();
188 	void deleteSelectedNotes();
189 
190 	void updatePosition(const MidiTime & t );
191 	void updatePositionAccompany(const MidiTime & t );
192 
193 	void zoomingChanged();
194 	void quantizeChanged();
195 	void quantizeNotes();
196 
197 	void updateSemiToneMarkerMenu();
198 
199 	void changeNoteEditMode( int i );
200 	void markSemiTone( int i );
201 
202 	void hidePattern( Pattern* pattern );
203 
204 	void selectRegionFromPixels( int xStart, int xEnd );
205 
206 
207 signals:
208 	void currentPatternChanged();
209 	void semiToneMarkerMenuScaleSetEnabled(bool);
210 	void semiToneMarkerMenuChordSetEnabled(bool);
211 
212 
213 private:
214 	enum Actions
215 	{
216 		ActionNone,
217 		ActionMoveNote,
218 		ActionResizeNote,
219 		ActionSelectNotes,
220 		ActionChangeNoteProperty,
221 		ActionResizeNoteEditArea
222 	};
223 
224 	enum NoteEditMode
225 	{
226 		NoteEditVolume,
227 		NoteEditPanning,
228 		NoteEditCount // make sure this one is always last
229 	};
230 
231 	enum SemiToneMarkerAction
232 	{
233 		stmaUnmarkAll,
234 		stmaMarkCurrentSemiTone,
235 		stmaMarkAllOctaveSemiTones,
236 		stmaMarkCurrentScale,
237 		stmaMarkCurrentChord,
238 		stmaCopyAllNotesOnKey
239 	};
240 
241 	enum PianoRollKeyTypes
242 	{
243 		PR_WHITE_KEY_SMALL,
244 		PR_WHITE_KEY_BIG,
245 		PR_BLACK_KEY
246 	};
247 
248 	QVector<QString> m_nemStr; // gui names of each edit mode
249 	QMenu * m_noteEditMenu; // when you right click below the key area
250 
251 	QList<int> m_markedSemiTones;
252 	QMenu * m_semiToneMarkerMenu; // when you right click on the key area
253 	int m_pianoKeySelected;
254 
255 	PianoRoll();
256 	PianoRoll( const PianoRoll & );
257 	virtual ~PianoRoll();
258 
259 	void autoScroll(const MidiTime & t );
260 
261 	MidiTime newNoteLen() const;
262 
263 	void shiftPos(int amount);
264 	void shiftSemiTone(int amount);
265 	bool isSelection() const;
266 	int selectionCount() const;
267 	void testPlayNote( Note * n );
268 	void testPlayKey( int _key, int _vol, int _pan );
269 	void pauseTestNotes(bool pause = true );
270 
271 	QList<int> getAllOctavesForKey( int keyToMirror ) const;
272 
273 	int noteEditTop() const;
274 	int keyAreaBottom() const;
275 	int noteEditBottom() const;
276 	int keyAreaTop() const;
277 	int noteEditRight() const;
278 	int noteEditLeft() const;
279 
280 	void dragNotes( int x, int y, bool alt, bool shift, bool ctrl );
281 
282 	static const int cm_scrollAmtHoriz = 10;
283 	static const int cm_scrollAmtVert = 1;
284 
285 	static QPixmap * s_whiteKeyBigPm;
286 	static QPixmap * s_whiteKeyBigPressedPm;
287 	static QPixmap * s_whiteKeySmallPm;
288 	static QPixmap * s_whiteKeySmallPressedPm;
289 	static QPixmap * s_blackKeyPm;
290 	static QPixmap * s_blackKeyPressedPm;
291 	static QPixmap * s_toolDraw;
292 	static QPixmap * s_toolErase;
293 	static QPixmap * s_toolSelect;
294 	static QPixmap * s_toolMove;
295 	static QPixmap * s_toolOpen;
296 
297 	static PianoRollKeyTypes prKeyOrder[];
298 
299 	static TextFloat * s_textFloat;
300 
301 	ComboBoxModel m_zoomingModel;
302 	ComboBoxModel m_quantizeModel;
303 	ComboBoxModel m_noteLenModel;
304 	ComboBoxModel m_scaleModel;
305 	ComboBoxModel m_chordModel;
306 
307 	static const QVector<double> m_zoomLevels;
308 
309 	Pattern* m_pattern;
310 	QScrollBar * m_leftRightScroll;
311 	QScrollBar * m_topBottomScroll;
312 
313 	MidiTime m_currentPosition;
314 	bool m_recording;
315 	QList<Note> m_recordingNotes;
316 
317 	Note * m_currentNote;
318 	Actions m_action;
319 	NoteEditMode m_noteEditMode;
320 
321 	int m_selectStartTick;
322 	int m_selectedTick;
323 	int m_selectStartKey;
324 	int m_selectedKeys;
325 
326 	// boundary box around all selected notes when dragging
327 	int m_moveBoundaryLeft;
328 	int m_moveBoundaryTop;
329 	int m_moveBoundaryRight;
330 	int m_moveBoundaryBottom;
331 
332 	// remember where the scrolling started when dragging so that
333 	// we can handle dragging while scrolling with arrow keys
334 	int m_mouseDownKey;
335 	int m_mouseDownTick;
336 
337 	// remember the last x and y of a mouse movement
338 	int m_lastMouseX;
339 	int m_lastMouseY;
340 
341 	// x,y of when the user starts a drag
342 	int m_moveStartX;
343 	int m_moveStartY;
344 
345 	int m_oldNotesEditHeight;
346 	int m_notesEditHeight;
347 	int m_ppt;  // pixels per tact
348 	int m_totalKeysToScroll;
349 
350 	// remember these values to use them
351 	// for the next note that is set
352 	MidiTime m_lenOfNewNotes;
353 	volume_t m_lastNoteVolume;
354 	panning_t m_lastNotePanning;
355 
356 	int m_startKey; // first key when drawing
357 	int m_lastKey;
358 
359 	EditModes m_editMode;
360 	EditModes m_ctrlMode; // mode they were in before they hit ctrl
361 
362 	bool m_mouseDownRight; //true if right click is being held down
363 
364 	TimeLineWidget * m_timeLine;
365 	bool m_scrollBack;
366 
367 	void copyToClipboard(const NoteVector & notes ) const;
368 
369 	void drawDetuningInfo( QPainter & _p, const Note * _n, int _x, int _y ) const;
370 	bool mouseOverNote();
371 	Note * noteUnderMouse();
372 
373 	// turn a selection rectangle into selected notes
374 	void computeSelectedNotes( bool shift );
375 	void clearSelectedNotes();
376 
377 	// did we start a mouseclick with shift pressed
378 	bool m_startedWithShift;
379 
380 	friend class PianoRollWindow;
381 
382 	// qproperty fields
383 	QColor m_barLineColor;
384 	QColor m_beatLineColor;
385 	QColor m_lineColor;
386 	QColor m_noteModeColor;
387 	QColor m_noteColor;
388 	QColor m_barColor;
389 	QColor m_selectedNoteColor;
390 	QColor m_textColor;
391 	QColor m_textColorLight;
392 	QColor m_textShadow;
393 	QColor m_markedSemitoneColor;
394 	int m_noteOpacity;
395 	bool m_noteBorders;
396 	QColor m_backgroundShade;
397 
398 signals:
399 	void positionChanged( const MidiTime & );
400 } ;
401 
402 
403 
404 
405 class PianoRollWindow : public Editor, SerializingObject
406 {
407 	Q_OBJECT
408 public:
409 	PianoRollWindow();
410 
411 	const Pattern* currentPattern() const;
412 	void setCurrentPattern(Pattern* pattern);
413 
414 	int quantization() const;
415 
416 	void play();
417 	void stop();
418 	void record();
419 	void recordAccompany();
420 	void stopRecording();
421 
422 	bool isRecording() const;
423 
424 	/*! \brief Resets settings to default when e.g. creating a new project */
425 	void reset();
426 
427 	using SerializingObject::saveState;
428 	using SerializingObject::restoreState;
429 	virtual void saveSettings(QDomDocument & doc, QDomElement & de );
430 	virtual void loadSettings( const QDomElement & de );
431 
nodeName()432 	inline virtual QString nodeName() const
433 	{
434 		return "pianoroll";
435 	}
436 
437 	QSize sizeHint() const;
438 
439 signals:
440 	void currentPatternChanged();
441 
442 
443 private slots:
444 	void patternRenamed();
445 
446 private:
447 	void focusInEvent(QFocusEvent * event);
448 
449 	PianoRoll* m_editor;
450 
451 	ComboBox * m_zoomingComboBox;
452 	ComboBox * m_quantizeComboBox;
453 	ComboBox * m_noteLenComboBox;
454 	ComboBox * m_scaleComboBox;
455 	ComboBox * m_chordComboBox;
456 
457 };
458 
459 
460 #endif
461