Knife Tool for Sample Clips (Again) (#5524)
* Rebase BaraMGB's Knife Co-authored-by: Steffen Baranowsky <BaraMGB@freenet.de> * Draw marker * Refactoring and shift mode * Allow resizing * Add Icon * Fix stuck marker on RMB, remove unnecessary cast * Remove redundant line, more const * Fix * Review fixes * Only perform split logic for SampleTCO * Add unquantizedModHeld function * missed one * Don't use copy/paste * Don't use copy/paste * More git troubles * Fix undo * git dammit * Cleaner solution? * Set cursor, add copy assignment to SampleBuffer * Add TODO comment * Make it build * Fixes from review * Make splitTCO virtual * Make splitTCO more generic Co-authored-by: IanCaio <iancaio_dev@hotmail.com> * Prevent resizing of MIDI clips in knife mode * Fix move/resize and rework box select via ctrl * Apply suggestions from code review. Co-authored-by: IanCaio <iancaio_dev@hotmail.com> * Don't show inaccurate/useless/empty text float in knife mode * Addresses Github review - Fixes a typo where QWidget::mousePressEvent was being called inside mouseReleaseEvent. - Avoids unnecessarily disabling journalling on the Split action, since it doesn't require it. * Revert format changes in Track * Revert format changes in Track.h * Revert formatting changes in Track.cpp Co-authored-by: Hyunjin Song <tteu.ingog@gmail.com> Co-authored-by: IanCaio <iancaio_dev@hotmail.com>
This commit is contained in:
BIN
data/themes/classic/cursor_knife.png
Normal file
BIN
data/themes/classic/cursor_knife.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 414 B |
@@ -598,10 +598,10 @@ FxLine {
|
||||
color: #e0e0e0;
|
||||
qproperty-backgroundActive: qlineargradient(spread:reflect, x1:0, y1:0, x2:1, y2:0,
|
||||
stop:0 #7b838d, stop:1 #6b7581 );
|
||||
qproperty-strokeOuterActive: rgb( 0, 0, 0 );
|
||||
qproperty-strokeOuterInactive: rgba( 0, 0, 0, 50 );
|
||||
qproperty-strokeInnerActive: rgba( 255, 255, 255, 100 );
|
||||
qproperty-strokeInnerInactive: rgba( 255, 255, 255, 50 );
|
||||
qproperty-strokeOuterActive: rgb( 0, 0, 0 );
|
||||
qproperty-strokeOuterInactive: rgba( 0, 0, 0, 50 );
|
||||
qproperty-strokeInnerActive: rgba( 255, 255, 255, 100 );
|
||||
qproperty-strokeInnerInactive: rgba( 255, 255, 255, 50 );
|
||||
}
|
||||
|
||||
/* persistent peak markers for fx peak meters */
|
||||
@@ -658,7 +658,8 @@ TrackContentObjectView {
|
||||
qproperty-gradient: true; /* boolean property, set true to have a gradient */
|
||||
/* finger tip offset of cursor */
|
||||
qproperty-mouseHotspotHand: 3px 3px;
|
||||
|
||||
qproperty-mouseHotspotKnife: 0px 0px;
|
||||
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
|
||||
BIN
data/themes/default/cursor_knife.png
Normal file
BIN
data/themes/default/cursor_knife.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 414 B |
@@ -704,7 +704,8 @@ TrackContentObjectView {
|
||||
qproperty-gradient: false; /* boolean property, set true to have a gradient */
|
||||
/* finger tip offset of cursor */
|
||||
qproperty-mouseHotspotHand: 7px 2px;
|
||||
|
||||
qproperty-mouseHotspotKnife: 0px 0px;
|
||||
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
|
||||
@@ -93,7 +93,6 @@ private:
|
||||
BoolModel m_recordModel;
|
||||
bool m_isPlaying;
|
||||
|
||||
|
||||
friend class SampleTCOView;
|
||||
|
||||
|
||||
@@ -132,6 +131,7 @@ protected:
|
||||
private:
|
||||
SampleTCO * m_tco;
|
||||
QPixmap m_paintPixmap;
|
||||
bool splitTCO( const TimePos pos ) override;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ public:
|
||||
enum EditMode
|
||||
{
|
||||
DrawMode,
|
||||
KnifeMode,
|
||||
SelectMode
|
||||
};
|
||||
|
||||
@@ -77,6 +78,7 @@ public slots:
|
||||
|
||||
void setEditMode( EditMode mode );
|
||||
void setEditModeDraw();
|
||||
void setEditModeKnife();
|
||||
void setEditModeSelect();
|
||||
void toggleProportionalSnap();
|
||||
|
||||
@@ -112,6 +114,7 @@ private:
|
||||
void wheelEvent( QWheelEvent * we ) override;
|
||||
|
||||
bool allowRubberband() const override;
|
||||
bool knifeMode() const override;
|
||||
|
||||
int trackIndexFromSelectionPoint(int yPos);
|
||||
int indexOfTrackView(const TrackView* tv);
|
||||
@@ -173,6 +176,7 @@ public:
|
||||
QSize sizeHint() const override;
|
||||
|
||||
SongEditor* m_editor;
|
||||
void syncEditMode();
|
||||
|
||||
protected:
|
||||
void resizeEvent( QResizeEvent * event ) override;
|
||||
@@ -194,9 +198,6 @@ signals:
|
||||
void resized();
|
||||
|
||||
private:
|
||||
void keyPressEvent( QKeyEvent * ke ) override;
|
||||
void keyReleaseEvent( QKeyEvent * ke ) override;
|
||||
|
||||
QAction* m_addBBTrackAction;
|
||||
QAction* m_addSampleTrackAction;
|
||||
QAction* m_addAutomationTrackAction;
|
||||
@@ -204,6 +205,7 @@ private:
|
||||
|
||||
ActionGroup * m_editModeGroup;
|
||||
QAction* m_drawModeAction;
|
||||
QAction* m_knifeModeAction;
|
||||
QAction* m_selectModeAction;
|
||||
QAction* m_crtlAction;
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ public:
|
||||
const TrackView * trackViewAt( const int _y ) const;
|
||||
|
||||
virtual bool allowRubberband() const;
|
||||
virtual bool knifeMode() const;
|
||||
|
||||
inline bool rubberBandActive() const
|
||||
{
|
||||
|
||||
@@ -58,6 +58,7 @@ class TrackContentObjectView : public selectableObject, public ModelView
|
||||
// We have to use a QSize here because using QPoint isn't supported.
|
||||
// width -> x, height -> y
|
||||
Q_PROPERTY( QSize mouseHotspotHand WRITE setMouseHotspotHand )
|
||||
Q_PROPERTY( QSize mouseHotspotKnife WRITE setMouseHotspotKnife )
|
||||
|
||||
public:
|
||||
TrackContentObjectView( TrackContentObject * tco, TrackView * tv );
|
||||
@@ -93,6 +94,7 @@ public:
|
||||
void setBBPatternBackground( const QColor & c );
|
||||
void setGradient( const bool & b );
|
||||
void setMouseHotspotHand(const QSize & s);
|
||||
void setMouseHotspotKnife(const QSize & s);
|
||||
|
||||
// access needsUpdate member variable
|
||||
bool needsUpdate();
|
||||
@@ -118,6 +120,9 @@ public:
|
||||
|
||||
QColor getColorForDisplay( QColor );
|
||||
|
||||
void inline setMarkerPos(int x) { m_markerPos = x; }
|
||||
void inline setMarkerEnabled(bool e) { m_marker = e; }
|
||||
|
||||
public slots:
|
||||
virtual bool close();
|
||||
void remove();
|
||||
@@ -137,6 +142,13 @@ protected:
|
||||
Merge
|
||||
};
|
||||
|
||||
TrackView * m_trackView;
|
||||
TimePos m_initialTCOPos;
|
||||
TimePos m_initialTCOEnd;
|
||||
|
||||
bool m_marker = false;
|
||||
int m_markerPos = 0;
|
||||
|
||||
virtual void constructContextMenu( QMenu * )
|
||||
{
|
||||
}
|
||||
@@ -145,7 +157,6 @@ protected:
|
||||
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;
|
||||
@@ -155,6 +166,9 @@ protected:
|
||||
selectableObject::resizeEvent( re );
|
||||
}
|
||||
|
||||
bool unquantizedModHeld( QMouseEvent * me );
|
||||
TimePos quantizeSplitPos( TimePos, bool shiftMode );
|
||||
|
||||
float pixelsPerBar();
|
||||
|
||||
|
||||
@@ -176,6 +190,7 @@ private:
|
||||
MoveSelection,
|
||||
Resize,
|
||||
ResizeLeft,
|
||||
Split,
|
||||
CopySelection,
|
||||
ToggleSelected
|
||||
} ;
|
||||
@@ -183,12 +198,9 @@ private:
|
||||
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;
|
||||
@@ -202,7 +214,10 @@ private:
|
||||
QColor m_textShadowColor;
|
||||
QColor m_BBPatternBackground;
|
||||
bool m_gradient;
|
||||
QSize m_mouseHotspotHand; // QSize must be used because QPoint isn't supported by property system
|
||||
QSize m_mouseHotspotHand; // QSize must be used because QPoint
|
||||
QSize m_mouseHotspotKnife; // isn't supported by property system
|
||||
QCursor m_cursorHand;
|
||||
QCursor m_cursorKnife;
|
||||
bool m_cursorSetYet;
|
||||
|
||||
bool m_needsUpdate;
|
||||
@@ -217,6 +232,10 @@ private:
|
||||
|
||||
bool mouseMovedDistance( QMouseEvent * me, int distance );
|
||||
TimePos draggedTCOPos( QMouseEvent * me );
|
||||
int knifeMarkerPos( QMouseEvent * me );
|
||||
//! Return true iff TCO could be split. Currently only implemented for samples
|
||||
virtual bool splitTCO( const TimePos pos ){ return false; };
|
||||
void updateCursor(QMouseEvent * me);
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@ protected:
|
||||
void dragEnterEvent( QDragEnterEvent * dee ) override;
|
||||
void dropEvent( QDropEvent * de ) override;
|
||||
void mousePressEvent( QMouseEvent * me ) override;
|
||||
void mouseReleaseEvent( QMouseEvent * me ) override;
|
||||
void paintEvent( QPaintEvent * pe ) override;
|
||||
void resizeEvent( QResizeEvent * re ) override;
|
||||
|
||||
|
||||
@@ -308,6 +308,14 @@ bool TrackContainerView::allowRubberband() const
|
||||
|
||||
|
||||
|
||||
bool TrackContainerView::knifeMode() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void TrackContainerView::setPixelsPerBar( int ppb )
|
||||
{
|
||||
m_ppb = ppb;
|
||||
@@ -374,7 +382,7 @@ void TrackContainerView::dropEvent( QDropEvent * _de )
|
||||
//it->toggledInstrumentTrackButton( true );
|
||||
_de->accept();
|
||||
}
|
||||
else if( type == "samplefile" || type == "pluginpresetfile"
|
||||
else if( type == "samplefile" || type == "pluginpresetfile"
|
||||
|| type == "soundfontfile" || type == "vstpluginfile"
|
||||
|| type == "patchfile" )
|
||||
{
|
||||
|
||||
@@ -77,13 +77,13 @@ TrackContentObjectView::TrackContentObjectView( TrackContentObject * tco,
|
||||
TrackView * tv ) :
|
||||
selectableObject( tv->getTrackContentWidget() ),
|
||||
ModelView( NULL, this ),
|
||||
m_tco( tco ),
|
||||
m_trackView( tv ),
|
||||
m_initialTCOPos( TimePos(0) ),
|
||||
m_initialTCOEnd( TimePos(0) ),
|
||||
m_tco( tco ),
|
||||
m_action( NoAction ),
|
||||
m_initialMousePos( QPoint( 0, 0 ) ),
|
||||
m_initialMouseGlobalPos( QPoint( 0, 0 ) ),
|
||||
m_initialTCOPos( TimePos(0) ),
|
||||
m_initialTCOEnd( TimePos(0) ),
|
||||
m_initialOffsets( QVector<TimePos>() ),
|
||||
m_hint( NULL ),
|
||||
m_mutedColor( 0, 0, 0 ),
|
||||
@@ -94,6 +94,9 @@ TrackContentObjectView::TrackContentObjectView( TrackContentObject * tco,
|
||||
m_BBPatternBackground( 0, 0, 0 ),
|
||||
m_gradient( true ),
|
||||
m_mouseHotspotHand( 0, 0 ),
|
||||
m_mouseHotspotKnife( 0, 0 ),
|
||||
m_cursorHand( QCursor( embed::getIconPixmap( "hand" ) ) ),
|
||||
m_cursorKnife( QCursor( embed::getIconPixmap( "cursor_knife" ) ) ),
|
||||
m_cursorSetYet( false ),
|
||||
m_needsUpdate( true )
|
||||
{
|
||||
@@ -106,7 +109,7 @@ TrackContentObjectView::TrackContentObjectView( TrackContentObject * tco,
|
||||
setAttribute( Qt::WA_OpaquePaintEvent, true );
|
||||
setAttribute( Qt::WA_DeleteOnClose, true );
|
||||
setFocusPolicy( Qt::StrongFocus );
|
||||
setCursor( QCursor( embed::getIconPixmap( "hand" ), m_mouseHotspotHand.width(), m_mouseHotspotHand.height() ) );
|
||||
setCursor( m_cursorHand );
|
||||
move( 0, 0 );
|
||||
show();
|
||||
|
||||
@@ -159,7 +162,9 @@ void TrackContentObjectView::update()
|
||||
{
|
||||
if( !m_cursorSetYet )
|
||||
{
|
||||
setCursor( QCursor( embed::getIconPixmap( "hand" ), m_mouseHotspotHand.width(), m_mouseHotspotHand.height() ) );
|
||||
m_cursorHand = QCursor( embed::getIconPixmap( "hand" ), m_mouseHotspotHand.width(), m_mouseHotspotHand.height() );
|
||||
m_cursorKnife = QCursor( embed::getIconPixmap( "cursor_knife" ), m_mouseHotspotKnife.width(), m_mouseHotspotKnife.height() );
|
||||
setCursor( m_cursorHand );
|
||||
m_cursorSetYet = true;
|
||||
}
|
||||
|
||||
@@ -248,6 +253,11 @@ void TrackContentObjectView::setMouseHotspotHand(const QSize & s)
|
||||
m_mouseHotspotHand = s;
|
||||
}
|
||||
|
||||
void TrackContentObjectView::setMouseHotspotKnife(const QSize & s)
|
||||
{
|
||||
m_mouseHotspotKnife = s;
|
||||
}
|
||||
|
||||
// access needsUpdate member variable
|
||||
bool TrackContentObjectView::needsUpdate()
|
||||
{ return m_needsUpdate; }
|
||||
@@ -439,22 +449,32 @@ void TrackContentObjectView::dropEvent( QDropEvent * de )
|
||||
|
||||
|
||||
|
||||
/*! \brief Handle a dragged selection leaving our 'airspace'.
|
||||
/* @brief Chooses the correct cursor to be displayed on the widget
|
||||
*
|
||||
* \param e The QEvent to watch.
|
||||
* @param me The QMouseEvent that is triggering the cursor change
|
||||
*/
|
||||
void TrackContentObjectView::leaveEvent( QEvent * e )
|
||||
void TrackContentObjectView::updateCursor(QMouseEvent * me)
|
||||
{
|
||||
if( cursor().shape() != Qt::BitmapCursor )
|
||||
SampleTCO * sTco = dynamic_cast<SampleTCO*>(m_tco);
|
||||
|
||||
// If we are at the edges, use the resize cursor
|
||||
if ((me->x() > width() - RESIZE_GRIP_WIDTH && !me->buttons() && !m_tco->getAutoResize())
|
||||
|| (me->x() < RESIZE_GRIP_WIDTH && !me->buttons() && sTco && !m_tco->getAutoResize()))
|
||||
{
|
||||
setCursor( QCursor( embed::getIconPixmap( "hand" ), m_mouseHotspotHand.width(), m_mouseHotspotHand.height() ) );
|
||||
setCursor(Qt::SizeHorCursor);
|
||||
}
|
||||
if( e != NULL )
|
||||
// If we are in the middle on knife mode, use the knife cursor
|
||||
else if (sTco && m_trackView->trackContainerView()->knifeMode())
|
||||
{
|
||||
QWidget::leaveEvent( e );
|
||||
setCursor(m_cursorKnife);
|
||||
}
|
||||
// If we are in the middle in any other mode, use the hand cursor
|
||||
else { setCursor(m_cursorHand); }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \brief Create a DataFile suitable for copying multiple trackContentObjects.
|
||||
*
|
||||
* trackContentObjects in the vector are written to the "tcos" node in the
|
||||
@@ -568,7 +588,10 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me )
|
||||
setInitialOffsets();
|
||||
if( !fixedTCOs() && me->button() == Qt::LeftButton )
|
||||
{
|
||||
if( me->modifiers() & Qt::ControlModifier )
|
||||
SampleTCO * sTco = dynamic_cast<SampleTCO*>( m_tco );
|
||||
const bool knifeMode = m_trackView->trackContainerView()->knifeMode();
|
||||
|
||||
if ( me->modifiers() & Qt::ControlModifier && !(sTco && knifeMode) )
|
||||
{
|
||||
if( isSelected() )
|
||||
{
|
||||
@@ -579,9 +602,7 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me )
|
||||
m_action = ToggleSelected;
|
||||
}
|
||||
}
|
||||
else if( !me->modifiers()
|
||||
|| (me->modifiers() & Qt::AltModifier)
|
||||
|| (me->modifiers() & Qt::ShiftModifier) )
|
||||
else
|
||||
{
|
||||
if( isSelected() )
|
||||
{
|
||||
@@ -592,28 +613,43 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me )
|
||||
gui->songEditor()->m_editor->selectAllTcos( false );
|
||||
m_tco->addJournalCheckPoint();
|
||||
|
||||
// move or resize
|
||||
m_tco->setJournalling( false );
|
||||
// Move, Resize and ResizeLeft
|
||||
// Split action doesn't disable TCO journalling
|
||||
if (m_action == Move || m_action == Resize || m_action == ResizeLeft)
|
||||
{
|
||||
m_tco->setJournalling(false);
|
||||
}
|
||||
|
||||
setInitialPos( me->pos() );
|
||||
setInitialOffsets();
|
||||
|
||||
SampleTCO * sTco = dynamic_cast<SampleTCO*>( m_tco );
|
||||
if( me->x() < RESIZE_GRIP_WIDTH && sTco
|
||||
&& !m_tco->getAutoResize() )
|
||||
if( m_tco->getAutoResize() )
|
||||
{ // Always move clips that can't be manually resized
|
||||
m_action = Move;
|
||||
setCursor( Qt::SizeAllCursor );
|
||||
}
|
||||
else if( me->x() >= width() - RESIZE_GRIP_WIDTH )
|
||||
{
|
||||
m_action = Resize;
|
||||
setCursor( Qt::SizeHorCursor );
|
||||
}
|
||||
else if( me->x() < RESIZE_GRIP_WIDTH && sTco )
|
||||
{
|
||||
m_action = ResizeLeft;
|
||||
setCursor( Qt::SizeHorCursor );
|
||||
}
|
||||
else if( m_tco->getAutoResize() || me->x() < width() - RESIZE_GRIP_WIDTH )
|
||||
else if( sTco && knifeMode )
|
||||
{
|
||||
m_action = Move;
|
||||
setCursor( Qt::SizeAllCursor );
|
||||
m_action = Split;
|
||||
setCursor( m_cursorKnife );
|
||||
setMarkerPos( knifeMarkerPos( me ) );
|
||||
setMarkerEnabled( true );
|
||||
update();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_action = Resize;
|
||||
setCursor( Qt::SizeHorCursor );
|
||||
m_action = Move;
|
||||
setCursor( Qt::SizeAllCursor );
|
||||
}
|
||||
|
||||
if( m_action == Move )
|
||||
@@ -641,7 +677,7 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me )
|
||||
// s_textFloat->reparent( this );
|
||||
// setup text-float as if TCO was already moved/resized
|
||||
s_textFloat->moveGlobal( this, QPoint( width() + 2, height() + 2) );
|
||||
s_textFloat->show();
|
||||
if ( m_action != Split) { s_textFloat->show(); }
|
||||
}
|
||||
|
||||
delete m_hint;
|
||||
@@ -662,6 +698,16 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me )
|
||||
{
|
||||
remove( active );
|
||||
}
|
||||
if (m_action == Split)
|
||||
{
|
||||
m_action = NoAction;
|
||||
SampleTCO * sTco = dynamic_cast<SampleTCO*>( m_tco );
|
||||
if (sTco)
|
||||
{
|
||||
setMarkerEnabled( false );
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( me->button() == Qt::MidButton )
|
||||
{
|
||||
@@ -790,8 +836,6 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me )
|
||||
}
|
||||
else if( m_action == Resize || m_action == ResizeLeft )
|
||||
{
|
||||
// If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize
|
||||
const bool unquantized = (me->modifiers() & Qt::ControlModifier) || (me->modifiers() & Qt::AltModifier);
|
||||
const float snapSize = gui->songEditor()->m_editor->getSnapSize();
|
||||
// Length in ticks of one snap increment
|
||||
const TimePos snapLength = TimePos( (int)(snapSize * TimePos::ticksPerBar()) );
|
||||
@@ -801,7 +845,8 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me )
|
||||
// The clip's new length
|
||||
TimePos l = static_cast<int>( me->x() * TimePos::ticksPerBar() / ppb );
|
||||
|
||||
if ( unquantized )
|
||||
// If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize
|
||||
if ( unquantizedModHeld(me) )
|
||||
{ // We want to preserve this adjusted offset,
|
||||
// even if the user switches to snapping later
|
||||
setInitialPos( m_initialMousePos );
|
||||
@@ -837,7 +882,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me )
|
||||
m_trackView->trackContainerView()->currentPosition() +
|
||||
static_cast<int>( x * TimePos::ticksPerBar() / ppb ) );
|
||||
|
||||
if( unquantized )
|
||||
if( unquantizedModHeld(me) )
|
||||
{ // We want to preserve this adjusted offset,
|
||||
// even if the user switches to snapping later
|
||||
setInitialPos( m_initialMousePos );
|
||||
@@ -882,19 +927,17 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me )
|
||||
TimePos::ticksPerBar() ) );
|
||||
s_textFloat->moveGlobal( this, QPoint( width() + 2, height() + 2) );
|
||||
}
|
||||
else
|
||||
else if( m_action == Split )
|
||||
{
|
||||
SampleTCO * sTco = dynamic_cast<SampleTCO*>( m_tco );
|
||||
if( ( me->x() > width() - RESIZE_GRIP_WIDTH && !me->buttons() && !m_tco->getAutoResize() )
|
||||
|| ( me->x() < RESIZE_GRIP_WIDTH && !me->buttons() && sTco && !m_tco->getAutoResize() ) )
|
||||
{
|
||||
setCursor( Qt::SizeHorCursor );
|
||||
}
|
||||
else
|
||||
{
|
||||
leaveEvent( NULL );
|
||||
if (sTco) {
|
||||
setCursor( m_cursorKnife );
|
||||
setMarkerPos( knifeMarkerPos( me ) );
|
||||
}
|
||||
update();
|
||||
}
|
||||
// None of the actions above, we will just handle the cursor
|
||||
else { updateCursor(me); }
|
||||
}
|
||||
|
||||
|
||||
@@ -918,17 +961,26 @@ void TrackContentObjectView::mouseReleaseEvent( QMouseEvent * me )
|
||||
{
|
||||
setSelected( !isSelected() );
|
||||
}
|
||||
|
||||
if( m_action == Move || m_action == Resize || m_action == ResizeLeft )
|
||||
else if( m_action == Move || m_action == Resize || m_action == ResizeLeft )
|
||||
{
|
||||
// TODO: Fix m_tco->setJournalling() consistency
|
||||
m_tco->setJournalling( true );
|
||||
}
|
||||
else if( m_action == Split )
|
||||
{
|
||||
const float ppb = m_trackView->trackContainerView()->pixelsPerBar();
|
||||
const TimePos relPos = me->pos().x() * TimePos::ticksPerBar() / ppb;
|
||||
splitTCO(unquantizedModHeld(me) ?
|
||||
relPos :
|
||||
quantizeSplitPos(relPos, me->modifiers() & Qt::ShiftModifier)
|
||||
);
|
||||
}
|
||||
|
||||
m_action = NoAction;
|
||||
delete m_hint;
|
||||
m_hint = NULL;
|
||||
s_textFloat->hide();
|
||||
leaveEvent( NULL );
|
||||
updateCursor(me);
|
||||
selectableObject::mouseReleaseEvent( me );
|
||||
}
|
||||
|
||||
@@ -1271,6 +1323,15 @@ bool TrackContentObjectView::mouseMovedDistance( QMouseEvent * me, int distance
|
||||
|
||||
|
||||
|
||||
|
||||
bool TrackContentObjectView::unquantizedModHeld( QMouseEvent * me )
|
||||
{
|
||||
return me->modifiers() & Qt::ControlModifier || me->modifiers() & Qt::AltModifier;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \brief Calculate the new position of a dragged TCO from a mouse event
|
||||
*
|
||||
*
|
||||
@@ -1285,12 +1346,8 @@ TimePos TrackContentObjectView::draggedTCOPos( QMouseEvent * me )
|
||||
TimePos newPos = m_initialTCOPos + mouseOff * TimePos::ticksPerBar() / ppb;
|
||||
TimePos offset = newPos - m_initialTCOPos;
|
||||
// If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize
|
||||
if ( me->button() != Qt::NoButton
|
||||
|| (me->modifiers() & Qt::ControlModifier)
|
||||
|| (me->modifiers() & Qt::AltModifier) )
|
||||
{
|
||||
// We want to preserve this adjusted offset,
|
||||
// even if the user switches to snapping
|
||||
if ( me->button() != Qt::NoButton || unquantizedModHeld(me) )
|
||||
{ // We want to preserve this adjusted offset, even if the user switches to snapping
|
||||
setInitialPos( m_initialMousePos );
|
||||
}
|
||||
else if ( me->modifiers() & Qt::ShiftModifier )
|
||||
@@ -1313,6 +1370,50 @@ TimePos TrackContentObjectView::draggedTCOPos( QMouseEvent * me )
|
||||
}
|
||||
|
||||
|
||||
int TrackContentObjectView::knifeMarkerPos( QMouseEvent * me )
|
||||
{
|
||||
//Position relative to start of clip
|
||||
const int markerPos = me->pos().x();
|
||||
|
||||
//In unquantized mode, we don't have to mess with the position at all
|
||||
if ( unquantizedModHeld(me) ) { return markerPos; }
|
||||
else
|
||||
{ //Otherwise we...
|
||||
//1: Convert the position to a TimePos
|
||||
const float ppb = m_trackView->trackContainerView()->pixelsPerBar();
|
||||
TimePos midiPos = markerPos * TimePos::ticksPerBar() / ppb;
|
||||
//2: Snap to the correct position, based on modifier keys
|
||||
midiPos = quantizeSplitPos( midiPos, me->modifiers() & Qt::ShiftModifier );
|
||||
//3: Convert back to a pixel position
|
||||
return midiPos * ppb / TimePos::ticksPerBar();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
TimePos TrackContentObjectView::quantizeSplitPos( TimePos midiPos, bool shiftMode )
|
||||
{
|
||||
const float snapSize = gui->songEditor()->m_editor->getSnapSize();
|
||||
if ( shiftMode )
|
||||
{ //If shift is held we quantize the length of the new left clip...
|
||||
const TimePos leftPos = midiPos.quantize( snapSize );
|
||||
//...or right clip...
|
||||
const TimePos rightOff = m_tco->length() - midiPos;
|
||||
const TimePos rightPos = m_tco->length() - rightOff.quantize( snapSize );
|
||||
//...whichever gives a position closer to the cursor
|
||||
if ( abs(leftPos - midiPos) < abs(rightPos - midiPos) ) { return leftPos; }
|
||||
else { return rightPos; }
|
||||
}
|
||||
else
|
||||
{
|
||||
return TimePos(midiPos + m_initialTCOPos).quantize( snapSize ) - m_initialTCOPos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Return the color that the TCO's background should be
|
||||
QColor TrackContentObjectView::getColorForDisplay( QColor defaultColor )
|
||||
{
|
||||
@@ -1355,4 +1456,3 @@ QColor TrackContentObjectView::getColorForDisplay( QColor defaultColor )
|
||||
// Return color to caller
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
@@ -449,6 +449,11 @@ void SongEditor::setEditModeDraw()
|
||||
setEditMode(DrawMode);
|
||||
}
|
||||
|
||||
void SongEditor::setEditModeKnife()
|
||||
{
|
||||
setEditMode(KnifeMode);
|
||||
}
|
||||
|
||||
void SongEditor::setEditModeSelect()
|
||||
{
|
||||
setEditMode(SelectMode);
|
||||
@@ -860,6 +865,14 @@ bool SongEditor::allowRubberband() const
|
||||
|
||||
|
||||
|
||||
bool SongEditor::knifeMode() const
|
||||
{
|
||||
return m_mode == KnifeMode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int SongEditor::trackIndexFromSelectionPoint(int yPos)
|
||||
{
|
||||
const TrackView * tv = trackViewAt(yPos - m_timeLine->height());
|
||||
@@ -944,13 +957,16 @@ SongEditorWindow::SongEditorWindow(Song* song) :
|
||||
|
||||
m_editModeGroup = new ActionGroup(this);
|
||||
m_drawModeAction = m_editModeGroup->addAction(embed::getIconPixmap("edit_draw"), tr("Draw mode"));
|
||||
m_knifeModeAction = m_editModeGroup->addAction(embed::getIconPixmap("edit_knife"), tr("Knife mode (split sample clips)"));
|
||||
m_selectModeAction = m_editModeGroup->addAction(embed::getIconPixmap("edit_select"), tr("Edit mode (select and move)"));
|
||||
m_drawModeAction->setChecked(true);
|
||||
|
||||
connect(m_drawModeAction, SIGNAL(triggered()), m_editor, SLOT(setEditModeDraw()));
|
||||
connect(m_knifeModeAction, SIGNAL(triggered()), m_editor, SLOT(setEditModeKnife()));
|
||||
connect(m_selectModeAction, SIGNAL(triggered()), m_editor, SLOT(setEditModeSelect()));
|
||||
|
||||
editActionsToolBar->addAction( m_drawModeAction );
|
||||
editActionsToolBar->addAction( m_knifeModeAction );
|
||||
editActionsToolBar->addAction( m_selectModeAction );
|
||||
|
||||
DropToolBar *timeLineToolBar = addDropToolBarToTop(tr("Timeline controls"));
|
||||
@@ -1031,6 +1047,13 @@ void SongEditorWindow::updateSnapLabel(){
|
||||
|
||||
|
||||
|
||||
void SongEditorWindow::syncEditMode(){
|
||||
m_editModeGroup->checkedAction()->trigger();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void SongEditorWindow::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
emit resized();
|
||||
@@ -1108,31 +1131,3 @@ void SongEditorWindow::adjustUiAfterProjectLoad()
|
||||
connect( qobject_cast<SubWindow *>( parentWidget() ), SIGNAL( focusLost() ), this, SLOT( lostFocus() ) );
|
||||
m_editor->scrolled(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void SongEditorWindow::keyPressEvent( QKeyEvent *ke )
|
||||
{
|
||||
if( ke->key() == Qt::Key_Control )
|
||||
{
|
||||
m_crtlAction = m_editModeGroup->checkedAction();
|
||||
m_selectModeAction->setChecked( true );
|
||||
m_selectModeAction->trigger();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void SongEditorWindow::keyReleaseEvent( QKeyEvent *ke )
|
||||
{
|
||||
if( ke->key() == Qt::Key_Control )
|
||||
{
|
||||
if( m_crtlAction )
|
||||
{
|
||||
m_crtlAction->setChecked( true );
|
||||
m_crtlAction->trigger();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -547,14 +547,22 @@ void TrackContentWidget::dropEvent( QDropEvent * de )
|
||||
*/
|
||||
void TrackContentWidget::mousePressEvent( QMouseEvent * me )
|
||||
{
|
||||
// Enable box select if control is held when clicking an empty space
|
||||
// (If we had clicked a TCO it would have intercepted the mouse event)
|
||||
if( me->modifiers() & Qt::ControlModifier ){
|
||||
gui->songEditor()->m_editor->setEditMode(SongEditor::EditMode::SelectMode);
|
||||
}
|
||||
// Forward event to allow box select if the editor supports it and is in that mode
|
||||
if( m_trackView->trackContainerView()->allowRubberband() == true )
|
||||
{
|
||||
QWidget::mousePressEvent( me );
|
||||
}
|
||||
// Forward shift clicks so tracks can be resized
|
||||
else if( me->modifiers() & Qt::ShiftModifier )
|
||||
{
|
||||
QWidget::mousePressEvent( me );
|
||||
}
|
||||
// For an unmodified click, create a new TCO
|
||||
else if( me->button() == Qt::LeftButton &&
|
||||
!m_trackView->trackContainerView()->fixedTCOs() )
|
||||
{
|
||||
@@ -573,6 +581,15 @@ void TrackContentWidget::mousePressEvent( QMouseEvent * me )
|
||||
|
||||
|
||||
|
||||
void TrackContentWidget::mouseReleaseEvent( QMouseEvent * me )
|
||||
{
|
||||
gui->songEditor()->syncEditMode();
|
||||
QWidget::mouseReleaseEvent(me);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \brief Repaint the trackContentWidget on command
|
||||
*
|
||||
* \param pe the Paint Event to respond to
|
||||
@@ -707,4 +724,3 @@ void TrackContentWidget::setGridColor( const QBrush & c )
|
||||
//! \brief CSS theming qproperty access method
|
||||
void TrackContentWidget::setEmbossColor( const QBrush & c )
|
||||
{ m_embossColor = c; }
|
||||
|
||||
|
||||
@@ -106,9 +106,6 @@ SampleTCO::SampleTCO( Track * _track ) :
|
||||
updateTrackTcos();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
SampleTCO::SampleTCO(const SampleTCO& orig) :
|
||||
SampleTCO(orig.getTrack())
|
||||
{
|
||||
@@ -634,6 +631,10 @@ void SampleTCOView::paintEvent( QPaintEvent * pe )
|
||||
embed::getIconPixmap( "muted", size, size ) );
|
||||
}
|
||||
|
||||
if ( m_marker )
|
||||
{
|
||||
p.drawLine(m_markerPos, rect().bottom(), m_markerPos, rect().top());
|
||||
}
|
||||
// recording sample tracks is not possible at the moment
|
||||
|
||||
/* if( m_tco->isRecord() )
|
||||
@@ -667,6 +668,39 @@ void SampleTCOView::reverseSample()
|
||||
|
||||
|
||||
|
||||
//! Split this TCO.
|
||||
/*! \param pos the position of the split, relative to the start of the clip */
|
||||
bool SampleTCOView::splitTCO( const TimePos pos )
|
||||
{
|
||||
setMarkerEnabled( false );
|
||||
|
||||
const TimePos splitPos = m_initialTCOPos + pos;
|
||||
|
||||
//Don't split if we slid off the TCO or if we're on the clip's start/end
|
||||
//Cutting at exactly the start/end position would create a zero length
|
||||
//clip (bad), and a clip the same length as the original one (pointless).
|
||||
if ( splitPos > m_initialTCOPos && splitPos < m_initialTCOEnd )
|
||||
{
|
||||
m_tco->getTrack()->addJournalCheckPoint();
|
||||
m_tco->getTrack()->saveJournallingState( false );
|
||||
|
||||
SampleTCO * rightTCO = new SampleTCO ( *m_tco );
|
||||
|
||||
m_tco->changeLength( splitPos - m_initialTCOPos );
|
||||
|
||||
rightTCO->movePosition( splitPos );
|
||||
rightTCO->changeLength( m_initialTCOEnd - splitPos );
|
||||
rightTCO->setStartTimeOffset( m_tco->startTimeOffset() - m_tco->length() );
|
||||
|
||||
m_tco->getTrack()->restoreJournallingState();
|
||||
return true;
|
||||
}
|
||||
else { return false; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
SampleTrack::SampleTrack(TrackContainer* tc) :
|
||||
|
||||
Reference in New Issue
Block a user