/*
Rosegarden
A MIDI and audio sequencer and musical notation editor .
This program is Copyright 2000 - 2008
Guillaume Laurent < glaurent @ telegraph - road . org > ,
Chris Cannam < cannam @ all - day - breakfast . com > ,
Richard Bown < richard . bown @ ferventsoftware . com >
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 <tdelocale.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 <tdemessagebox.h>
# include <tqcursor.h>
# include <tqevent.h>
# include <tqpoint.h>
# include <tqrect.h>
# include <tqstring.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 ( TQt : : sizeHorCursor ) ;
connect ( m_canvas , TQ_SIGNAL ( contentsMoving ( int , int ) ) ,
this , TQ_SLOT ( slotCanvasScrolled ( int , int ) ) ) ;
setBasicContextHelp ( false ) ;
}
void SegmentResizer : : stow ( )
{
disconnect ( m_canvas , TQ_SIGNAL ( contentsMoving ( int , int ) ) ,
this , TQ_SLOT ( slotCanvasScrolled ( int , int ) ) ) ;
}
void SegmentResizer : : slotCanvasScrolled ( int newX , int newY )
{
TQMouseEvent tmpEvent ( TQEvent : : MouseMove ,
m_canvas - > viewport ( ) - > mapFromGlobal ( TQCursor : : pos ( ) ) + TQPoint ( newX , newY ) ,
TQt : : NoButton , TQt : : NoButton ) ;
handleMouseMove ( & tmpEvent ) ;
}
void SegmentResizer : : handleMouseButtonPress ( TQMouseEvent * 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 ( TQMouseEvent * e )
{
RG_DEBUG < < " SegmentResizer::handleMouseButtonRelease " < < endl ;
bool rescale = ( e - > state ( ) & TQt : : 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. \n You must set the audio file path to a valid directory in Document Properties before rescaling an audio file. \n Would 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 ( ) , TQ_SIGNAL ( setProgress ( int ) ) ,
progressDlg . progressBar ( ) , TQ_SLOT ( setValue ( int ) ) ) ;
connect ( & progressDlg , TQ_SIGNAL ( cancelClicked ( ) ) ,
& m_doc - > getAudioFileManager ( ) , TQ_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 ( TQMouseEvent * e )
{
// RG_DEBUG << "SegmentResizer::handleMouseMove" << endl;
bool rescale = ( e - > state ( ) & TQt : : 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 ;
}
*/
TQRect 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 TQPoint & 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 TQString SegmentResizer : : ToolName = " segmentresizer " ;
}
# include "SegmentResizer.moc"