5 Commits ca0ed811f0 ... e348475d3e

Author SHA1 Message Date
  CYBERDEViL e348475d3e Make razor cut-line (color) themable. 3 years ago
  CYBERDEViL 219ff68981 Cancel razor action on SHIFT release. 3 years ago
  CYBERDEViL 10efa14f03 Style change suggested by @russiankumar 3 years ago
  Ian Caio 2529604c1c Removes an extra call to noteUnderMouse 3 years ago
  Ian Caio 20a37ea460 Extract the split action to a separate method 3 years ago
5 changed files with 107 additions and 52 deletions
  1. 1 0
      data/themes/default/style.css
  2. 3 0
      include/Pattern.h
  3. 8 2
      include/PianoRoll.h
  4. 61 50
      src/gui/editors/PianoRoll.cpp
  5. 34 0
      src/tracks/Pattern.cpp

+ 1 - 0
data/themes/default/style.css

@@ -187,6 +187,7 @@ PianoRoll {
 	qproperty-ghostNoteBorders: false;
 	qproperty-barColor: #078f3a;
 	qproperty-markedSemitoneColor: rgba(255, 255, 255, 30);
+	qproperty-razorCutLine: rgba(255, 0, 0, 255);
 	/* Piano keys */
 	qproperty-whiteKeyWidth: 64;
 	qproperty-whiteKeyActiveTextColor: #000;

+ 3 - 0
include/Pattern.h

@@ -76,6 +76,9 @@ public:
 	Note * addStepNote( int step );
 	void setStep( int step, bool enabled );
 
+	// Split the list of notes on the given position
+	void splitNotes(NoteVector notes, TimePos pos);
+
 	// pattern-type stuff
 	inline PatternTypes type() const
 	{

+ 8 - 2
include/PianoRoll.h

@@ -70,6 +70,7 @@ class PianoRoll : public QWidget
 	Q_PROPERTY(QColor textColorLight MEMBER m_textColorLight)
 	Q_PROPERTY(QColor textShadow MEMBER m_textShadow)
 	Q_PROPERTY(QColor markedSemitoneColor MEMBER m_markedSemitoneColor)
+	Q_PROPERTY(QColor razorCutLine MEMBER m_razorCutLineColor)
 	Q_PROPERTY(int noteOpacity MEMBER m_noteOpacity)
 	Q_PROPERTY(bool noteBorders MEMBER m_noteBorders)
 	Q_PROPERTY(int ghostNoteOpacity MEMBER m_ghostNoteOpacity)
@@ -286,7 +287,6 @@ private:
 
 	void setRazorAction();
 	void cancelRazorAction();
-	int getMouseTickPos();
 
 	void updateScrollbars();
 	void updatePositionLineHeight();
@@ -310,7 +310,7 @@ private:
 	static QPixmap * s_toolSelect;
 	static QPixmap * s_toolMove;
 	static QPixmap * s_toolOpen;
-	static QPixmap * s_toolRazor;
+	static QPixmap* s_toolRazor;
 
 	static PianoRollKeyTypes prKeyOrder[];
 
@@ -399,6 +399,7 @@ private:
 	EditModes m_razorMode; // mode they where in before entering razor
 
 	bool m_mouseDownRight; //true if right click is being held down
+	bool m_firstRazorSplit; // if it's allowed to cancel razor action on SHIFT release event.
 
 	TimeLineWidget * m_timeLine;
 	bool m_scrollBack;
@@ -416,6 +417,10 @@ private:
 	// did we start a mouseclick with shift pressed
 	bool m_startedWithShift;
 
+	// Variable that holds the position in ticks for the razor action
+	int m_razorTickPos;
+	void updateRazorPos(QMouseEvent* me);
+
 	friend class PianoRollWindow;
 
 	StepRecorderWidget m_stepRecorderWidget;
@@ -436,6 +441,7 @@ private:
 	QColor m_textColorLight;
 	QColor m_textShadow;
 	QColor m_markedSemitoneColor;
+	QColor m_razorCutLineColor;
 	int m_noteOpacity;
 	int m_ghostNoteOpacity;
 	bool m_noteBorders;

+ 61 - 50
src/gui/editors/PianoRoll.cpp

@@ -115,7 +115,7 @@ QPixmap * PianoRoll::s_toolErase = NULL;
 QPixmap * PianoRoll::s_toolSelect = NULL;
 QPixmap * PianoRoll::s_toolMove = NULL;
 QPixmap * PianoRoll::s_toolOpen = NULL;
-QPixmap * PianoRoll::s_toolRazor = NULL;
+QPixmap* PianoRoll::s_toolRazor = nullptr;
 
 TextFloat * PianoRoll::s_textFloat = NULL;
 
@@ -185,6 +185,7 @@ PianoRoll::PianoRoll() :
 	m_editMode( ModeDraw ),
 	m_ctrlMode( ModeDraw ),
 	m_mouseDownRight( false ),
+	m_firstRazorSplit(false),
 	m_scrollBack( false ),
 	m_stepRecorderWidget(this, DEFAULT_PR_PPB, PR_TOP_MARGIN, PR_BOTTOM_MARGIN + m_notesEditHeight, WHITE_KEY_WIDTH, 0),
 	m_stepRecorder(*this, m_stepRecorderWidget),
@@ -201,6 +202,7 @@ PianoRoll::PianoRoll() :
 	m_textColorLight( 0, 0, 0 ),
 	m_textShadow( 0, 0, 0 ),
 	m_markedSemitoneColor( 0, 0, 0 ),
+	m_razorCutLineColor(0, 0, 0),
 	m_noteOpacity( 255 ),
 	m_ghostNoteOpacity( 255 ),
 	m_noteBorders( true ),
@@ -272,9 +274,9 @@ PianoRoll::PianoRoll() :
 	{
 		s_toolOpen = new QPixmap( embed::getIconPixmap( "automation" ) );
 	}
-	if( s_toolRazor == NULL )
+	if (s_toolRazor == nullptr)
 	{
-		s_toolRazor = new QPixmap( embed::getIconPixmap( "razor" ) );
+		s_toolRazor = new QPixmap(embed::getIconPixmap("razor"));
 	}
 
 	// init text-float
@@ -1273,6 +1275,7 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke)
 			break;
 
 		case Qt::Key_Escape:
+			// On the Razor mode, ESC cancels it
 			if (m_editMode == ModeEditRazor)
 			{
 				cancelRazorAction();
@@ -1326,6 +1329,8 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke)
 		}
 
 		case Qt::Key_Control:
