diff options
Diffstat (limited to 'src/gui/editors/segment/segmentcanvas/SegmentResizer.cpp')
-rw-r--r-- | src/gui/editors/segment/segmentcanvas/SegmentResizer.cpp | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/src/gui/editors/segment/segmentcanvas/SegmentResizer.cpp b/src/gui/editors/segment/segmentcanvas/SegmentResizer.cpp new file mode 100644 index 0000000..6ae7433 --- /dev/null +++ b/src/gui/editors/segment/segmentcanvas/SegmentResizer.cpp @@ -0,0 +1,393 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rosegarden + A MIDI and audio sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <[email protected]>, + Chris Cannam <[email protected]>, + Richard Bown <[email protected]> + + The moral rights of Guillaume Laurent, Chris Cannam, and Richard + Bown to claim authorship of this work have been asserted. + + Other copyrights also apply to some parts of this work. Please + see the AUTHORS file and individual file headers for details. + + 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. See the file + COPYING included with this distribution for more information. +*/ + + +#include "SegmentResizer.h" + +#include "base/Event.h" +#include <klocale.h> +#include "misc/Debug.h" +#include "base/Composition.h" +#include "base/NotationTypes.h" +#include "base/Segment.h" +#include "base/Track.h" +#include "base/SnapGrid.h" +#include "commands/segment/AudioSegmentResizeFromStartCommand.h" +#include "commands/segment/AudioSegmentRescaleCommand.h" +#include "commands/segment/SegmentRescaleCommand.h" +#include "commands/segment/SegmentReconfigureCommand.h" +#include "commands/segment/SegmentResizeFromStartCommand.h" +#include "CompositionItemHelper.h" +#include "CompositionModel.h" +#include "CompositionView.h" +#include "document/RosegardenGUIDoc.h" +#include "gui/general/BaseTool.h" +#include "gui/application/RosegardenGUIApp.h" +#include "gui/general/RosegardenCanvasView.h" +#include "gui/widgets/ProgressDialog.h" +#include "SegmentTool.h" +#include <kcommand.h> +#include <kmessagebox.h> +#include <qcursor.h> +#include <qevent.h> +#include <qpoint.h> +#include <qrect.h> +#include <qstring.h> + + +namespace Rosegarden +{ + +SegmentResizer::SegmentResizer(CompositionView *c, RosegardenGUIDoc *d, + int edgeThreshold) + : SegmentTool(c, d), + m_edgeThreshold(edgeThreshold) +{ + RG_DEBUG << "SegmentResizer()\n"; +} + +void SegmentResizer::ready() +{ + m_canvas->viewport()->setCursor(Qt::sizeHorCursor); + connect(m_canvas, SIGNAL(contentsMoving (int, int)), + this, SLOT(slotCanvasScrolled(int, int))); + setBasicContextHelp(false); +} + +void SegmentResizer::stow() +{ + disconnect(m_canvas, SIGNAL(contentsMoving (int, int)), + this, SLOT(slotCanvasScrolled(int, int))); +} + +void SegmentResizer::slotCanvasScrolled(int newX, int newY) +{ + QMouseEvent tmpEvent(QEvent::MouseMove, + m_canvas->viewport()->mapFromGlobal(QCursor::pos()) + QPoint(newX, newY), + Qt::NoButton, Qt::NoButton); + handleMouseMove(&tmpEvent); +} + +void SegmentResizer::handleMouseButtonPress(QMouseEvent *e) +{ + RG_DEBUG << "SegmentResizer::handleMouseButtonPress" << endl; + m_canvas->getModel()->clearSelected(); + + CompositionItem item = m_canvas->getFirstItemAt(e->pos()); + + if (item) { + RG_DEBUG << "SegmentResizer::handleMouseButtonPress - got item" << endl; + setCurrentItem(item); + + // Are we resizing from start or end? + if (item->rect().x() + item->rect().width() / 2 > e->pos().x()) { + m_resizeStart = true; + } else { + m_resizeStart = false; + } + + m_canvas->getModel()->startChange(item, m_resizeStart ? CompositionModel::ChangeResizeFromStart : CompositionModel::ChangeResizeFromEnd); + + } +} + +void SegmentResizer::handleMouseButtonRelease(QMouseEvent *e) +{ + RG_DEBUG << "SegmentResizer::handleMouseButtonRelease" << endl; + + bool rescale = (e->state() & Qt::ControlButton); + + if (m_currentItem) { + + Segment* segment = CompositionItemHelper::getSegment(m_currentItem); + + // We only want to snap the end that we were actually resizing. + + timeT oldStartTime, oldEndTime; + + oldStartTime = segment->getStartTime(); + oldEndTime = segment->getEndMarkerTime(); + + timeT newStartTime, newEndTime; + + if (m_resizeStart) { + newStartTime = CompositionItemHelper::getStartTime + (m_currentItem, m_canvas->grid()); + newEndTime = oldEndTime; + } else { + newEndTime = CompositionItemHelper::getEndTime + (m_currentItem, m_canvas->grid()); + newStartTime = oldStartTime; + } + + if (changeMade()) { + + if (newStartTime > newEndTime) std::swap(newStartTime, newEndTime); + + if (rescale) { + + if (segment->getType() == Segment::Audio) { + + try { + m_doc->getAudioFileManager().testAudioPath(); + } catch (AudioFileManager::BadAudioPathException) { + if (KMessageBox::warningContinueCancel + (0, + i18n("The audio file path does not exist or is not writable.\nYou must set the audio file path to a valid directory in Document Properties before rescaling an audio file.\nWould you like to set it now?"), + i18n("Warning"), + i18n("Set audio file path")) == KMessageBox::Continue) { + RosegardenGUIApp::self()->slotOpenAudioPathSettings(); + } + } + + float ratio = float(newEndTime - newStartTime) / + float(oldEndTime - oldStartTime); + + AudioSegmentRescaleCommand *command = + new AudioSegmentRescaleCommand(m_doc, segment, ratio, + newStartTime, newEndTime); + + ProgressDialog progressDlg + (i18n("Rescaling audio file..."), 100, 0); + progressDlg.setAutoClose(false); + progressDlg.setAutoReset(false); + progressDlg.show(); + command->connectProgressDialog(&progressDlg); + + addCommandToHistory(command); + + progressDlg.setLabel(i18n("Generating audio preview...")); + command->disconnectProgressDialog(&progressDlg); + connect(&m_doc->getAudioFileManager(), SIGNAL(setProgress(int)), + progressDlg.progressBar(), SLOT(setValue(int))); + connect(&progressDlg, SIGNAL(cancelClicked()), + &m_doc->getAudioFileManager(), SLOT(slotStopPreview())); + + int fid = command->getNewAudioFileId(); + if (fid >= 0) { + RosegardenGUIApp::self()->slotAddAudioFile(fid); + m_doc->getAudioFileManager().generatePreview(fid); + } + + } else { + + SegmentRescaleCommand *command = + new SegmentRescaleCommand(segment, + newEndTime - newStartTime, + oldEndTime - oldStartTime, + newStartTime); + addCommandToHistory(command); + } + } else { + + if (m_resizeStart) { + + if (segment->getType() == Segment::Audio) { + addCommandToHistory(new AudioSegmentResizeFromStartCommand + (segment, newStartTime)); + } else { + addCommandToHistory(new SegmentResizeFromStartCommand + (segment, newStartTime)); + } + + } else { + + SegmentReconfigureCommand *command = + new SegmentReconfigureCommand("Resize Segment"); + + int trackPos = CompositionItemHelper::getTrackPos + (m_currentItem, m_canvas->grid()); + + Composition &comp = m_doc->getComposition(); + Track *track = comp.getTrackByPosition(trackPos); + + command->addSegment(segment, + newStartTime, + newEndTime, + track->getId()); + addCommandToHistory(command); + } + } + } + } + + m_canvas->getModel()->endChange(); + m_canvas->updateContents(); + setChangeMade(false); + m_currentItem = CompositionItem(); + setBasicContextHelp(); +} + +int SegmentResizer::handleMouseMove(QMouseEvent *e) +{ + // RG_DEBUG << "SegmentResizer::handleMouseMove" << endl; + + bool rescale = (e->state() & Qt::ControlButton); + + if (!m_currentItem) { + setBasicContextHelp(rescale); + return RosegardenCanvasView::NoFollow; + } + + if (rescale) { + if (!m_canvas->isFineGrain()) { + setContextHelp(i18n("Hold Shift to avoid snapping to beat grid")); + } else { + clearContextHelp(); + } + } else { + if (!m_canvas->isFineGrain()) { + setContextHelp(i18n("Hold Shift to avoid snapping to beat grid; hold Ctrl as well to rescale contents")); + } else { + setContextHelp("Hold Ctrl to rescale contents"); + } + } + + Segment* segment = CompositionItemHelper::getSegment(m_currentItem); + + // Don't allow Audio segments to resize yet + // + /*!!! + if (segment->getType() == Segment::Audio) + { + m_currentItem = CompositionItem(); + KMessageBox::information(m_canvas, + i18n("You can't yet resize an audio segment!")); + return RosegardenCanvasView::NoFollow; + } + */ + + QRect oldRect = m_currentItem->rect(); + + m_canvas->setSnapGrain(true); + + timeT time = m_canvas->grid().snapX(e->pos().x()); + timeT snap = m_canvas->grid().getSnapTime(double(e->pos().x())); + if (snap == 0) + snap = Note(Note::Shortest).getDuration(); + + // We only want to snap the end that we were actually resizing. + + timeT itemStartTime, itemEndTime; + + if (m_resizeStart) { + itemStartTime = CompositionItemHelper::getStartTime + (m_currentItem, m_canvas->grid()); + itemEndTime = segment->getEndMarkerTime(); + } else { + itemEndTime = CompositionItemHelper::getEndTime + (m_currentItem, m_canvas->grid()); + itemStartTime = segment->getStartTime(); + } + + timeT duration = 0; + + if (m_resizeStart) { + + duration = itemEndTime - time; + // RG_DEBUG << "SegmentResizer::handleMouseMove() resize start : duration = " + // << duration << " - snap = " << snap + // << " - itemEndTime : " << itemEndTime + // << " - time : " << time + // << endl; + + timeT newStartTime = 0; + + if ((duration > 0 && duration < snap) || + (duration < 0 && duration > -snap)) { + + newStartTime = itemEndTime - (duration < 0 ? -snap : snap); + + } else { + + newStartTime = itemEndTime - duration; + + } + + CompositionItemHelper::setStartTime(m_currentItem, + newStartTime, + m_canvas->grid()); + } else { // resize end + + duration = time - itemStartTime; + + timeT newEndTime = 0; + + // RG_DEBUG << "SegmentResizer::handleMouseMove() resize end : duration = " + // << duration << " - snap = " << snap + // << " - itemEndTime : " << itemEndTime + // << " - time : " << time + // << endl; + + if ((duration > 0 && duration < snap) || + (duration < 0 && duration > -snap)) { + + newEndTime = (duration < 0 ? -snap : snap) + itemStartTime; + + } else { + + newEndTime = duration + itemStartTime; + + } + + CompositionItemHelper::setEndTime(m_currentItem, + newEndTime, + m_canvas->grid()); + } + + if (duration != 0) + setChangeMade(true); + + m_canvas->slotUpdateSegmentsDrawBuffer(m_currentItem->rect() | oldRect); + + return RosegardenCanvasView::FollowHorizontal; +} + +bool SegmentResizer::cursorIsCloseEnoughToEdge(const CompositionItem& p, const QPoint &coord, + int edgeThreshold, bool &start) +{ + if (abs(p->rect().x() + p->rect().width() - coord.x()) < edgeThreshold) { + start = false; + return true; + } else if (abs(p->rect().x() - coord.x()) < edgeThreshold) { + start = true; + return true; + } else { + return false; + } +} + +void SegmentResizer::setBasicContextHelp(bool ctrlPressed) +{ + if (ctrlPressed) { + setContextHelp(i18n("Click and drag to resize a segment; hold Ctrl as well to rescale its contents")); + } else { + setContextHelp(i18n("Click and drag to rescale segment")); + } +} + +const QString SegmentResizer::ToolName = "segmentresizer"; + +} +#include "SegmentResizer.moc" |