Split Track.cpp and Track.h (#5806) (Fixes #5592)

This commit is contained in:
Alexandre Almeida
2020-12-03 22:47:16 -03:00
committed by GitHub
parent ddf69feebc
commit b701e82e3b
39 changed files with 3821 additions and 3454 deletions

View File

@@ -30,7 +30,7 @@
#include <QtCore/QMap>
#include <QtCore/QPointer>
#include "Track.h"
#include "TrackContentObject.h"
class AutomationTrack;

View File

@@ -30,7 +30,7 @@
#include "AutomationPattern.h"
#include "Song.h"
#include "SongEditor.h"
#include "Track.h"
#include "TrackContentObjectView.h"
class AutomationPatternView : public TrackContentObjectView

View File

@@ -28,6 +28,7 @@
#define AUTOMATION_TRACK_H
#include "Track.h"
#include "TrackView.h"
class AutomationTrack : public Track

View File

@@ -26,6 +26,7 @@
#ifndef BB_EDITOR_H
#define BB_EDITOR_H
#include "Editor.h"
#include "TrackContainerView.h"

View File

@@ -31,7 +31,9 @@
#include <QtCore/QMap>
#include <QStaticText>
#include "TrackContentObjectView.h"
#include "Track.h"
#include "TrackView.h"
class TrackLabelButton;
class TrackContainer;

View File

@@ -40,6 +40,7 @@
#include "Pitch.h"
#include "Plugin.h"
#include "Track.h"
#include "TrackView.h"

View File

@@ -34,16 +34,10 @@
#include "Note.h"
#include "Track.h"
#include "TrackContentObjectView.h"
class QAction;
class QProgressBar;
class QPushButton;
class InstrumentTrack;
class SampleBuffer;
class LMMS_EXPORT Pattern : public TrackContentObject

View File

@@ -29,6 +29,7 @@
#include "NotePlayHandle.h"
class DataFile;
class InstrumentTrack;
class PreviewTrackContainer;

View File

@@ -33,6 +33,8 @@
#include "FxMixer.h"
#include "FxLineLcdSpinBox.h"
#include "Track.h"
#include "TrackContentObjectView.h"
#include "TrackView.h"
class EffectRackView;
class Knob;

View File

@@ -29,6 +29,8 @@
#include <QtCore/QSharedMemory>
#include <QtCore/QVector>
#include <QHash>
#include <QString>
#include "TrackContainer.h"
#include "Controller.h"

View File

@@ -1,6 +1,5 @@
/*
* Track.h - declaration of classes concerning tracks -> necessary for all
* track-like objects (beat/bassline, sample-track...)
* Track.h - declaration of Track class
*
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
@@ -26,43 +25,22 @@
#ifndef TRACK_H
#define TRACK_H
#include <QtCore/QVector>
#include <QtCore/QList>
#include <QWidget>
#include <QSize>
#include <QColor>
#include <QMimeData>
#include "lmms_basics.h"
#include "TimePos.h"
#include "Rubberband.h"
#include "JournallingObject.h"
#include "AutomatableModel.h"
#include "ModelView.h"
#include "DataFile.h"
#include "FadeButton.h"
#include "JournallingObject.h"
#include "lmms_basics.h"
class QMenu;
class QPushButton;
class PixmapButton;
class TextFloat;
class Track;
class TrackContentObjectView;
class TimePos;
class TrackContainer;
class TrackContainerView;
class TrackContentWidget;
class TrackContentObject;
class TrackView;
const int DEFAULT_SETTINGS_WIDGET_WIDTH = 224;
const int TRACK_OP_WIDTH = 78;
// This shaves 150-ish pixels off track buttons,
// ruled from config: ui.compacttrackbuttons
const int DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT = 96;
const int TRACK_OP_WIDTH_COMPACT = 62;
/*! The minimum track height in pixels
*
* Tracks can be resized by shift-dragging anywhere inside the track
@@ -71,483 +49,10 @@ const int TRACK_OP_WIDTH_COMPACT = 62;
const int MINIMAL_TRACK_HEIGHT = 32;
const int DEFAULT_TRACK_HEIGHT = 32;
const int TCO_BORDER_WIDTH = 2;
char const *const FILENAME_FILTER = "[\\0000-\x1f\"*/:<>?\\\\|\x7f]";
class LMMS_EXPORT TrackContentObject : public Model, public JournallingObject
{
Q_OBJECT
MM_OPERATORS
mapPropertyFromModel(bool,isMuted,setMuted,m_mutedModel);
mapPropertyFromModel(bool,isSolo,setSolo,m_soloModel);
public:
TrackContentObject( Track * track );
virtual ~TrackContentObject();
inline Track * getTrack() const
{
return m_track;
}
inline const QString & name() const
{
return m_name;
}
inline void setName( const QString & name )
{
m_name = name;
emit dataChanged();
}
QString displayName() const override
{
return name();
}
inline const TimePos & startPosition() const
{
return m_startPosition;
}
inline TimePos endPosition() const
{
const int sp = m_startPosition;
return sp + m_length;
}
inline const TimePos & length() const
{
return m_length;
}
inline void setAutoResize( const bool r )
{
m_autoResize = r;
}
inline const bool getAutoResize() const
{
return m_autoResize;
}
QColor color() const
{
return m_color;
}
void setColor( const QColor & c )
{
m_color = c;
}
bool hasColor();
void useCustomClipColor( bool b );
bool usesCustomClipColor()
{
return m_useCustomClipColor;
}
virtual void movePosition( const TimePos & pos );
virtual void changeLength( const TimePos & length );
virtual TrackContentObjectView * createView( TrackView * tv ) = 0;
inline void selectViewOnCreate( bool select )
{
m_selectViewOnCreate = select;
}
inline bool getSelectViewOnCreate()
{
return m_selectViewOnCreate;
}
/// Returns true if and only if a->startPosition() < b->startPosition()
static bool comparePosition(const TrackContentObject* a, const TrackContentObject* b);
TimePos startTimeOffset() const;
void setStartTimeOffset( const TimePos &startTimeOffset );
void updateColor();
// Will copy the state of a TCO to another TCO
static void copyStateTo( TrackContentObject *src, TrackContentObject *dst );
public slots:
void toggleMute();
signals:
void lengthChanged();
void positionChanged();
void destroyedTCO();
void trackColorChanged();
private:
enum Actions
{
NoAction,
Move,
Resize
} ;
Track * m_track;
QString m_name;
TimePos m_startPosition;
TimePos m_length;
TimePos m_startTimeOffset;
BoolModel m_mutedModel;
BoolModel m_soloModel;
bool m_autoResize;
bool m_selectViewOnCreate;
QColor m_color;
bool m_useCustomClipColor;
friend class TrackContentObjectView;
} ;
class TrackContentObjectView : public selectableObject, public ModelView
{
Q_OBJECT
// theming qproperties
Q_PROPERTY( QColor mutedColor READ mutedColor WRITE setMutedColor )
Q_PROPERTY( QColor mutedBackgroundColor READ mutedBackgroundColor WRITE setMutedBackgroundColor )
Q_PROPERTY( QColor selectedColor READ selectedColor WRITE setSelectedColor )
Q_PROPERTY( QColor textColor READ textColor WRITE setTextColor )
Q_PROPERTY( QColor textBackgroundColor READ textBackgroundColor WRITE setTextBackgroundColor )
Q_PROPERTY( QColor textShadowColor READ textShadowColor WRITE setTextShadowColor )
Q_PROPERTY( QColor BBPatternBackground READ BBPatternBackground WRITE setBBPatternBackground )
Q_PROPERTY( bool gradient READ gradient WRITE setGradient )
// We have to use a QSize here because using QPoint isn't supported.
// width -> x, height -> y
Q_PROPERTY( QSize mouseHotspotHand WRITE setMouseHotspotHand )
public:
TrackContentObjectView( TrackContentObject * tco, TrackView * tv );
virtual ~TrackContentObjectView();
bool fixedTCOs();
inline TrackContentObject * getTrackContentObject()
{
return m_tco;
}
inline TrackView * getTrackView()
{
return m_trackView;
}
// qproperty access func
QColor mutedColor() const;
QColor mutedBackgroundColor() const;
QColor selectedColor() const;
QColor textColor() const;
QColor textBackgroundColor() const;
QColor textShadowColor() const;
QColor BBPatternBackground() const;
bool gradient() const;
void setMutedColor( const QColor & c );
void setMutedBackgroundColor( const QColor & c );
void setSelectedColor( const QColor & c );
void setTextColor( const QColor & c );
void setTextBackgroundColor( const QColor & c );
void setTextShadowColor( const QColor & c );
void setBBPatternBackground( const QColor & c );
void setGradient( const bool & b );
void setMouseHotspotHand(const QSize & s);
// access needsUpdate member variable
bool needsUpdate();
void setNeedsUpdate( bool b );
// Method to get a QVector of TCOs to be affected by a context menu action
QVector<TrackContentObjectView *> getClickedTCOs();
// Methods to remove, copy, cut, paste and mute a QVector of TCO views
void copy( QVector<TrackContentObjectView *> tcovs );
void cut( QVector<TrackContentObjectView *> tcovs );
void paste();
// remove and toggleMute are static because they don't depend
// being called from a particular TCO view, but can be called anywhere as long
// as a valid TCO view list is given, while copy/cut require an instance for
// some metadata to be written to the clipboard.
static void remove( QVector<TrackContentObjectView *> tcovs );
static void toggleMute( QVector<TrackContentObjectView *> tcovs );
QColor getColorForDisplay( QColor );
public slots:
virtual bool close();
void remove();
void update() override;
void changeClipColor();
void useTrackColor();
protected:
enum ContextMenuAction
{
Remove,
Cut,
Copy,
Paste,
Mute
};
virtual void constructContextMenu( QMenu * )
{
}
void contextMenuEvent( QContextMenuEvent * cme ) override;
void contextMenuAction( ContextMenuAction action );
void dragEnterEvent( QDragEnterEvent * dee ) override;
void dropEvent( QDropEvent * de ) override;
void leaveEvent( QEvent * e ) override;
void mousePressEvent( QMouseEvent * me ) override;
void mouseMoveEvent( QMouseEvent * me ) override;
void mouseReleaseEvent( QMouseEvent * me ) override;
void resizeEvent( QResizeEvent * re ) override
{
m_needsUpdate = true;
selectableObject::resizeEvent( re );
}
float pixelsPerBar();
DataFile createTCODataFiles(const QVector<TrackContentObjectView *> & tcos) const;
virtual void paintTextLabel(QString const & text, QPainter & painter);
protected slots:
void updateLength();
void updatePosition();
private:
enum Actions
{
NoAction,
Move,
MoveSelection,
Resize,
ResizeLeft,
CopySelection,
ToggleSelected
} ;
static TextFloat * s_textFloat;
TrackContentObject * m_tco;
TrackView * m_trackView;
Actions m_action;
QPoint m_initialMousePos;
QPoint m_initialMouseGlobalPos;
TimePos m_initialTCOPos;
TimePos m_initialTCOEnd;
QVector<TimePos> m_initialOffsets;
TextFloat * m_hint;
// qproperty fields
QColor m_mutedColor;
QColor m_mutedBackgroundColor;
QColor m_selectedColor;
QColor m_textColor;
QColor m_textBackgroundColor;
QColor m_textShadowColor;
QColor m_BBPatternBackground;
bool m_gradient;
QSize m_mouseHotspotHand; // QSize must be used because QPoint isn't supported by property system
bool m_cursorSetYet;
bool m_needsUpdate;
inline void setInitialPos( QPoint pos )
{
m_initialMousePos = pos;
m_initialMouseGlobalPos = mapToGlobal( pos );
m_initialTCOPos = m_tco->startPosition();
m_initialTCOEnd = m_initialTCOPos + m_tco->length();
}
void setInitialOffsets();
bool mouseMovedDistance( QMouseEvent * me, int distance );
TimePos draggedTCOPos( QMouseEvent * me );
} ;
class TrackContentWidget : public QWidget, public JournallingObject
{
Q_OBJECT
// qproperties for track background gradients
Q_PROPERTY( QBrush darkerColor READ darkerColor WRITE setDarkerColor )
Q_PROPERTY( QBrush lighterColor READ lighterColor WRITE setLighterColor )
Q_PROPERTY( QBrush gridColor READ gridColor WRITE setGridColor )
Q_PROPERTY( QBrush embossColor READ embossColor WRITE setEmbossColor )
public:
TrackContentWidget( TrackView * parent );
virtual ~TrackContentWidget();
/*! \brief Updates the background tile pixmap. */
void updateBackground();
void addTCOView( TrackContentObjectView * tcov );
void removeTCOView( TrackContentObjectView * tcov );
void removeTCOView( int tcoNum )
{
if( tcoNum >= 0 && tcoNum < m_tcoViews.size() )
{
removeTCOView( m_tcoViews[tcoNum] );
}
}
bool canPasteSelection( TimePos tcoPos, const QDropEvent *de );
bool canPasteSelection( TimePos tcoPos, const QMimeData *md, bool allowSameBar = false );
bool pasteSelection( TimePos tcoPos, QDropEvent * de );
bool pasteSelection( TimePos tcoPos, const QMimeData * md, bool skipSafetyCheck = false );
TimePos endPosition( const TimePos & posStart );
// qproperty access methods
QBrush darkerColor() const;
QBrush lighterColor() const;
QBrush gridColor() const;
QBrush embossColor() const;
void setDarkerColor( const QBrush & c );
void setLighterColor( const QBrush & c );
void setGridColor( const QBrush & c );
void setEmbossColor( const QBrush & c);
public slots:
void update();
void changePosition( const TimePos & newPos = TimePos( -1 ) );
protected:
enum ContextMenuAction
{
Paste
};
void contextMenuEvent( QContextMenuEvent * cme ) override;
void contextMenuAction( QContextMenuEvent * cme, ContextMenuAction action );
void dragEnterEvent( QDragEnterEvent * dee ) override;
void dropEvent( QDropEvent * de ) override;
void mousePressEvent( QMouseEvent * me ) override;
void paintEvent( QPaintEvent * pe ) override;
void resizeEvent( QResizeEvent * re ) override;
QString nodeName() const override
{
return "trackcontentwidget";
}
void saveSettings( QDomDocument& doc, QDomElement& element ) override
{
Q_UNUSED(doc)
Q_UNUSED(element)
}
void loadSettings( const QDomElement& element ) override
{
Q_UNUSED(element)
}
private:
Track * getTrack();
TimePos getPosition( int mouseX );
TrackView * m_trackView;
typedef QVector<TrackContentObjectView *> tcoViewVector;
tcoViewVector m_tcoViews;
QPixmap m_background;
// qproperty fields
QBrush m_darkerColor;
QBrush m_lighterColor;
QBrush m_gridColor;
QBrush m_embossColor;
} ;
class TrackOperationsWidget : public QWidget
{
Q_OBJECT
public:
TrackOperationsWidget( TrackView * parent );
~TrackOperationsWidget();
protected:
void mousePressEvent( QMouseEvent * me ) override;
void paintEvent( QPaintEvent * pe ) override;
private slots:
void cloneTrack();
void removeTrack();
void updateMenu();
void changeTrackColor();
void randomTrackColor();
void resetTrackColor();
void useTrackColor();
void toggleRecording(bool on);
void recordingOn();
void recordingOff();
void clearTrack();
private:
TrackView * m_trackView;
QPushButton * m_trackOps;
PixmapButton * m_muteBtn;
PixmapButton * m_soloBtn;
friend class TrackView;
signals:
void trackRemovalScheduled( TrackView * t );
void colorChanged( QColor & c );
void colorParented();
void colorReset();
} ;
// base-class for all tracks
//! Base-class for all tracks
class LMMS_EXPORT Track : public Model, public JournallingObject
{
Q_OBJECT
@@ -729,122 +234,4 @@ signals:
class TrackView : public QWidget, public ModelView, public JournallingObject
{
Q_OBJECT
public:
TrackView( Track * _track, TrackContainerView* tcv );
virtual ~TrackView();
inline const Track * getTrack() const
{
return m_track;
}
inline Track * getTrack()
{
return m_track;
}
inline TrackContainerView* trackContainerView()
{
return m_trackContainerView;
}
inline TrackOperationsWidget * getTrackOperationsWidget()
{
return &m_trackOperationsWidget;
}
inline QWidget * getTrackSettingsWidget()
{
return &m_trackSettingsWidget;
}
inline TrackContentWidget * getTrackContentWidget()
{
return &m_trackContentWidget;
}
bool isMovingTrack() const
{
return m_action == MoveTrack;
}
virtual void update();
// Create a menu for assigning/creating channels for this track
// Currently instrument track and sample track supports it
virtual QMenu * createFxMenu(QString title, QString newFxLabel);
public slots:
virtual bool close();
protected:
void modelChanged() override;
void saveSettings( QDomDocument& doc, QDomElement& element ) override
{
Q_UNUSED(doc)
Q_UNUSED(element)
}
void loadSettings( const QDomElement& element ) override
{
Q_UNUSED(element)
}
QString nodeName() const override
{
return "trackview";
}
void dragEnterEvent( QDragEnterEvent * dee ) override;
void dropEvent( QDropEvent * de ) override;
void mousePressEvent( QMouseEvent * me ) override;
void mouseMoveEvent( QMouseEvent * me ) override;
void mouseReleaseEvent( QMouseEvent * me ) override;
void paintEvent( QPaintEvent * pe ) override;
void resizeEvent( QResizeEvent * re ) override;
private:
enum Actions
{
NoAction,
MoveTrack,
ResizeTrack
} ;
Track * m_track;
TrackContainerView * m_trackContainerView;
TrackOperationsWidget m_trackOperationsWidget;
QWidget m_trackSettingsWidget;
TrackContentWidget m_trackContentWidget;
Actions m_action;
virtual FadeButton * getActivityIndicator()
{
return nullptr;
}
void setIndicatorMute(FadeButton* indicator, bool muted);
friend class TrackLabelButton;
private slots:
void createTCOView( TrackContentObject * tco );
void muteChanged();
} ;
#endif

View File

@@ -31,12 +31,15 @@
#include <QWidget>
#include <QThread>
#include "Track.h"
#include "JournallingObject.h"
#include "InstrumentTrack.h"
#include "ModelView.h"
#include "Rubberband.h"
#include "TrackView.h"
class QVBoxLayout;
class InstrumentTrack;
class TrackContainer;

View File

@@ -0,0 +1,183 @@
/*
* TrackConteintObject.h - declaration of TrackContentObject class
*
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* 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 (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef TRACK_CONTENT_OBJECT_H
#define TRACK_CONTENT_OBJECT_H
#include <QColor>
#include "AutomatableModel.h"
#include "lmms_basics.h"
class Track;
class TrackContentObjectView;
class TrackContainer;
class TrackView;
class LMMS_EXPORT TrackContentObject : public Model, public JournallingObject
{
Q_OBJECT
MM_OPERATORS
mapPropertyFromModel(bool,isMuted,setMuted,m_mutedModel);
mapPropertyFromModel(bool,isSolo,setSolo,m_soloModel);
public:
TrackContentObject( Track * track );
virtual ~TrackContentObject();
inline Track * getTrack() const
{
return m_track;
}
inline const QString & name() const
{
return m_name;
}
inline void setName( const QString & name )
{
m_name = name;
emit dataChanged();
}
QString displayName() const override
{
return name();
}
inline const TimePos & startPosition() const
{
return m_startPosition;
}
inline TimePos endPosition() const
{
const int sp = m_startPosition;
return sp + m_length;
}
inline const TimePos & length() const
{
return m_length;
}
inline void setAutoResize( const bool r )
{
m_autoResize = r;
}
inline const bool getAutoResize() const
{
return m_autoResize;
}
QColor color() const
{
return m_color;
}
void setColor( const QColor & c )
{
m_color = c;
}
bool hasColor();
void useCustomClipColor( bool b );
bool usesCustomClipColor()
{
return m_useCustomClipColor;
}
virtual void movePosition( const TimePos & pos );
virtual void changeLength( const TimePos & length );
virtual TrackContentObjectView * createView( TrackView * tv ) = 0;
inline void selectViewOnCreate( bool select )
{
m_selectViewOnCreate = select;
}
inline bool getSelectViewOnCreate()
{
return m_selectViewOnCreate;
}
/// Returns true if and only if a->startPosition() < b->startPosition()
static bool comparePosition(const TrackContentObject* a, const TrackContentObject* b);
TimePos startTimeOffset() const;
void setStartTimeOffset( const TimePos &startTimeOffset );
void updateColor();
// Will copy the state of a TCO to another TCO
static void copyStateTo( TrackContentObject *src, TrackContentObject *dst );
public slots:
void toggleMute();
signals:
void lengthChanged();
void positionChanged();
void destroyedTCO();
void trackColorChanged();
private:
enum Actions
{
NoAction,
Move,
Resize
} ;
Track * m_track;
QString m_name;
TimePos m_startPosition;
TimePos m_length;
TimePos m_startTimeOffset;
BoolModel m_mutedModel;
BoolModel m_soloModel;
bool m_autoResize;
bool m_selectViewOnCreate;
QColor m_color;
bool m_useCustomClipColor;
friend class TrackContentObjectView;
} ;
#endif

View File

@@ -0,0 +1,218 @@
/*
* TrackContentObjectView.h - declaration of TrackContentObjectView class
*
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* 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 (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef TRACK_CONTENT_OBJECT_VIEW_H
#define TRACK_CONTENT_OBJECT_VIEW_H
#include <QtCore/QVector>
#include "ModelView.h"
#include "Rubberband.h"
#include "TrackContentObject.h"
class QMenu;
class QContextMenuEvent;
class DataFile;
class TextFloat;
class TrackContentObject;
class TrackView;
class TrackContentObjectView : public selectableObject, public ModelView
{
Q_OBJECT
// theming qproperties
Q_PROPERTY( QColor mutedColor READ mutedColor WRITE setMutedColor )
Q_PROPERTY( QColor mutedBackgroundColor READ mutedBackgroundColor WRITE setMutedBackgroundColor )
Q_PROPERTY( QColor selectedColor READ selectedColor WRITE setSelectedColor )
Q_PROPERTY( QColor textColor READ textColor WRITE setTextColor )
Q_PROPERTY( QColor textBackgroundColor READ textBackgroundColor WRITE setTextBackgroundColor )
Q_PROPERTY( QColor textShadowColor READ textShadowColor WRITE setTextShadowColor )
Q_PROPERTY( QColor BBPatternBackground READ BBPatternBackground WRITE setBBPatternBackground )
Q_PROPERTY( bool gradient READ gradient WRITE setGradient )
// We have to use a QSize here because using QPoint isn't supported.
// width -> x, height -> y
Q_PROPERTY( QSize mouseHotspotHand WRITE setMouseHotspotHand )
public:
TrackContentObjectView( TrackContentObject * tco, TrackView * tv );
virtual ~TrackContentObjectView();
bool fixedTCOs();
inline TrackContentObject * getTrackContentObject()
{
return m_tco;
}
inline TrackView * getTrackView()
{
return m_trackView;
}
// qproperty access func
QColor mutedColor() const;
QColor mutedBackgroundColor() const;
QColor selectedColor() const;
QColor textColor() const;
QColor textBackgroundColor() const;
QColor textShadowColor() const;
QColor BBPatternBackground() const;
bool gradient() const;
void setMutedColor( const QColor & c );
void setMutedBackgroundColor( const QColor & c );
void setSelectedColor( const QColor & c );
void setTextColor( const QColor & c );
void setTextBackgroundColor( const QColor & c );
void setTextShadowColor( const QColor & c );
void setBBPatternBackground( const QColor & c );
void setGradient( const bool & b );
void setMouseHotspotHand(const QSize & s);
// access needsUpdate member variable
bool needsUpdate();
void setNeedsUpdate( bool b );
// Method to get a QVector of TCOs to be affected by a context menu action
QVector<TrackContentObjectView *> getClickedTCOs();
// Methods to remove, copy, cut, paste and mute a QVector of TCO views
void copy( QVector<TrackContentObjectView *> tcovs );
void cut( QVector<TrackContentObjectView *> tcovs );
void paste();
// remove and toggleMute are static because they don't depend
// being called from a particular TCO view, but can be called anywhere as long
// as a valid TCO view list is given, while copy/cut require an instance for
// some metadata to be written to the clipboard.
static void remove( QVector<TrackContentObjectView *> tcovs );
static void toggleMute( QVector<TrackContentObjectView *> tcovs );
QColor getColorForDisplay( QColor );
public slots:
virtual bool close();
void remove();
void update() override;
void changeClipColor();
void useTrackColor();
protected:
enum ContextMenuAction
{
Remove,
Cut,
Copy,
Paste,
Mute
};
virtual void constructContextMenu( QMenu * )
{
}
void contextMenuEvent( QContextMenuEvent * cme ) override;
void contextMenuAction( ContextMenuAction action );
void dragEnterEvent( QDragEnterEvent * dee ) override;
void dropEvent( QDropEvent * de ) override;
void leaveEvent( QEvent * e ) override;
void mousePressEvent( QMouseEvent * me ) override;
void mouseMoveEvent( QMouseEvent * me ) override;
void mouseReleaseEvent( QMouseEvent * me ) override;
void resizeEvent( QResizeEvent * re ) override
{
m_needsUpdate = true;
selectableObject::resizeEvent( re );
}
float pixelsPerBar();
DataFile createTCODataFiles(const QVector<TrackContentObjectView *> & tcos) const;
virtual void paintTextLabel(QString const & text, QPainter & painter);
protected slots:
void updateLength();
void updatePosition();
private:
enum Actions
{
NoAction,
Move,
MoveSelection,
Resize,
ResizeLeft,
CopySelection,
ToggleSelected
} ;
static TextFloat * s_textFloat;
TrackContentObject * m_tco;
TrackView * m_trackView;
Actions m_action;
QPoint m_initialMousePos;
QPoint m_initialMouseGlobalPos;
TimePos m_initialTCOPos;
TimePos m_initialTCOEnd;
QVector<TimePos> m_initialOffsets;
TextFloat * m_hint;
// qproperty fields
QColor m_mutedColor;
QColor m_mutedBackgroundColor;
QColor m_selectedColor;
QColor m_textColor;
QColor m_textBackgroundColor;
QColor m_textShadowColor;
QColor m_BBPatternBackground;
bool m_gradient;
QSize m_mouseHotspotHand; // QSize must be used because QPoint isn't supported by property system
bool m_cursorSetYet;
bool m_needsUpdate;
inline void setInitialPos( QPoint pos )
{
m_initialMousePos = pos;
m_initialMouseGlobalPos = mapToGlobal( pos );
m_initialTCOPos = m_tco->startPosition();
m_initialTCOEnd = m_initialTCOPos + m_tco->length();
}
void setInitialOffsets();
bool mouseMovedDistance( QMouseEvent * me, int distance );
TimePos draggedTCOPos( QMouseEvent * me );
} ;
#endif

View File

@@ -0,0 +1,142 @@
/*
* TrackContentWidget.h - declaration of TrackContentWidget class
*
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* 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 (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef TRACK_CONTENT_WIDGET_H
#define TRACK_CONTENT_WIDGET_H
#include <QWidget>
#include "JournallingObject.h"
#include "TimePos.h"
class QMimeData;
class Track;
class TrackContentObjectView;
class TrackView;
class TrackContentWidget : public QWidget, public JournallingObject
{
Q_OBJECT
// qproperties for track background gradients
Q_PROPERTY( QBrush darkerColor READ darkerColor WRITE setDarkerColor )
Q_PROPERTY( QBrush lighterColor READ lighterColor WRITE setLighterColor )
Q_PROPERTY( QBrush gridColor READ gridColor WRITE setGridColor )
Q_PROPERTY( QBrush embossColor READ embossColor WRITE setEmbossColor )
public:
TrackContentWidget( TrackView * parent );
virtual ~TrackContentWidget();
/*! \brief Updates the background tile pixmap. */
void updateBackground();
void addTCOView( TrackContentObjectView * tcov );
void removeTCOView( TrackContentObjectView * tcov );
void removeTCOView( int tcoNum )
{
if( tcoNum >= 0 && tcoNum < m_tcoViews.size() )
{
removeTCOView( m_tcoViews[tcoNum] );
}
}
bool canPasteSelection( TimePos tcoPos, const QDropEvent *de );
bool canPasteSelection( TimePos tcoPos, const QMimeData *md, bool allowSameBar = false );
bool pasteSelection( TimePos tcoPos, QDropEvent * de );
bool pasteSelection( TimePos tcoPos, const QMimeData * md, bool skipSafetyCheck = false );
TimePos endPosition( const TimePos & posStart );
// qproperty access methods
QBrush darkerColor() const;
QBrush lighterColor() const;
QBrush gridColor() const;
QBrush embossColor() const;
void setDarkerColor( const QBrush & c );
void setLighterColor( const QBrush & c );
void setGridColor( const QBrush & c );
void setEmbossColor( const QBrush & c);
public slots:
void update();
void changePosition( const TimePos & newPos = TimePos( -1 ) );
protected:
enum ContextMenuAction
{
Paste
};
void contextMenuEvent( QContextMenuEvent * cme ) override;
void contextMenuAction( QContextMenuEvent * cme, ContextMenuAction action );
void dragEnterEvent( QDragEnterEvent * dee ) override;
void dropEvent( QDropEvent * de ) override;
void mousePressEvent( QMouseEvent * me ) override;
void paintEvent( QPaintEvent * pe ) override;
void resizeEvent( QResizeEvent * re ) override;
QString nodeName() const override
{
return "trackcontentwidget";
}
void saveSettings( QDomDocument& doc, QDomElement& element ) override
{
Q_UNUSED(doc)
Q_UNUSED(element)
}
void loadSettings( const QDomElement& element ) override
{
Q_UNUSED(element)
}
private:
Track * getTrack();
TimePos getPosition( int mouseX );
TrackView * m_trackView;
typedef QVector<TrackContentObjectView *> tcoViewVector;
tcoViewVector m_tcoViews;
QPixmap m_background;
// qproperty fields
QBrush m_darkerColor;
QBrush m_lighterColor;
QBrush m_gridColor;
QBrush m_embossColor;
} ;
#endif

