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