+			// Ctrl will not enter selection mode if we are
+			// in Razor mode, but unquantize it
 			if (m_editMode == ModeEditRazor)
 			{
 				break;
@@ -1378,6 +1383,12 @@ void PianoRoll::keyReleaseEvent(QKeyEvent* ke )
 			update();
 			break;
 
+		case Qt::Key_Shift:
+			if (m_editMode == ModeEditRazor && !m_firstRazorSplit)
+			{
+				cancelRazorAction();
+			}
+
 		// update after undo/redo
 		case Qt::Key_Z:
 		case Qt::Key_R:
@@ -1462,40 +1473,27 @@ void PianoRoll::mousePressEvent(QMouseEvent * me )
 	}
 
 	// -- Razor
-	if (m_editMode == ModeEditRazor && me->button() == Qt::LeftButton
-		&& noteUnderMouse())
+	if (m_editMode == ModeEditRazor && me->button() == Qt::LeftButton)
 	{
-		Note * n = noteUnderMouse();
+		NoteVector n;
+		Note* note = noteUnderMouse();
 
-		float zoomFactor = ((float)m_ppb / TimePos::ticksPerBar());
-		int x = getMouseTickPos() - m_whiteKeyWidth;
-		int newLength = ((x/zoomFactor) + (m_currentPosition) - (n->pos()));
-		int leftOverLength = n->length() - newLength;
-
-		if (!newLength || !leftOverLength)
+		if (note)
 		{
-			return;
-		}
+			n.append(note);
 
-		m_pattern->addJournalCheckPoint();
+			updateRazorPos(me);
 
-		// Reduce note length
-		n->setLength(newLength);
-
-		// Add note with leftover length
-		Note noteCopy(
-			leftOverLength,
-			n->pos() + newLength,
-			n->key(),
-			n->getVolume(),
-			n->getPanning(),
-			n->detuning()
-		);
-		if (n->selected()) { noteCopy.setSelected(true); }
-		m_pattern->addNote(noteCopy, false);
+			// Call splitNotes for the note
+			m_pattern->splitNotes(n, TimePos(m_razorTickPos));
+
+			// Allow cancel razor mode when shift is released (if hold down).
+			m_firstRazorSplit = false;
+		}
 
 		// Keep in razor mode while SHIFT is hold during cut