View File

@@ -0,0 +1,79 @@
/*
* TrackOperationsWidget.h - declaration of TrackOperationsWidget class
*
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* 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 (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef TRACK_OPERATIONS_WIDGET_H
#define TRACK_OPERATIONS_WIDGET_H
#include <QWidget>
class QPushButton;
class PixmapButton;
class TrackView;
class TrackOperationsWidget : public QWidget
{
Q_OBJECT
public:
TrackOperationsWidget( TrackView * parent );
~TrackOperationsWidget();
protected:
void mousePressEvent( QMouseEvent * me ) override;
void paintEvent( QPaintEvent * pe ) override;
private slots:
void cloneTrack();
void removeTrack();
void updateMenu();
void changeTrackColor();
void randomTrackColor();
void resetTrackColor();
void useTrackColor();
void toggleRecording(bool on);
void recordingOn();
void recordingOff();
void clearTrack();
private:
TrackView * m_trackView;
QPushButton * m_trackOps;
PixmapButton * m_muteBtn;
PixmapButton * m_soloBtn;
friend class TrackView;
signals:
void trackRemovalScheduled( TrackView * t );
void colorChanged( QColor & c );
void colorParented();
void colorReset();
} ;
#endif

173
include/TrackView.h Normal file
View File

@@ -0,0 +1,173 @@
/*
* TrackView.h - declaration of TrackView class
*
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* 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 (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef TRACK_VIEW_H
#define TRACK_VIEW_H
#include <QWidget>
#include "JournallingObject.h"
#include "ModelView.h"
#include "TrackContentWidget.h"
#include "TrackOperationsWidget.h"
class QMenu;
class FadeButton;
class Track;
class TrackContainerView;
class TrackContentObject;
const int DEFAULT_SETTINGS_WIDGET_WIDTH = 224;
const int TRACK_OP_WIDTH = 78;
// This shaves 150-ish pixels off track buttons,
// ruled from config: ui.compacttrackbuttons
const int DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT = 96;
const int TRACK_OP_WIDTH_COMPACT = 62;
const int TCO_BORDER_WIDTH = 2;
class TrackView : public QWidget, public ModelView, public JournallingObject
{
Q_OBJECT
public:
TrackView( Track * _track, TrackContainerView* tcv );
virtual ~TrackView();
inline const Track * getTrack() const
{
return m_track;
}
inline Track * getTrack()
{
return m_track;
}
inline TrackContainerView* trackContainerView()
{
return m_trackContainerView;
}
inline TrackOperationsWidget * getTrackOperationsWidget()
{
return &m_trackOperationsWidget;
}
inline QWidget * getTrackSettingsWidget()
{
return &m_trackSettingsWidget;
}
inline TrackContentWidget * getTrackContentWidget()
{
return &m_trackContentWidget;
}
bool isMovingTrack() const
{
return m_action == MoveTrack;
}
virtual void update();
// Create a menu for assigning/creating channels for this track
// Currently instrument track and sample track supports it
virtual QMenu * createFxMenu(QString title, QString newFxLabel);
public slots:
virtual bool close();
protected:
void modelChanged() override;
void saveSettings( QDomDocument& doc, QDomElement& element ) override
{
Q_UNUSED(doc)
Q_UNUSED(element)
}
void loadSettings( const QDomElement& element ) override
{
Q_UNUSED(element)
}
QString nodeName() const override
{
return "trackview";
}
void dragEnterEvent( QDragEnterEvent * dee ) override;
void dropEvent( QDropEvent * de ) override;
void mousePressEvent( QMouseEvent * me ) override;
void mouseMoveEvent( QMouseEvent * me ) override;
void mouseReleaseEvent( QMouseEvent * me ) override;
void paintEvent( QPaintEvent * pe ) override;
void resizeEvent( QResizeEvent * re ) override;
private:
enum Actions
{
NoAction,
MoveTrack,
ResizeTrack
} ;
Track * m_track;
TrackContainerView * m_trackContainerView;
TrackOperationsWidget m_trackOperationsWidget;
QWidget m_trackSettingsWidget;
TrackContentWidget m_trackContentWidget;
Actions m_action;
virtual FadeButton * getActivityIndicator()
{
return nullptr;
}
void setIndicatorMute(FadeButton* indicator, bool muted);
friend class TrackLabelButton;
private slots:
void createTCOView( TrackContentObject * tco );
void muteChanged();
} ;
#endif

View File

@@ -35,6 +35,7 @@
#include "lmms_math.h"
#include "TrackContainer.h"
#include "BBTrack.h"
#include "DataFile.h"
#include "InstrumentTrack.h"
#include "LocaleHelper.h"

View File

@@ -71,6 +71,7 @@ set(LMMS_SRCS
core/ToolPlugin.cpp
core/Track.cpp
core/TrackContainer.cpp
core/TrackContentObject.cpp
core/ValueBuffer.cpp
core/VstSyncController.cpp
core/StepRecorder.cpp

View File

@@ -48,6 +48,8 @@
#include "FxMixerView.h"
#include "GuiApplication.h"
#include "ExportFilter.h"
#include "InstrumentTrack.h"
#include "NotePlayHandle.h"
#include "Pattern.h"
#include "PianoRoll.h"
#include "ProjectJournal.h"

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,206 @@
/*
* TrackContentObject.cpp - implementation of TrackContentObject class
*
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* 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 (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include "TrackContentObject.h"
#include <QDomDocument>
#include "AutomationEditor.h"
#include "AutomationPattern.h"
#include "Engine.h"
#include "GuiApplication.h"
#include "Song.h"
/*! \brief Create a new TrackContentObject
*
* Creates a new track content object for the given track.
*
* \param _track The track that will contain the new object
*/
TrackContentObject::TrackContentObject( Track * track ) :
Model( track ),
m_track( track ),
m_startPosition(),
m_length(),
m_mutedModel( false, this, tr( "Mute" ) ),
m_selectViewOnCreate( false ),
m_color( 128, 128, 128 ),
m_useCustomClipColor( false )
{
if( getTrack() )
{
getTrack()->addTCO( this );
}
setJournalling( false );
movePosition( 0 );
changeLength( 0 );
setJournalling( true );
}
/*! \brief Destroy a TrackContentObject
*
* Destroys the given track content object.
*
*/
TrackContentObject::~TrackContentObject()
{
emit destroyedTCO();
if( getTrack() )
{
getTrack()->removeTCO( this );
}
}
/*! \brief Move this TrackContentObject's position in time
*
* If the track content object has moved, update its position. We
* also add a journal entry for undo and update the display.
*
* \param _pos The new position of the track content object.
*/
void TrackContentObject::movePosition( const TimePos & pos )
{
TimePos newPos = qMax(0, pos.getTicks());
if (m_startPosition != newPos)
{
Engine::mixer()->requestChangeInModel();
m_startPosition = newPos;
Engine::mixer()->doneChangeInModel();
Engine::getSong()->updateLength();
emit positionChanged();
}
}
/*! \brief Change the length of this TrackContentObject
*
* If the track content object's length has changed, update it. We
* also add a journal entry for undo and update the display.
*
* \param _length The new length of the track content object.
*/
void TrackContentObject::changeLength( const TimePos & length )
{
m_length = length;
Engine::getSong()->updateLength();
emit lengthChanged();
}
bool TrackContentObject::comparePosition(const TrackContentObject *a, const TrackContentObject *b)
{
return a->startPosition() < b->startPosition();
}
/*! \brief Copies the state of a TrackContentObject to another TrackContentObject
*
* This method copies the state of a TCO to another TCO
*/
void TrackContentObject::copyStateTo( TrackContentObject *src, TrackContentObject *dst )
{
// If the node names match we copy the state
if( src->nodeName() == dst->nodeName() ){
QDomDocument doc;
QDomElement parent = doc.createElement( "StateCopy" );
src->saveState( doc, parent );
const TimePos pos = dst->startPosition();
dst->restoreState( parent.firstChild().toElement() );
dst->movePosition( pos );
AutomationPattern::resolveAllIDs();
GuiApplication::instance()->automationEditor()->m_editor->updateAfterPatternChange();
}
}
/*! \brief Mutes this TrackContentObject
*
* Restore the previous state of this track content object. This will
* restore the position or the length of the track content object
* depending on what was changed.
*
* \param _je The journal entry to undo
*/
void TrackContentObject::toggleMute()
{
m_mutedModel.setValue( !m_mutedModel.value() );
emit dataChanged();
}
TimePos TrackContentObject::startTimeOffset() const
{
return m_startTimeOffset;
}
void TrackContentObject::setStartTimeOffset( const TimePos &startTimeOffset )
{
m_startTimeOffset = startTimeOffset;
}
// Update TCO color if it follows the track color
void TrackContentObject::updateColor()
{
if( ! m_useCustomClipColor )
{
emit trackColorChanged();
}
}
void TrackContentObject::useCustomClipColor( bool b )
{
m_useCustomClipColor = b;
updateColor();
}
bool TrackContentObject::hasColor()
{
return usesCustomClipColor() || getTrack()->useColor();
}

