1 /*
2  * Track.h - declaration of classes concerning tracks -> necessary for all
3  *           track-like objects (beat/bassline, sample-track...)
4  *
5  * Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
6  *
7  * This file is part of LMMS - https://lmms.io
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public
20  * License along with this program (see COPYING); if not, write to the
21  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301 USA.
23  *
24  */
25 
26 #ifndef TRACK_H
27 #define TRACK_H
28 
29 #include <QtCore/QVector>
30 #include <QtCore/QList>
31 #include <QWidget>
32 #include <QSignalMapper>
33 #include <QSize>
34 #include <QColor>
35 #include <QMimeData>
36 
37 #include "lmms_basics.h"
38 #include "MidiTime.h"
39 #include "Rubberband.h"
40 #include "JournallingObject.h"
41 #include "AutomatableModel.h"
42 #include "ModelView.h"
43 #include "DataFile.h"
44 
45 
46 class QMenu;
47 class QPushButton;
48 
49 class PixmapButton;
50 class TextFloat;
51 class Track;
52 class TrackContentObjectView;
53 class TrackContainer;
54 class TrackContainerView;
55 class TrackContentWidget;
56 class TrackView;
57 
58 
59 const int DEFAULT_SETTINGS_WIDGET_WIDTH = 224;
60 const int TRACK_OP_WIDTH = 78;
61 // This shaves 150-ish pixels off track buttons,
62 // ruled from config: ui.compacttrackbuttons
63 const int DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT = 96;
64 const int TRACK_OP_WIDTH_COMPACT = 62;
65 
66 /*! The minimum track height in pixels
67  *
68  * Tracks can be resized by shift-dragging anywhere inside the track
69  * display.  This sets the minimum size in pixels for a track.
70  */
71 const int MINIMAL_TRACK_HEIGHT = 32;
72 const int DEFAULT_TRACK_HEIGHT = 32;
73 
74 const int TCO_BORDER_WIDTH = 2;
75 
76 char const *const FILENAME_FILTER = "[\\0000-\x1f\"*/:<>?\\\\|\x7f]";
77 
78 
79 class TrackContentObject : public Model, public JournallingObject
80 {
81 	Q_OBJECT
82 	MM_OPERATORS
83 	mapPropertyFromModel(bool,isMuted,setMuted,m_mutedModel);
84 	mapPropertyFromModel(bool,isSolo,setSolo,m_soloModel);
85 public:
86 	TrackContentObject( Track * track );
87 	virtual ~TrackContentObject();
88 
getTrack()89 	inline Track * getTrack() const
90 	{
91 		return m_track;
92 	}
93 
name()94 	inline const QString & name() const
95 	{
96 		return m_name;
97 	}
98 
setName(const QString & name)99 	inline void setName( const QString & name )
100 	{
101 		m_name = name;
102 		emit dataChanged();
103 	}
104 
displayName()105 	virtual QString displayName() const
106 	{
107 		return name();
108 	}
109 
110 
startPosition()111 	inline const MidiTime & startPosition() const
112 	{
113 		return m_startPosition;
114 	}
115 
endPosition()116 	inline MidiTime endPosition() const
117 	{
118 		const int sp = m_startPosition;
119 		return sp + m_length;
120 	}
121 
length()122 	inline const MidiTime & length() const
123 	{
124 		return m_length;
125 	}
126 
setAutoResize(const bool r)127 	inline void setAutoResize( const bool r )
128 	{
129 		m_autoResize = r;
130 	}
131 
getAutoResize()132 	inline const bool getAutoResize() const
133 	{
134 		return m_autoResize;
135 	}
136 
137 	virtual void movePosition( const MidiTime & pos );
138 	virtual void changeLength( const MidiTime & length );
139 
140 	virtual TrackContentObjectView * createView( TrackView * tv ) = 0;
141 
selectViewOnCreate(bool select)142 	inline void selectViewOnCreate( bool select )
143 	{
144 		m_selectViewOnCreate = select;
145 	}
146 
getSelectViewOnCreate()147 	inline bool getSelectViewOnCreate()
148 	{
149 		return m_selectViewOnCreate;
150 	}
151 
152 	/// Returns true if and only if a->startPosition() < b->startPosition()
153 	static bool comparePosition(const TrackContentObject* a, const TrackContentObject* b);
154 
155 public slots:
156 	void copy();
157 	void paste();
158 	void toggleMute();
159 
160 
161 signals:
162 	void lengthChanged();
163 	void positionChanged();
164 	void destroyedTCO();
165 
166 
167 private:
168 	enum Actions
169 	{
170 		NoAction,
171 		Move,
172 		Resize
173 	} ;
174 
175 	Track * m_track;
176 	QString m_name;
177 
178 	MidiTime m_startPosition;
179 	MidiTime m_length;
180 
181 	BoolModel m_mutedModel;
182 	BoolModel m_soloModel;
183 	bool m_autoResize;
184 
185 	bool m_selectViewOnCreate;
186 
187 	friend class TrackContentObjectView;
188 
189 } ;
190 
191 
192 
193 class TrackContentObjectView : public selectableObject, public ModelView
194 {
195 	Q_OBJECT
196 
197 // theming qproperties
198 	Q_PROPERTY( QColor mutedColor READ mutedColor WRITE setMutedColor )
199 	Q_PROPERTY( QColor mutedBackgroundColor READ mutedBackgroundColor WRITE setMutedBackgroundColor )
200 	Q_PROPERTY( QColor selectedColor READ selectedColor WRITE setSelectedColor )
201 	Q_PROPERTY( QColor textColor READ textColor WRITE setTextColor )
202 	Q_PROPERTY( QColor textShadowColor READ textShadowColor WRITE setTextShadowColor )
203 	Q_PROPERTY( QColor BBPatternBackground READ BBPatternBackground WRITE setBBPatternBackground )
204 	Q_PROPERTY( bool gradient READ gradient WRITE setGradient )
205 	// We have to use a QSize here because using QPoint isn't supported.
206 	// width -> x, height -> y
207 	Q_PROPERTY( QSize mouseHotspotHand WRITE setMouseHotspotHand )
208 
209 public:
210 	TrackContentObjectView( TrackContentObject * tco, TrackView * tv );
211 	virtual ~TrackContentObjectView();
212 
213 	bool fixedTCOs();
214 
getTrackContentObject()215 	inline TrackContentObject * getTrackContentObject()
216 	{
217 		return m_tco;
218 	}
219 
getTrackView()220 	inline TrackView * getTrackView()
221 	{
222 		return m_trackView;
223 	}
224 
225 	// qproperty access func
226 	QColor mutedColor() const;
227 	QColor mutedBackgroundColor() const;
228 	QColor selectedColor() const;
229 	QColor textColor() const;
230 	QColor textShadowColor() const;
231 	QColor BBPatternBackground() const;
232 	bool gradient() const;
233 	void setMutedColor( const QColor & c );
234 	void setMutedBackgroundColor( const QColor & c );
235 	void setSelectedColor( const QColor & c );
236 	void setTextColor( const QColor & c );
237 	void setTextShadowColor( const QColor & c );
238 	void setBBPatternBackground( const QColor & c );
239 	void setGradient( const bool & b );
240 	void setMouseHotspotHand(const QSize & s);
241 
242 	// access needsUpdate member variable
243 	bool needsUpdate();
244 	void setNeedsUpdate( bool b );
245 
246 public slots:
247 	virtual bool close();
248 	void cut();
249 	void remove();
250 	virtual void update();
251 
252 protected:
constructContextMenu(QMenu *)253 	virtual void constructContextMenu( QMenu * )
254 	{
255 	}
256 
257 	virtual void contextMenuEvent( QContextMenuEvent * cme );
258 	virtual void dragEnterEvent( QDragEnterEvent * dee );
259 	virtual void dropEvent( QDropEvent * de );
260 	virtual void leaveEvent( QEvent * e );
261 	virtual void mousePressEvent( QMouseEvent * me );
262 	virtual void mouseMoveEvent( QMouseEvent * me );
263 	virtual void mouseReleaseEvent( QMouseEvent * me );
resizeEvent(QResizeEvent * re)264 	virtual void resizeEvent( QResizeEvent * re )
265 	{
266 		m_needsUpdate = true;
267 		selectableObject::resizeEvent( re );
268 	}
269 
270 	float pixelsPerTact();
271 
272 
273 	DataFile createTCODataFiles(const QVector<TrackContentObjectView *> & tcos) const;
274 
275 
276 protected slots:
277 	void updateLength();
278 	void updatePosition();
279 
280 
281 private:
282 	enum Actions
283 	{
284 		NoAction,
285 		Move,
286 		MoveSelection,
287 		Resize,
288 		CopySelection,
289 		ToggleSelected
290 	} ;
291 
292 	static TextFloat * s_textFloat;
293 
294 	TrackContentObject * m_tco;
295 	TrackView * m_trackView;
296 	Actions m_action;
297 	QPoint m_initialMousePos;
298 	QPoint m_initialMouseGlobalPos;
299 
300 	TextFloat * m_hint;
301 
302 // qproperty fields
303 	QColor m_mutedColor;
304 	QColor m_mutedBackgroundColor;
305 	QColor m_selectedColor;
306 	QColor m_textColor;
307 	QColor m_textShadowColor;
308 	QColor m_BBPatternBackground;
309 	bool m_gradient;
310 	QSize m_mouseHotspotHand; // QSize must be used because QPoint isn't supported by property system
311 	bool m_cursorSetYet;
312 
313 	bool m_needsUpdate;
setInitialMousePos(QPoint pos)314 	inline void setInitialMousePos( QPoint pos )
315 	{
316 		m_initialMousePos = pos;
317 		m_initialMouseGlobalPos = mapToGlobal( pos );
318 	}
319 
320 	bool mouseMovedDistance( QMouseEvent * me, int distance );
321 
322 } ;
323 
324 
325 
326 
327 
328 class TrackContentWidget : public QWidget, public JournallingObject
329 {
330 	Q_OBJECT
331 
332 	// qproperties for track background gradients
333 	Q_PROPERTY( QBrush darkerColor READ darkerColor WRITE setDarkerColor )
334 	Q_PROPERTY( QBrush lighterColor READ lighterColor WRITE setLighterColor )
335 	Q_PROPERTY( QBrush gridColor READ gridColor WRITE setGridColor )
336 	Q_PROPERTY( QBrush embossColor READ embossColor WRITE setEmbossColor )
337 
338 public:
339 	TrackContentWidget( TrackView * parent );
340 	virtual ~TrackContentWidget();
341 
342 	/*! \brief Updates the background tile pixmap. */
343 	void updateBackground();
344 
345 	void addTCOView( TrackContentObjectView * tcov );
346 	void removeTCOView( TrackContentObjectView * tcov );
removeTCOView(int tcoNum)347 	void removeTCOView( int tcoNum )
348 	{
349 		if( tcoNum >= 0 && tcoNum < m_tcoViews.size() )
350 		{
351 			removeTCOView( m_tcoViews[tcoNum] );
352 		}
353 	}
354 
355 	bool canPasteSelection( MidiTime tcoPos, const QDropEvent *de );
356 	bool pasteSelection( MidiTime tcoPos, QDropEvent * de );
357 
358 	MidiTime endPosition( const MidiTime & posStart );
359 
360 	// qproperty access methods
361 
362 	QBrush darkerColor() const;
363 	QBrush lighterColor() const;
364 	QBrush gridColor() const;
365 	QBrush embossColor() const;
366 
367 	void setDarkerColor( const QBrush & c );
368 	void setLighterColor( const QBrush & c );
369 	void setGridColor( const QBrush & c );
370 	void setEmbossColor( const QBrush & c);
371 
372 public slots:
373 	void update();
374 	void changePosition( const MidiTime & newPos = MidiTime( -1 ) );
375 
376 
377 protected:
378 	virtual void dragEnterEvent( QDragEnterEvent * dee );
379 	virtual void dropEvent( QDropEvent * de );
380 	virtual void mousePressEvent( QMouseEvent * me );
381 	virtual void paintEvent( QPaintEvent * pe );
382 	virtual void resizeEvent( QResizeEvent * re );
383 
nodeName()384 	virtual QString nodeName() const
385 	{
386 		return "trackcontentwidget";
387 	}
388 
saveSettings(QDomDocument & doc,QDomElement & element)389 	virtual void saveSettings( QDomDocument& doc, QDomElement& element )
390 	{
391 		Q_UNUSED(doc)
392 		Q_UNUSED(element)
393 	}
394 
loadSettings(const QDomElement & element)395 	virtual void loadSettings( const QDomElement& element )
396 	{
397 		Q_UNUSED(element)
398 	}
399 
400 
401 private:
402 	Track * getTrack();
403 	MidiTime getPosition( int mouseX );
404 
405 	TrackView * m_trackView;
406 
407 	typedef QVector<TrackContentObjectView *> tcoViewVector;
408 	tcoViewVector m_tcoViews;
409 
410 	QPixmap m_background;
411 
412 	// qproperty fields
413 	QBrush m_darkerColor;
414 	QBrush m_lighterColor;
415 	QBrush m_gridColor;
416 	QBrush m_embossColor;
417 } ;
418 
419 
420 
421 
422 
423 class TrackOperationsWidget : public QWidget
424 {
425 	Q_OBJECT
426 public:
427 	TrackOperationsWidget( TrackView * parent );
428 	~TrackOperationsWidget();
429 
430 
431 protected:
432 	virtual void mousePressEvent( QMouseEvent * me );
433 	virtual void paintEvent( QPaintEvent * pe );
434 
435 
436 private slots:
437 	void cloneTrack();
438 	void removeTrack();
439 	void updateMenu();
440 	void recordingOn();
441 	void recordingOff();
442 	void clearTrack();
443 
444 private:
445 	static QPixmap * s_grip;
446 
447 	TrackView * m_trackView;
448 
449 	QPushButton * m_trackOps;
450 	PixmapButton * m_muteBtn;
451 	PixmapButton * m_soloBtn;
452 
453 
454 	friend class TrackView;
455 
456 signals:
457 	void trackRemovalScheduled( TrackView * t );
458 
459 } ;
460 
461 
462 
463 
464 
465 // base-class for all tracks
466 class EXPORT Track : public Model, public JournallingObject
467 {
468 	Q_OBJECT
469 	MM_OPERATORS
470 	mapPropertyFromModel(bool,isMuted,setMuted,m_mutedModel);
471 	mapPropertyFromModel(bool,isSolo,setSolo,m_soloModel);
472 public:
473 	typedef QVector<TrackContentObject *> tcoVector;
474 
475 	enum TrackTypes
476 	{
477 		InstrumentTrack,
478 		BBTrack,
479 		SampleTrack,
480 		EventTrack,
481 		VideoTrack,
482 		AutomationTrack,
483 		HiddenAutomationTrack,
484 		NumTrackTypes
485 	} ;
486 
487 	Track( TrackTypes type, TrackContainer * tc );
488 	virtual ~Track();
489 
490 	static Track * create( TrackTypes tt, TrackContainer * tc );
491 	static Track * create( const QDomElement & element,
492 							TrackContainer * tc );
493 	Track * clone();
494 
495 
496 	// pure virtual functions
type()497 	TrackTypes type() const
498 	{
499 		return m_type;
500 	}
501 
502 	virtual bool play( const MidiTime & start, const fpp_t frames,
503 						const f_cnt_t frameBase, int tcoNum = -1 ) = 0;
504 
505 
506 	virtual TrackView * createView( TrackContainerView * view ) = 0;
507 	virtual TrackContentObject * createTCO( const MidiTime & pos ) = 0;
508 
509 	virtual void saveTrackSpecificSettings( QDomDocument & doc,
510 						QDomElement & parent ) = 0;
511 	virtual void loadTrackSpecificSettings( const QDomElement & element ) = 0;
512 
513 
514 	virtual void saveSettings( QDomDocument & doc, QDomElement & element );
515 	virtual void loadSettings( const QDomElement & element );
516 
setSimpleSerializing()517 	void setSimpleSerializing()
518 	{
519 		m_simpleSerializingMode = true;
520 	}
521 
522 	// -- for usage by TrackContentObject only ---------------
523 	TrackContentObject * addTCO( TrackContentObject * tco );
524 	void removeTCO( TrackContentObject * tco );
525 	// -------------------------------------------------------
526 	void deleteTCOs();
527 
528 	int numOfTCOs();
529 	TrackContentObject * getTCO( int tcoNum );
530 	int getTCONum(const TrackContentObject* tco );
531 
getTCOs()532 	const tcoVector & getTCOs() const
533 	{
534 		return m_trackContentObjects;
535 	}
536 	void getTCOsInRange( tcoVector & tcoV, const MidiTime & start,
537 							const MidiTime & end );
538 	void swapPositionOfTCOs( int tcoNum1, int tcoNum2 );
539 
540 	void createTCOsForBB( int bb );
541 
542 
543 	void insertTact( const MidiTime & pos );
544 	void removeTact( const MidiTime & pos );
545 
546 	tact_t length() const;
547 
548 
trackContainer()549 	inline TrackContainer* trackContainer() const
550 	{
551 		return m_trackContainer;
552 	}
553 
554 	// name-stuff
name()555 	virtual const QString & name() const
556 	{
557 		return m_name;
558 	}
559 
displayName()560 	virtual QString displayName() const
561 	{
562 		return name();
563 	}
564 
565 	using Model::dataChanged;
566 
getHeight()567 	inline int getHeight()
568 	{
569 		return m_height >= MINIMAL_TRACK_HEIGHT
570 			? m_height
571 			: DEFAULT_TRACK_HEIGHT;
572 	}
setHeight(int height)573 	inline void setHeight( int height )
574 	{
575 		m_height = height;
576 	}
577 
lock()578 	void lock()
579 	{
580 		m_processingLock.lock();
581 	}
unlock()582 	void unlock()
583 	{
584 		m_processingLock.unlock();
585 	}
tryLock()586 	bool tryLock()
587 	{
588 		return m_processingLock.tryLock();
589 	}
590 
591 	BoolModel* getMutedModel();
592 
593 public slots:
setName(const QString & newName)594 	virtual void setName( const QString & newName )
595 	{
596 		m_name = newName;
597 		emit nameChanged();
598 	}
599 
600 	void toggleSolo();
601 
602 
603 private:
604 	TrackContainer* m_trackContainer;
605 	TrackTypes m_type;
606 	QString m_name;
607 	int m_height;
608 
609 protected:
610 	BoolModel m_mutedModel;
611 private:
612 	BoolModel m_soloModel;
613 	bool m_mutedBeforeSolo;
614 
615 	bool m_simpleSerializingMode;
616 
617 	tcoVector m_trackContentObjects;
618 
619 	QMutex m_processingLock;
620 
621 	friend class TrackView;
622 
623 
624 signals:
625 	void destroyedTrack();
626 	void nameChanged();
627 	void trackContentObjectAdded( TrackContentObject * );
628 
629 } ;
630 
631 
632 
633 
634 class TrackView : public QWidget, public ModelView, public JournallingObject
635 {
636 	Q_OBJECT
637 public:
638 	TrackView( Track * _track, TrackContainerView* tcv );
639 	virtual ~TrackView();
640 
getTrack()641 	inline const Track * getTrack() const
642 	{
643 		return m_track;
644 	}
645 
getTrack()646 	inline Track * getTrack()
647 	{
648 		return m_track;
649 	}
650 
trackContainerView()651 	inline TrackContainerView* trackContainerView()
652 	{
653 		return m_trackContainerView;
654 	}
655 
getTrackOperationsWidget()656 	inline TrackOperationsWidget * getTrackOperationsWidget()
657 	{
658 		return &m_trackOperationsWidget;
659 	}
660 
getTrackSettingsWidget()661 	inline QWidget * getTrackSettingsWidget()
662 	{
663 		return &m_trackSettingsWidget;
664 	}
665 
getTrackContentWidget()666 	inline TrackContentWidget * getTrackContentWidget()
667 	{
668 		return &m_trackContentWidget;
669 	}
670 
isMovingTrack()671 	bool isMovingTrack() const
672 	{
673 		return m_action == MoveTrack;
674 	}
675 
676 	virtual void update();
677 
678 
679 public slots:
680 	virtual bool close();
681 
682 
683 protected:
684 	virtual void modelChanged();
685 
saveSettings(QDomDocument & doc,QDomElement & element)686 	virtual void saveSettings( QDomDocument& doc, QDomElement& element )
687 	{
688 		Q_UNUSED(doc)
689 		Q_UNUSED(element)
690 	}
691 
loadSettings(const QDomElement & element)692 	virtual void loadSettings( const QDomElement& element )
693 	{
694 		Q_UNUSED(element)
695 	}
696 
nodeName()697 	virtual QString nodeName() const
698 	{
699 		return "trackview";
700 	}
701 
702 
703 	virtual void dragEnterEvent( QDragEnterEvent * dee );
704 	virtual void dropEvent( QDropEvent * de );
705 	virtual void mousePressEvent( QMouseEvent * me );
706 	virtual void mouseMoveEvent( QMouseEvent * me );
707 	virtual void mouseReleaseEvent( QMouseEvent * me );
708 	virtual void paintEvent( QPaintEvent * pe );
709 	virtual void resizeEvent( QResizeEvent * re );
710 
711 
712 private:
713 	enum Actions
714 	{
715 		NoAction,
716 		MoveTrack,
717 		ResizeTrack
718 	} ;
719 
720 	Track * m_track;
721 	TrackContainerView * m_trackContainerView;
722 
723 	TrackOperationsWidget m_trackOperationsWidget;
724 	QWidget m_trackSettingsWidget;
725 	TrackContentWidget m_trackContentWidget;
726 
727 	Actions m_action;
728 
729 
730 	friend class TrackLabelButton;
731 
732 
733 private slots:
734 	void createTCOView( TrackContentObject * tco );
735 
736 } ;
737 
738 
739 
740 #endif
741