-		if (!(me->modifiers() & Qt::ShiftModifier)) {
+		if (!(me->modifiers() & Qt::ShiftModifier))
+		{
 			cancelRazorAction();
 		}
 
@@ -2012,6 +2010,7 @@ void PianoRoll::setRazorAction()
 {
 	if (m_editMode != ModeEditRazor)
 	{
+		m_firstRazorSplit = true;
 		m_razorMode = m_editMode;
 		m_editMode = ModeEditRazor;
 		m_action = ActionRazor;
@@ -2027,15 +2026,6 @@ void PianoRoll::cancelRazorAction()
 	update();
 }
 
-int PianoRoll::getMouseTickPos() {
-	QPoint pos = mapFromGlobal(QCursor::pos());
-	int pixelsPer = m_ppb / (TimePos::ticksPerBar() / quantization());
-	float zoomFactor = ((float)m_ppb / TimePos::ticksPerBar());
-	int scrollOffset = (int)(m_currentPosition * zoomFactor) % pixelsPer;
-	return (pixelsPer * (((pos.x() - m_whiteKeyWidth)) / pixelsPer) + (m_whiteKeyWidth - scrollOffset));
-}
-
-
 
 
 void PianoRoll::testPlayKey( int key, int velocity, int pan )
@@ -2136,6 +2126,7 @@ void PianoRoll::mouseReleaseEvent( QMouseEvent * me )
 
 	s_textFloat->hide();
 
+	// Quit razor mode if we pressed and released the right mouse button
 	if (m_editMode == ModeEditRazor && me->button() == Qt::RightButton)
 	{
 		cancelRazorAction();
@@ -2260,6 +2251,12 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me )
 		return;
 	}
 
+	// Update Razor position if we are on Razor mode
+	if (m_editMode == ModeEditRazor)
+	{
+		updateRazorPos(me);
+	}
+
 	if( me->y() > PR_TOP_MARGIN || m_action != ActionNone )
 	{
 		bool edit_note = ( me->y() > noteEditTop() )
@@ -2635,6 +2632,24 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me )
 
 
 
+void PianoRoll::updateRazorPos(QMouseEvent* me)
+{
+	// Calculate the TimePos from the mouse
+	int mouseViewportPos = me->x() - m_whiteKeyWidth;
+	int mouseTickPos = mouseViewportPos / (m_ppb / TimePos::ticksPerBar()) + m_currentPosition;
+
+	// If ctrl is not pressed, quantize the position
+	if (!(me->modifiers() & Qt::ControlModifier))
+	{
+		mouseTickPos = floor(mouseTickPos / quantization()) * quantization();
+	}
+
+	m_razorTickPos = mouseTickPos;
+}
+
+
+
+
 void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl )
 {
 	// dragging one or more notes around
@@ -3335,27 +3350,23 @@ void PianoRoll::paintEvent(QPaintEvent * pe )
 		// -- Razor tool (draw cut line)
 		if (m_action == ActionRazor)
 		{
-			auto xCoordOfTick = [=](int tick) {
+			auto xCoordOfTick = [this](int tick) {
 				return m_whiteKeyWidth + (
-					(tick - m_currentPosition) * m_ppb / TimePos::ticksPerBar()
-				);
+					(tick - m_currentPosition) * m_ppb / TimePos::ticksPerBar());
 			};
-			Note * n = noteUnderMouse();
+			Note* n = noteUnderMouse();
 			if (n)
 			{
 				const int key = n->key() - m_startKey + 1;
 				int y = y_base - key * m_keyLineHeight;
-				int x = getMouseTickPos();
+
+				int x = xCoordOfTick(m_razorTickPos);
 
 				if (x > xCoordOfTick(n->pos()) &&
 					x < xCoordOfTick(n->pos() + n->length()))
 				{
-					p.setPen(QPen(QColor("#FF0000"), 1));
-					p.drawLine(
-						x, y,
-						x,
-						y + m_keyLineHeight
-					);
+					p.setPen(QPen(m_razorCutLineColor, 1));
+					p.drawLine(x, y, x, y + m_keyLineHeight);
 
 					setCursor(Qt::BlankCursor);
 				}

+ 34 - 0
src/tracks/Pattern.cpp

@@ -324,6 +324,40 @@ void Pattern::setStep( int step, bool enabled )
 
 
 
+void Pattern::splitNotes(NoteVector notes, TimePos pos)
+{
+	if (notes.empty()) { return; }
+
+	addJournalCheckPoint();
+
+	for (int i = 0; i < notes.size(); ++i)
+	{
+		Note* note = notes.at(i);
+
+		int leftLength = pos.getTicks() - note->pos();
+		int rightLength = note->length() - leftLength;
+
+		// Split out of bounds
+		if (leftLength <= 0 || rightLength <= 0)
+		{
+			continue;
+		}
+
+		// Reduce note length
+		note->setLength(leftLength);
+
+		// Add new note with the remaining length
+		Note newNote = Note(*note);
+		newNote.setLength(rightLength);
+		newNote.setPos(note->pos() + leftLength);
+
+		addNote(newNote, false);
+	}
+}
+
+
+
+
 void Pattern::setType( PatternTypes _new_pattern_type )
 {
 	if( _new_pattern_type == BeatPattern ||