View File

@@ -59,6 +59,7 @@
#include "MainApplication.h"
#include "ConfigManager.h"
#include "DataFile.h"
#include "NotePlayHandle.h"
#include "embed.h"
#include "Engine.h"

View File

@@ -35,6 +35,8 @@ SET(LMMS_SRCS
gui/TimeLineWidget.cpp
gui/ToolPluginView.cpp
gui/TrackContainerView.cpp
gui/TrackContentObjectView.cpp
gui/TrackView.cpp
gui/dialogs/FileDialog.cpp
gui/dialogs/VersionedSaveDialog.cpp
@@ -98,6 +100,8 @@ SET(LMMS_SRCS
gui/widgets/ToolButton.cpp
gui/widgets/ToolTip.cpp
gui/widgets/TrackLabelButton.cpp
gui/widgets/TrackContentWidget.cpp
gui/widgets/TrackOperationsWidget.cpp
gui/widgets/TrackRenameLineEdit.cpp
gui/widgets/StepRecorderWidget.cpp

View File

@@ -39,6 +39,7 @@
#include "FileBrowser.h"
#include "BBTrackContainer.h"
#include "ConfigManager.h"
#include "DataFile.h"
#include "embed.h"
#include "Engine.h"
#include "GuiApplication.h"

View File

@@ -34,6 +34,7 @@
#include "ConfigManager.h"
#include "ControllerRackView.h"
#include "FxMixerView.h"
#include "InstrumentTrack.h"
#include "MainWindow.h"
#include "PianoRoll.h"
#include "ProjectNotes.h"

View File

@@ -32,6 +32,7 @@
#include <QMdiArea>
#include <QMenuBar>
#include <QMessageBox>
#include <QScrollBar>
#include <QShortcut>
#include <QLibrary>
#include <QSplitter>
@@ -50,6 +51,7 @@
#include "FxMixerView.h"
#include "GuiApplication.h"
#include "ImportFilter.h"
#include "InstrumentTrack.h"
#include "PianoRoll.h"
#include "PluginBrowser.h"
#include "PluginFactory.h"
@@ -71,6 +73,7 @@
#include "lmmsversion.h"
#if !defined(LMMS_BUILD_WIN32) && !defined(LMMS_BUILD_APPLE) && !defined(LMMS_BUILD_HAIKU)
//Work around an issue on KDE5 as per https://bugs.kde.org/show_bug.cgi?id=337491#c21
void disableAutoKeyAccelerators(QWidget* mainWindow)

View File

@@ -29,15 +29,18 @@
#include <QApplication>
#include <QLayout>
#include <QMdiArea>
#include <QScrollBar>
#include <QWheelEvent>
#include "TrackContainer.h"
#include "BBTrack.h"
#include "DataFile.h"
#include "MainWindow.h"
#include "Mixer.h"
#include "FileBrowser.h"
#include "ImportFilter.h"
#include "Instrument.h"
#include "InstrumentTrack.h"
#include "Song.h"
#include "StringPairDrag.h"
#include "GuiApplication.h"

File diff suppressed because it is too large Load Diff

458
src/gui/TrackView.cpp Normal file
View File

@@ -0,0 +1,458 @@
/*
* TrackView.cpp - implementation of TrackView class
*
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* 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 (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include "TrackView.h"
#include <QApplication>
#include <QHBoxLayout>
#include <QMenu>
#include <QMouseEvent>
#include <QPainter>
#include <QStyleOption>
#include <QtGlobal>
#include "ConfigManager.h"
#include "DataFile.h"
#include "Engine.h"
#include "FadeButton.h"
#include "Mixer.h"
#include "PixmapButton.h"
#include "StringPairDrag.h"
#include "ToolTip.h"
#include "Track.h"
#include "TrackContainerView.h"
#include "TrackContentObjectView.h"
/*! \brief Create a new track View.
*
* The track View is handles the actual display of the track, including
* displaying its various widgets and the track segments.
*
* \param track The track to display.
* \param tcv The track Container View for us to be displayed in.
* \todo Is my description of these properties correct?
*/
TrackView::TrackView( Track * track, TrackContainerView * tcv ) :
QWidget( tcv->contentWidget() ), /*!< The Track Container View's content widget. */
ModelView( NULL, this ), /*!< The model view of this track */
m_track( track ), /*!< The track we're displaying */
m_trackContainerView( tcv ), /*!< The track Container View we're displayed in */
m_trackOperationsWidget( this ), /*!< Our trackOperationsWidget */
m_trackSettingsWidget( this ), /*!< Our trackSettingsWidget */
m_trackContentWidget( this ), /*!< Our trackContentWidget */
m_action( NoAction ) /*!< The action we're currently performing */
{
setAutoFillBackground( true );
QPalette pal;
pal.setColor( backgroundRole(), QColor( 32, 36, 40 ) );
setPalette( pal );
m_trackSettingsWidget.setAutoFillBackground( true );
QHBoxLayout * layout = new QHBoxLayout( this );
layout->setMargin( 0 );
layout->setSpacing( 0 );
layout->addWidget( &m_trackOperationsWidget );
layout->addWidget( &m_trackSettingsWidget );
layout->addWidget( &m_trackContentWidget, 1 );
setFixedHeight( m_track->getHeight() );
resizeEvent( NULL );
setAcceptDrops( true );
setAttribute( Qt::WA_DeleteOnClose, true );
connect( m_track, SIGNAL( destroyedTrack() ), this, SLOT( close() ) );
connect( m_track,
SIGNAL( trackContentObjectAdded( TrackContentObject * ) ),
this, SLOT( createTCOView( TrackContentObject * ) ),
Qt::QueuedConnection );
connect( &m_track->m_mutedModel, SIGNAL( dataChanged() ),
&m_trackContentWidget, SLOT( update() ) );
connect(&m_track->m_mutedModel, SIGNAL(dataChanged()),
this, SLOT(muteChanged()));
connect( &m_track->m_soloModel, SIGNAL( dataChanged() ),
m_track, SLOT( toggleSolo() ), Qt::DirectConnection );
connect( &m_trackOperationsWidget, SIGNAL( colorChanged( QColor & ) ),
m_track, SLOT( trackColorChanged( QColor & ) ) );
connect( &m_trackOperationsWidget, SIGNAL( colorReset() ),
m_track, SLOT( trackColorReset() ) );
// create views for already existing TCOs
for( Track::tcoVector::iterator it =
m_track->m_trackContentObjects.begin();
it != m_track->m_trackContentObjects.end(); ++it )
{
createTCOView( *it );
}
m_trackContainerView->addTrackView( this );
}
/*! \brief Destroy this track View.
*
*/
TrackView::~TrackView()
{
}
/*! \brief Resize this track View.
*
* \param re the Resize Event to handle.
*/
void TrackView::resizeEvent( QResizeEvent * re )
{
if( ConfigManager::inst()->value( "ui",
"compacttrackbuttons" ).toInt() )
{
m_trackOperationsWidget.setFixedSize( TRACK_OP_WIDTH_COMPACT, height() - 1 );
m_trackSettingsWidget.setFixedSize( DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT, height() - 1 );
}
else
{
m_trackOperationsWidget.setFixedSize( TRACK_OP_WIDTH, height() - 1 );
m_trackSettingsWidget.setFixedSize( DEFAULT_SETTINGS_WIDGET_WIDTH, height() - 1 );
}
m_trackContentWidget.setFixedHeight( height() );
}
/*! \brief Update this track View and all its content objects.
*
*/
void TrackView::update()
{
m_trackContentWidget.update();
if( !m_trackContainerView->fixedTCOs() )
{
m_trackContentWidget.changePosition();
}
QWidget::update();
}
/*! \brief Create a menu for assigning/creating channels for this track.
*
*/
QMenu * TrackView::createFxMenu(QString title, QString newFxLabel)
{
Q_UNUSED(title)
Q_UNUSED(newFxLabel)
return NULL;
}
/*! \brief Close this track View.
*
*/
bool TrackView::close()
{
m_trackContainerView->removeTrackView( this );
return QWidget::close();
}
/*! \brief Register that the model of this track View has changed.
*
*/
void TrackView::modelChanged()
{
m_track = castModel<Track>();
Q_ASSERT( m_track != NULL );
connect( m_track, SIGNAL( destroyedTrack() ), this, SLOT( close() ) );
m_trackOperationsWidget.m_muteBtn->setModel( &m_track->m_mutedModel );
m_trackOperationsWidget.m_soloBtn->setModel( &m_track->m_soloModel );
ModelView::modelChanged();
setFixedHeight( m_track->getHeight() );
}
/*! \brief Start a drag event on this track View.
*
* \param dee the DragEnterEvent to start.
*/
void TrackView::dragEnterEvent( QDragEnterEvent * dee )
{
StringPairDrag::processDragEnterEvent( dee, "track_" +
QString::number( m_track->type() ) );
}
/*! \brief Accept a drop event on this track View.
*
* We only accept drop events that are of the same type as this track.
* If so, we decode the data from the drop event by just feeding it
* back into the engine as a state.
*
* \param de the DropEvent to handle.
*/
void TrackView::dropEvent( QDropEvent * de )
{
QString type = StringPairDrag::decodeKey( de );
QString value = StringPairDrag::decodeValue( de );
if( type == ( "track_" + QString::number( m_track->type() ) ) )
{
// value contains our XML-data so simply create a
// DataFile which does the rest for us...
DataFile dataFile( value.toUtf8() );
Engine::mixer()->requestChangeInModel();
m_track->restoreState( dataFile.content().firstChild().toElement() );
Engine::mixer()->doneChangeInModel();
de->accept();
}
}
/*! \brief Handle a mouse press event on this track View.
*
* If this track container supports rubber band selection, let the
* widget handle that and don't bother with any other handling.
*
* If the left mouse button is pressed, we handle two things. If
* SHIFT is pressed, then we resize vertically. Otherwise we start
* the process of moving this track to a new position.
*
* Otherwise we let the widget handle the mouse event as normal.
*
* \param me the MouseEvent to handle.
*/
void TrackView::mousePressEvent( QMouseEvent * me )
{
// If previously dragged too small, restore on shift-leftclick
if( height() < DEFAULT_TRACK_HEIGHT &&
me->modifiers() & Qt::ShiftModifier &&
me->button() == Qt::LeftButton )
{
setFixedHeight( DEFAULT_TRACK_HEIGHT );
m_track->setHeight( DEFAULT_TRACK_HEIGHT );
}
int widgetTotal = ConfigManager::inst()->value( "ui",
"compacttrackbuttons" ).toInt()==1 ?
DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT + TRACK_OP_WIDTH_COMPACT :
DEFAULT_SETTINGS_WIDGET_WIDTH + TRACK_OP_WIDTH;
if( m_trackContainerView->allowRubberband() == true && me->x() > widgetTotal )
{
QWidget::mousePressEvent( me );
}
else if( me->button() == Qt::LeftButton )
{
if( me->modifiers() & Qt::ShiftModifier )
{
m_action = ResizeTrack;
QCursor::setPos( mapToGlobal( QPoint( me->x(),
height() ) ) );
QCursor c( Qt::SizeVerCursor);
QApplication::setOverrideCursor( c );
}
else
{
if( me->x()>10 ) // 10 = The width of the grip + 2 pixels to the left and right.
{
QWidget::mousePressEvent( me );
return;
}
m_action = MoveTrack;
QCursor c( Qt::SizeVerCursor );
QApplication::setOverrideCursor( c );
// update because in move-mode, all elements in
// track-op-widgets are hidden as a visual feedback
m_trackOperationsWidget.update();
}
me->accept();
}
else
{
QWidget::mousePressEvent( me );
}
}
/*! \brief Handle a mouse move event on this track View.
*
* If this track container supports rubber band selection, let the
* widget handle that and don't bother with any other handling.
*
* Otherwise if we've started the move process (from mousePressEvent())
* then move ourselves into that position, reordering the track list
* with moveTrackViewUp() and moveTrackViewDown() to suit. We make a
* note of this in the undo journal in case the user wants to undo this
* move.
*
* Likewise if we've started a resize process, handle this too, making
* sure that we never go below the minimum track height.
*
* \param me the MouseEvent to handle.
*/
void TrackView::mouseMoveEvent( QMouseEvent * me )
{
int widgetTotal = ConfigManager::inst()->value( "ui",
"compacttrackbuttons" ).toInt()==1 ?
DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT + TRACK_OP_WIDTH_COMPACT :
DEFAULT_SETTINGS_WIDGET_WIDTH + TRACK_OP_WIDTH;
if( m_trackContainerView->allowRubberband() == true && me->x() > widgetTotal )
{
QWidget::mouseMoveEvent( me );
}
else if( m_action == MoveTrack )
{
// look which track-widget the mouse-cursor is over
const int yPos =
m_trackContainerView->contentWidget()->mapFromGlobal( me->globalPos() ).y();
const TrackView * trackAtY = m_trackContainerView->trackViewAt( yPos );
// debug code
// qDebug( "y position %d", yPos );
// a track-widget not equal to ourself?
if( trackAtY != NULL && trackAtY != this )
{
// then move us up/down there!
if( me->y() < 0 )
{
m_trackContainerView->moveTrackViewUp( this );
}
else
{
m_trackContainerView->moveTrackViewDown( this );
}
}
}
else if( m_action == ResizeTrack )
{
setFixedHeight( qMax<int>( me->y(), MINIMAL_TRACK_HEIGHT ) );
m_trackContainerView->realignTracks();
m_track->setHeight( height() );
}
if( height() < DEFAULT_TRACK_HEIGHT )
{
ToolTip::add( this, m_track->m_name );
}
}
/*! \brief Handle a mouse release event on this track View.
*
* \param me the MouseEvent to handle.
*/
void TrackView::mouseReleaseEvent( QMouseEvent * me )
{
m_action = NoAction;
while( QApplication::overrideCursor() != NULL )
{
QApplication::restoreOverrideCursor();
}
m_trackOperationsWidget.update();
QWidget::mouseReleaseEvent( me );
}
/*! \brief Repaint this track View.
*
* \param pe the PaintEvent to start.
*/
void TrackView::paintEvent( QPaintEvent * pe )
{
QStyleOption opt;
opt.initFrom( this );
QPainter p( this );
style()->drawPrimitive( QStyle::PE_Widget, &opt, &p, this );
}
/*! \brief Create a TrackContentObject View in this track View.
*
* \param tco the TrackContentObject to create the view for.
* \todo is this a good description for what this method does?
*/
void TrackView::createTCOView( TrackContentObject * tco )
{
TrackContentObjectView * tv = tco->createView( this );
if( tco->getSelectViewOnCreate() == true )
{
tv->setSelected( true );
}
tco->selectViewOnCreate( false );
}
void TrackView::muteChanged()
{
FadeButton * indicator = getActivityIndicator();
if (indicator) { setIndicatorMute(indicator, m_track->m_mutedModel.value()); }
}
void TrackView::setIndicatorMute(FadeButton* indicator, bool muted)
{
QPalette::ColorRole role = muted ? QPalette::Highlight : QPalette::BrightText;
indicator->setActiveColor(QApplication::palette().color(QPalette::Active, role));
}

View File

@@ -31,6 +31,7 @@
#include "ComboBox.h"
#include "BBTrack.h"
#include "BBTrackContainer.h"
#include "DataFile.h"
#include "embed.h"
#include "MainWindow.h"
#include "Song.h"

View File

@@ -52,6 +52,7 @@
#include "Clipboard.h"
#include "ComboBox.h"
#include "ConfigManager.h"
#include "DataFile.h"
#include "debug.h"
#include "DeprecationHelper.h"
#include "DetuningHelper.h"

View File

@@ -31,6 +31,7 @@
#include <QMdiArea>
#include <QMdiSubWindow>
#include <QPainter>
#include <QScrollBar>
#include <QTimeLine>
#include "AudioDevice.h"
@@ -293,7 +294,7 @@ float SongEditor::getSnapSize() const
{
val = val - m_zoomingModel->value() + 3;
}
val = max(val, -6); // -6 gives 1/64th bar snapping. Lower values cause crashing.
val = std::max(val, -6); // -6 gives 1/64th bar snapping. Lower values cause crashing.
if ( val >= 0 ){
return 1 << val;
@@ -307,7 +308,7 @@ QString SongEditor::getSnapSizeString() const
{
int val = -m_snappingModel->value() + 3;
val = val - m_zoomingModel->value() + 3;
val = max(val, -6); // -6 gives 1/64th bar snapping. Lower values cause crashing.
val = std::max(val, -6); // -6 gives 1/64th bar snapping. Lower values cause crashing.
if ( val >= 0 ){
int bars = 1 << val;

View File

@@ -27,7 +27,7 @@
#include "CaptionMenu.h"
#include "FxMixerView.h"
#include "GuiApplication.h"
#include "Track.h"
#include "TrackView.h"
void FxLineLcdSpinBox::setTrackView(TrackView * tv)
{

View File

@@ -0,0 +1,710 @@
/*
* TrackContentWidget.cpp - implementation of TrackContentWidget class
*
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* 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 (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include "TrackContentWidget.h"
#include <QApplication>
#include <QContextMenuEvent>
#include <QMenu>
#include <QPainter>
#include "AutomationPattern.h"
#include "BBEditor.h"
#include "BBTrackContainer.h"
#include "Clipboard.h"
#include "DataFile.h"
#include "Engine.h"
#include "GuiApplication.h"
#include "Song.h"
#include "SongEditor.h"
#include "StringPairDrag.h"
#include "TrackContainerView.h"
#include "TrackContentObjectView.h"
#include "TrackView.h"
/*! Alternate between a darker and a lighter background color every 4 bars
*/
const int BARS_PER_GROUP = 4;
/*! \brief Create a new trackContentWidget
*
* Creates a new track content widget for the given track.
* The content widget comprises the 'grip bar' and the 'tools' button
* for the track's context menu.
*
* \param parent The parent track.
*/
TrackContentWidget::TrackContentWidget( TrackView * parent ) :
QWidget( parent ),
m_trackView( parent ),
m_darkerColor( Qt::SolidPattern ),
m_lighterColor( Qt::SolidPattern ),
m_gridColor( Qt::SolidPattern ),
m_embossColor( Qt::SolidPattern )
{
setAcceptDrops( true );
connect( parent->trackContainerView(),
SIGNAL( positionChanged( const TimePos & ) ),
this, SLOT( changePosition( const TimePos & ) ) );
setStyle( QApplication::style() );
updateBackground();
}
/*! \brief Destroy this trackContentWidget
*
* Destroys the trackContentWidget.
*/
TrackContentWidget::~TrackContentWidget()
{
}
void TrackContentWidget::updateBackground()
{
const TrackContainerView * tcv = m_trackView->trackContainerView();
// Assume even-pixels-per-bar. Makes sense, should be like this anyways
int ppb = static_cast<int>( tcv->pixelsPerBar() );
int w = ppb * BARS_PER_GROUP;
int h = height();
m_background = QPixmap( w * 2, height() );
QPainter pmp( &m_background );
pmp.fillRect( 0, 0, w, h, darkerColor() );
pmp.fillRect( w, 0, w , h, lighterColor() );
// draw lines
// vertical lines
pmp.setPen( QPen( gridColor(), 1 ) );
for( float x = 0; x < w * 2; x += ppb )
{
pmp.drawLine( QLineF( x, 0.0, x, h ) );
}
pmp.setPen( QPen( embossColor(), 1 ) );
for( float x = 1.0; x < w * 2; x += ppb )
{
pmp.drawLine( QLineF( x, 0.0, x, h ) );
}
// horizontal line
pmp.setPen( QPen( gridColor(), 1 ) );
pmp.drawLine( 0, h-1, w*2, h-1 );
pmp.end();
// Force redraw
update();
}
/*! \brief Adds a trackContentObjectView to this widget.
*
* Adds a(nother) trackContentObjectView to our list of views. We also
* check that our position is up-to-date.
*
* \param tcov The trackContentObjectView to add.
*/
void TrackContentWidget::addTCOView( TrackContentObjectView * tcov )
{
TrackContentObject * tco = tcov->getTrackContentObject();
m_tcoViews.push_back( tcov );
tco->saveJournallingState( false );
changePosition();
tco->restoreJournallingState();
}
/*! \brief Removes the given trackContentObjectView to this widget.
*
* Removes the given trackContentObjectView from our list of views.
*
* \param tcov The trackContentObjectView to add.
*/
void TrackContentWidget::removeTCOView( TrackContentObjectView * tcov )
{
tcoViewVector::iterator it = std::find( m_tcoViews.begin(),
m_tcoViews.end(),
tcov );
if( it != m_tcoViews.end() )
{
m_tcoViews.erase( it );
Engine::getSong()->setModified();
}
}
/*! \brief Update ourselves by updating all the tCOViews attached.
*
*/
void TrackContentWidget::update()
{
for( tcoViewVector::iterator it = m_tcoViews.begin();
it != m_tcoViews.end(); ++it )
{
( *it )->setFixedHeight( height() - 1 );
( *it )->update();
}
QWidget::update();
}
// resposible for moving track-content-widgets to appropriate position after
// change of visible viewport
/*! \brief Move the trackContentWidget to a new place in time
*
* \param newPos The MIDI time to move to.
*/
void TrackContentWidget::changePosition( const TimePos & newPos )
{
if( m_trackView->trackContainerView() == gui->getBBEditor()->trackContainerView() )
{
const int curBB = Engine::getBBTrackContainer()->currentBB();
setUpdatesEnabled( false );
// first show TCO for current BB...
for( tcoViewVector::iterator it = m_tcoViews.begin();
it != m_tcoViews.end(); ++it )
{
if( ( *it )->getTrackContentObject()->
startPosition().getBar() == curBB )
{
( *it )->move( 0, ( *it )->y() );
( *it )->raise();
( *it )->show();
}
else
{
( *it )->lower();
}
}
// ...then hide others to avoid flickering
for( tcoViewVector::iterator it = m_tcoViews.begin();
it != m_tcoViews.end(); ++it )
{
if( ( *it )->getTrackContentObject()->
startPosition().getBar() != curBB )
{
( *it )->hide();
}
}
setUpdatesEnabled( true );
return;
}
TimePos pos = newPos;
if( pos < 0 )
{
pos = m_trackView->trackContainerView()->currentPosition();
}
const int begin = pos;
const int end = endPosition( pos );
const float ppb = m_trackView->trackContainerView()->pixelsPerBar();
setUpdatesEnabled( false );
for( tcoViewVector::iterator it = m_tcoViews.begin();
it != m_tcoViews.end(); ++it )
{
TrackContentObjectView * tcov = *it;
TrackContentObject * tco = tcov->getTrackContentObject();
tco->changeLength( tco->length() );
const int ts = tco->startPosition();
const int te = tco->endPosition()-3;
if( ( ts >= begin && ts <= end ) ||
( te >= begin && te <= end ) ||
( ts <= begin && te >= end ) )
{
tcov->move( static_cast<int>( ( ts - begin ) * ppb /
TimePos::ticksPerBar() ),
tcov->y() );
if( !tcov->isVisible() )
{
tcov->show();
}
}
else
{
tcov->move( -tcov->width()-10, tcov->y() );
}
}
setUpdatesEnabled( true );
// redraw background
// update();
}
/*! \brief Return the position of the trackContentWidget in bars.
*
* \param mouseX the mouse's current X position in pixels.
*/
TimePos TrackContentWidget::getPosition( int mouseX )
{
TrackContainerView * tv = m_trackView->trackContainerView();
return TimePos( tv->currentPosition() +
mouseX *
TimePos::ticksPerBar() /
static_cast<int>( tv->pixelsPerBar() ) );
}
/*! \brief Respond to a drag enter event on the trackContentWidget
*
* \param dee the Drag Enter Event to respond to
*/
void TrackContentWidget::dragEnterEvent( QDragEnterEvent * dee )
{
TimePos tcoPos = getPosition( dee->pos().x() );
if( canPasteSelection( tcoPos, dee ) == false )
{
dee->ignore();
}
else
{
StringPairDrag::processDragEnterEvent( dee, "tco_" +
QString::number( getTrack()->type() ) );
}
}
/*! \brief Returns whether a selection of TCOs can be pasted into this
*
* \param tcoPos the position of the TCO slot being pasted on
* \param de the DropEvent generated
*/
bool TrackContentWidget::canPasteSelection( TimePos tcoPos, const QDropEvent* de )
{
const QMimeData * mimeData = de->mimeData();
// If the source of the DropEvent is the current instance of LMMS we don't allow pasting in the same bar
// if it's another instance of LMMS we allow it
return de->source()
? canPasteSelection( tcoPos, mimeData )
: canPasteSelection( tcoPos, mimeData, true );
}
// Overloaded method to make it possible to call this method without a Drag&Drop event
bool TrackContentWidget::canPasteSelection( TimePos tcoPos, const QMimeData* md , bool allowSameBar )
{
// For decodeKey() and decodeValue()
using namespace Clipboard;
Track * t = getTrack();
QString type = decodeKey( md );
QString value = decodeValue( md );
// We can only paste into tracks of the same type
if( type != ( "tco_" + QString::number( t->type() ) ) ||
m_trackView->trackContainerView()->fixedTCOs() == true )
{
return false;
}
// value contains XML needed to reconstruct TCOs and place them
DataFile dataFile( value.toUtf8() );
// Extract the metadata and which TCO was grabbed
QDomElement metadata = dataFile.content().firstChildElement( "copyMetadata" );
QDomAttr tcoPosAttr = metadata.attributeNode( "grabbedTCOPos" );
TimePos grabbedTCOPos = tcoPosAttr.value().toInt();
TimePos grabbedTCOBar = TimePos( grabbedTCOPos.getBar(), 0 );
// Extract the track index that was originally clicked
QDomAttr tiAttr = metadata.attributeNode( "initialTrackIndex" );
const int initialTrackIndex = tiAttr.value().toInt();
// Get the current track's index
const TrackContainer::TrackList tracks = t->trackContainer()->tracks();
const int currentTrackIndex = tracks.indexOf( t );
// Don't paste if we're on the same bar and allowSameBar is false
auto sourceTrackContainerId = metadata.attributeNode( "trackContainerId" ).value().toUInt();
if( !allowSameBar && sourceTrackContainerId == t->trackContainer()->id() &&
tcoPos == grabbedTCOBar && currentTrackIndex == initialTrackIndex )
{
return false;
}
// Extract the tco data
QDomElement tcoParent = dataFile.content().firstChildElement( "tcos" );
QDomNodeList tcoNodes = tcoParent.childNodes();
// Determine if all the TCOs will land on a valid track
for( int i = 0; i < tcoNodes.length(); i++ )
{
QDomElement tcoElement = tcoNodes.item( i ).toElement();
int trackIndex = tcoElement.attributeNode( "trackIndex" ).value().toInt();
int finalTrackIndex = trackIndex + currentTrackIndex - initialTrackIndex;
// Track must be in TrackContainer's tracks
if( finalTrackIndex < 0 || finalTrackIndex >= tracks.size() )
{
return false;
}
// Track must be of the same type
auto startTrackType = tcoElement.attributeNode("trackType").value().toInt();
Track * endTrack = tracks.at( finalTrackIndex );
if( startTrackType != endTrack->type() )
{
return false;
}
}
return true;
}
/*! \brief Pastes a selection of TCOs onto the track
*
* \param tcoPos the position of the TCO slot being pasted on
* \param de the DropEvent generated
*/
bool TrackContentWidget::pasteSelection( TimePos tcoPos, QDropEvent * de )
{
const QMimeData * mimeData = de->mimeData();
if( canPasteSelection( tcoPos, de ) == false )
{
return false;
}
// We set skipSafetyCheck to true because we already called canPasteSelection
return pasteSelection( tcoPos, mimeData, true );
}
// Overloaded method so we can call it without a Drag&Drop event
bool TrackContentWidget::pasteSelection( TimePos tcoPos, const QMimeData * md, bool skipSafetyCheck )
{
// For decodeKey() and decodeValue()
using namespace Clipboard;
// When canPasteSelection was already called before, skipSafetyCheck will skip this
if( !skipSafetyCheck && canPasteSelection( tcoPos, md ) == false )
{
return false;
}
QString type = decodeKey( md );
QString value = decodeValue( md );
getTrack()->addJournalCheckPoint();
// value contains XML needed to reconstruct TCOs and place them
DataFile dataFile( value.toUtf8() );
// Extract the tco data
QDomElement tcoParent = dataFile.content().firstChildElement( "tcos" );
QDomNodeList tcoNodes = tcoParent.childNodes();
// Extract the track index that was originally clicked
QDomElement metadata = dataFile.content().firstChildElement( "copyMetadata" );
QDomAttr tiAttr = metadata.attributeNode( "initialTrackIndex" );
int initialTrackIndex = tiAttr.value().toInt();
QDomAttr tcoPosAttr = metadata.attributeNode( "grabbedTCOPos" );
TimePos grabbedTCOPos = tcoPosAttr.value().toInt();
// Snap the mouse position to the beginning of the dropped bar, in ticks
const TrackContainer::TrackList tracks = getTrack()->trackContainer()->tracks();
const int currentTrackIndex = tracks.indexOf( getTrack() );
bool wasSelection = m_trackView->trackContainerView()->rubberBand()->selectedObjects().count();
// Unselect the old group
const QVector<selectableObject *> so =
m_trackView->trackContainerView()->selectedObjects();
for( QVector<selectableObject *>::const_iterator it = so.begin();
it != so.end(); ++it )
{
( *it )->setSelected( false );
}
// TODO -- Need to draw the hovericon either way, or ghost the TCOs
// onto their final position.
float snapSize = gui->songEditor()->m_editor->getSnapSize();
// All patterns should be offset the same amount as the grabbed pattern
TimePos offset = TimePos(tcoPos - grabbedTCOPos);
// Users expect clips to "fall" backwards, so bias the offset
offset = offset - TimePos::ticksPerBar() * snapSize / 2;
// The offset is quantized (rather than the positions) to preserve fine adjustments
offset = offset.quantize(snapSize);
// Get the leftmost TCO and fix the offset if it reaches below bar 0
TimePos leftmostPos = grabbedTCOPos;
for(int i = 0; i < tcoNodes.length(); ++i)
{
QDomElement outerTCOElement = tcoNodes.item(i).toElement();
QDomElement tcoElement = outerTCOElement.firstChildElement();
TimePos pos = tcoElement.attributeNode("pos").value().toInt();
if(pos < leftmostPos) { leftmostPos = pos; }
}
// Fix offset if it sets the left most TCO to a negative position
offset = std::max(offset.getTicks(), -leftmostPos.getTicks());
for( int i = 0; i<tcoNodes.length(); i++ )
{
QDomElement outerTCOElement = tcoNodes.item( i ).toElement();
QDomElement tcoElement = outerTCOElement.firstChildElement();
int trackIndex = outerTCOElement.attributeNode( "trackIndex" ).value().toInt();
int finalTrackIndex = trackIndex + ( currentTrackIndex - initialTrackIndex );
Track * t = tracks.at( finalTrackIndex );
// The new position is the old position plus the offset.
TimePos pos = tcoElement.attributeNode( "pos" ).value().toInt() + offset;
// If we land on ourselves, offset by one snap
TimePos shift = TimePos::ticksPerBar() * gui->songEditor()->m_editor->getSnapSize();
if (offset == 0) { pos += shift; }
TrackContentObject * tco = t->createTCO( pos );
tco->restoreState( tcoElement );
tco->movePosition(pos); // Because we restored the state, we need to move the TCO again.
if( wasSelection )
{
tco->selectViewOnCreate( true );
}
}
AutomationPattern::resolveAllIDs();
return true;
}
/*! \brief Respond to a drop event on the trackContentWidget
*
* \param de the Drop Event to respond to
*/
void TrackContentWidget::dropEvent( QDropEvent * de )
{
TimePos tcoPos = TimePos( getPosition( de->pos().x() ) );
if( pasteSelection( tcoPos, de ) == true )
{
de->accept();
}
}
/*! \brief Respond to a mouse press on the trackContentWidget
*
* \param me the mouse press event to respond to
*/
void TrackContentWidget::mousePressEvent( QMouseEvent * me )
{
if( m_trackView->trackContainerView()->allowRubberband() == true )
{
QWidget::mousePressEvent( me );
}
else if( me->modifiers() & Qt::ShiftModifier )
{
QWidget::mousePressEvent( me );
}
else if( me->button() == Qt::LeftButton &&
!m_trackView->trackContainerView()->fixedTCOs() )
{
QVector<selectableObject*> so = m_trackView->trackContainerView()->rubberBand()->selectedObjects();
for( int i = 0; i < so.count(); ++i )
{
so.at( i )->setSelected( false);
}
getTrack()->addJournalCheckPoint();
const TimePos pos = getPosition( me->x() ).getBar() *
TimePos::ticksPerBar();
getTrack()->createTCO(pos);
}
}
/*! \brief Repaint the trackContentWidget on command
*
* \param pe the Paint Event to respond to
*/
void TrackContentWidget::paintEvent( QPaintEvent * pe )
{
// Assume even-pixels-per-bar. Makes sense, should be like this anyways
const TrackContainerView * tcv = m_trackView->trackContainerView();
int ppb = static_cast<int>( tcv->pixelsPerBar() );
QPainter p( this );
// Don't draw background on BB-Editor
if( m_trackView->trackContainerView() != gui->getBBEditor()->trackContainerView() )
{
p.drawTiledPixmap( rect(), m_background, QPoint(
tcv->currentPosition().getBar() * ppb, 0 ) );
}
}
/*! \brief Updates the background tile pixmap on size changes.
*
* \param resizeEvent the resize event to pass to base class
*/
void TrackContentWidget::resizeEvent( QResizeEvent * resizeEvent )
{
// Update backgroud
updateBackground();
// Force redraw
QWidget::resizeEvent( resizeEvent );
}
/*! \brief Return the track shown by the trackContentWidget
*
*/
Track * TrackContentWidget::getTrack()
{
return m_trackView->getTrack();
}
/*! \brief Return the end position of the trackContentWidget in Bars.
*
* \param posStart the starting position of the Widget (from getPosition())
*/
TimePos TrackContentWidget::endPosition( const TimePos & posStart )
{
const float ppb = m_trackView->trackContainerView()->pixelsPerBar();
const int w = width();
return posStart + static_cast<int>( w * TimePos::ticksPerBar() / ppb );
}
void TrackContentWidget::contextMenuEvent( QContextMenuEvent * cme )
{
// For hasFormat(), MimeType enum class and getMimeData()
using namespace Clipboard;
if( cme->modifiers() )
{
return;
}
// If we don't have TCO data in the clipboard there's no need to create this menu
// since "paste" is the only action at the moment.
if( ! hasFormat( MimeType::StringPair ) )
{
return;
}
QMenu contextMenu( this );
QAction *pasteA = contextMenu.addAction( embed::getIconPixmap( "edit_paste" ),
tr( "Paste" ), [this, cme](){ contextMenuAction( cme, Paste ); } );
// If we can't paste in the current TCW for some reason, disable the action so the user knows
pasteA->setEnabled( canPasteSelection( getPosition( cme->x() ), getMimeData() ) ? true : false );
contextMenu.exec( QCursor::pos() );
}
void TrackContentWidget::contextMenuAction( QContextMenuEvent * cme, ContextMenuAction action )
{
// For getMimeData()
using namespace Clipboard;
switch( action )
{
case Paste:
// Paste the selection on the TimePos of the context menu event
TimePos tcoPos = getPosition( cme->x() );
pasteSelection( tcoPos, getMimeData() );
break;
}
}
// qproperty access methods
//! \brief CSS theming qproperty access method
QBrush TrackContentWidget::darkerColor() const
{ return m_darkerColor; }
//! \brief CSS theming qproperty access method
QBrush TrackContentWidget::lighterColor() const
{ return m_lighterColor; }
//! \brief CSS theming qproperty access method
QBrush TrackContentWidget::gridColor() const
{ return m_gridColor; }
//! \brief CSS theming qproperty access method
QBrush TrackContentWidget::embossColor() const
{ return m_embossColor; }
//! \brief CSS theming qproperty access method
void TrackContentWidget::setDarkerColor( const QBrush & c )
{ m_darkerColor = c; }
//! \brief CSS theming qproperty access method
void TrackContentWidget::setLighterColor( const QBrush & c )
{ m_lighterColor = c; }
//! \brief CSS theming qproperty access method
void TrackContentWidget::setGridColor( const QBrush & c )
{ m_gridColor = c; }
//! \brief CSS theming qproperty access method
void TrackContentWidget::setEmbossColor( const QBrush & c )
{ m_embossColor = c; }

View File

@@ -0,0 +1,353 @@
/*
* TrackOperationsWidget.cpp - implementation of TrackOperationsWidget class
*
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* 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 (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include "TrackOperationsWidget.h"
#include <QMenu>
#include <QMouseEvent>
#include <QPainter>
#include <QPushButton>
#include "AutomationPattern.h"
#include "AutomationTrack.h"
#include "ColorChooser.h"
#include "ConfigManager.h"
#include "DataFile.h"
#include "embed.h"
#include "Engine.h"
#include "gui_templates.h"
#include "InstrumentTrack.h"
#include "PixmapButton.h"
#include "Song.h"
#include "StringPairDrag.h"
#include "ToolTip.h"
#include "Track.h"
#include "TrackContainerView.h"
#include "TrackView.h"
/*! \brief Create a new trackOperationsWidget
*
* The trackOperationsWidget is the grip and the mute button of a track.
*
* \param parent the trackView to contain this widget
*/
TrackOperationsWidget::TrackOperationsWidget( TrackView * parent ) :
QWidget( parent ), /*!< The parent widget */
m_trackView( parent ) /*!< The parent track view */
{
ToolTip::add( this, tr( "Press <%1> while clicking on move-grip "
"to begin a new drag'n'drop action." ).arg(UI_CTRL_KEY) );
QMenu * toMenu = new QMenu( this );
toMenu->setFont( pointSize<9>( toMenu->font() ) );
connect( toMenu, SIGNAL( aboutToShow() ), this, SLOT( updateMenu() ) );
setObjectName( "automationEnabled" );
m_trackOps = new QPushButton( this );
m_trackOps->move( 12, 1 );
m_trackOps->setFocusPolicy( Qt::NoFocus );
m_trackOps->setMenu( toMenu );
ToolTip::add( m_trackOps, tr( "Actions" ) );
m_muteBtn = new PixmapButton( this, tr( "Mute" ) );
m_muteBtn->setActiveGraphic( embed::getIconPixmap( "led_off" ) );
m_muteBtn->setInactiveGraphic( embed::getIconPixmap( "led_green" ) );
m_muteBtn->setCheckable( true );
m_soloBtn = new PixmapButton( this, tr( "Solo" ) );
m_soloBtn->setActiveGraphic( embed::getIconPixmap( "led_red" ) );
m_soloBtn->setInactiveGraphic( embed::getIconPixmap( "led_off" ) );
m_soloBtn->setCheckable( true );
if( ConfigManager::inst()->value( "ui",
"compacttrackbuttons" ).toInt() )
{
m_muteBtn->move( 46, 0 );
m_soloBtn->move( 46, 16 );
}
else
{
m_muteBtn->move( 46, 8 );
m_soloBtn->move( 62, 8 );
}
m_muteBtn->show();
ToolTip::add( m_muteBtn, tr( "Mute" ) );
m_soloBtn->show();
ToolTip::add( m_soloBtn, tr( "Solo" ) );
connect( this, SIGNAL( trackRemovalScheduled( TrackView * ) ),
m_trackView->trackContainerView(),
SLOT( deleteTrackView( TrackView * ) ),
Qt::QueuedConnection );
connect( m_trackView->getTrack()->getMutedModel(), SIGNAL( dataChanged() ),
this, SLOT( update() ) );
}
/*! \brief Destroy an existing trackOperationsWidget
*
*/
TrackOperationsWidget::~TrackOperationsWidget()
{
}
/*! \brief Respond to trackOperationsWidget mouse events
*
* If it's the left mouse button, and Ctrl is held down, and we're
* not a Beat+Bassline Editor track, then start a new drag event to
* copy this track.
*
* Otherwise, ignore all other events.
*
* \param me The mouse event to respond to.
*/
void TrackOperationsWidget::mousePressEvent( QMouseEvent * me )
{
if( me->button() == Qt::LeftButton &&
me->modifiers() & Qt::ControlModifier &&
m_trackView->getTrack()->type() != Track::BBTrack )
{
DataFile dataFile( DataFile::DragNDropData );
m_trackView->getTrack()->saveState( dataFile, dataFile.content() );
new StringPairDrag( QString( "track_%1" ).arg(
m_trackView->getTrack()->type() ),
dataFile.toString(), m_trackView->getTrackSettingsWidget()->grab(),
this );
}
else if( me->button() == Qt::LeftButton )
{
// track-widget (parent-widget) initiates track-move
me->ignore();
}
}
/*! \brief Repaint the trackOperationsWidget
*
* If we're not moving, and in the Beat+Bassline Editor, then turn
* automation on or off depending on its previous state and show
* ourselves.
*
* Otherwise, hide ourselves.
*
* \todo Flesh this out a bit - is it correct?
* \param pe The paint event to respond to
*/
void TrackOperationsWidget::paintEvent( QPaintEvent * pe )
{
QPainter p( this );
p.fillRect( rect(), palette().brush(QPalette::Background) );
if( m_trackView->getTrack()->useColor() && ! m_trackView->getTrack()->getMutedModel()->value() )
{
QRect coloredRect( 0, 0, 10, m_trackView->getTrack()->getHeight() );
p.fillRect( coloredRect, m_trackView->getTrack()->color() );
}
if( m_trackView->isMovingTrack() == false )
{
p.drawPixmap( 2, 2, embed::getIconPixmap("track_op_grip"));
}
else
{
p.drawPixmap( 2, 2, embed::getIconPixmap("track_op_grip_c"));
}
}
/*! \brief Clone this track
*
*/
void TrackOperationsWidget::cloneTrack()
{
TrackContainerView *tcView = m_trackView->trackContainerView();
Track *newTrack = m_trackView->getTrack()->clone();
TrackView *newTrackView = tcView->createTrackView( newTrack );
int index = tcView->trackViews().indexOf( m_trackView );
int i = tcView->trackViews().size();
while ( i != index + 1 )
{
tcView->moveTrackView( newTrackView, i - 1 );
i--;
}
}
/*! \brief Clear this track - clears all TCOs from the track */
void TrackOperationsWidget::clearTrack()
{
Track * t = m_trackView->getTrack();
t->addJournalCheckPoint();
t->lock();
t->deleteTCOs();
t->unlock();
}
/*! \brief Remove this track from the track list
*
*/
void TrackOperationsWidget::removeTrack()
{
emit trackRemovalScheduled( m_trackView );
}
void TrackOperationsWidget::changeTrackColor()
{
QColor new_color = ColorChooser( this ).withPalette( ColorChooser::Palette::Track )-> \
getColor( m_trackView->getTrack()->color() );
if( ! new_color.isValid() )
{ return; }
emit colorChanged( new_color );
Engine::getSong()->setModified();
update();
}
void TrackOperationsWidget::resetTrackColor()
{
emit colorReset();
Engine::getSong()->setModified();
update();
}
void TrackOperationsWidget::randomTrackColor()
{
QColor buffer = ColorChooser::getPalette( ColorChooser::Palette::Track )[ rand() % 48 ];
emit colorChanged( buffer );
Engine::getSong()->setModified();
update();
}
void TrackOperationsWidget::useTrackColor()
{
emit colorParented();
Engine::getSong()->setModified();
}
/*! \brief Update the trackOperationsWidget context menu
*
* For all track types, we have the Clone and Remove options.
* For instrument-tracks we also offer the MIDI-control-menu
* For automation tracks, extra options: turn on/off recording
* on all TCOs (same should be added for sample tracks when
* sampletrack recording is implemented)
*/
void TrackOperationsWidget::updateMenu()
{
QMenu * toMenu = m_trackOps->menu();
toMenu->clear();
toMenu->addAction( embed::getIconPixmap( "edit_copy", 16, 16 ),
tr( "Clone this track" ),
this, SLOT( cloneTrack() ) );
toMenu->addAction( embed::getIconPixmap( "cancel", 16, 16 ),
tr( "Remove this track" ),
this, SLOT( removeTrack() ) );
if( ! m_trackView->trackContainerView()->fixedTCOs() )
{
toMenu->addAction( tr( "Clear this track" ), this, SLOT( clearTrack() ) );
}
if (QMenu *fxMenu = m_trackView->createFxMenu(tr("FX %1: %2"), tr("Assign to new FX Channel")))
{
toMenu->addMenu(fxMenu);
}
if (InstrumentTrackView * trackView = dynamic_cast<InstrumentTrackView *>(m_trackView))
{
toMenu->addSeparator();
toMenu->addMenu(trackView->midiMenu());
}
if( dynamic_cast<AutomationTrackView *>( m_trackView ) )
{
toMenu->addAction( tr( "Turn all recording on" ), this, SLOT( recordingOn() ) );
toMenu->addAction( tr( "Turn all recording off" ), this, SLOT( recordingOff() ) );
}
toMenu->addSeparator();
toMenu->addAction( embed::getIconPixmap( "colorize" ),
tr( "Change color" ), this, SLOT( changeTrackColor() ) );
toMenu->addAction( embed::getIconPixmap( "colorize" ),
tr( "Reset color to default" ), this, SLOT( resetTrackColor() ) );
toMenu->addAction( embed::getIconPixmap( "colorize" ),
tr( "Set random color" ), this, SLOT( randomTrackColor() ) );
toMenu->addSeparator();
toMenu->addAction( embed::getIconPixmap( "colorize" ),
tr( "Clear clip colors" ), this, SLOT( useTrackColor() ) );
}
void TrackOperationsWidget::toggleRecording( bool on )
{
AutomationTrackView * atv = dynamic_cast<AutomationTrackView *>( m_trackView );
if( atv )
{
for( TrackContentObject * tco : atv->getTrack()->getTCOs() )
{
AutomationPattern * ap = dynamic_cast<AutomationPattern *>( tco );
if( ap ) { ap->setRecording( on ); }
}
atv->update();
}
}
void TrackOperationsWidget::recordingOn()
{
toggleRecording( true );
}
void TrackOperationsWidget::recordingOff()
{
toggleRecording( false );
}

View File

@@ -23,6 +23,7 @@
*/
#include "BBTrack.h"
#include <QDomElement>
#include <QMenu>
#include <QPainter>

View File

@@ -42,6 +42,7 @@
#include "CaptionMenu.h"
#include "ConfigManager.h"
#include "ControllerConnection.h"
#include "DataFile.h"
#include "EffectChain.h"
#include "EffectRackView.h"
#include "embed.h"

View File

@@ -24,6 +24,7 @@
*/
#include "SampleTrack.h"
#include <QDomElement>
#include <QDropEvent>
#include <QFileInfo>
#include <QMenu>