123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476 |
- //-----------------------------------------------------------------------------
- // Verve
- // Copyright (C) 2014 - Violent Tulip
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "Verve/GUI/VTimeLineControl.h"
- #include "console/consoleTypes.h"
- #include "gfx/gfxDrawUtil.h"
- #include "gui/core/guiCanvas.h"
- //-----------------------------------------------------------------------------
- const S32 gUnitsPerSec = 200;
- //-----------------------------------------------------------------------------
- IMPLEMENT_CONOBJECT( VTimeLineControl );
- //-----------------------------------------------------------------------------
- VTimeLineControl::VTimeLineControl( void ) :
- mIsController( true ),
- mController( NULL ),
- mDurationOffset( 50 )
- {
- mSelection.Active = false;
- mSelection.StartTime = 0;
- mSelection.EndTime = 0;
- }
- void VTimeLineControl::initPersistFields( void )
- {
- Parent::initPersistFields();
- addField( "IsController", TypeBool, Offset( mIsController, VTimeLineControl ) );
- addField( "Controller", TYPEID<VController>(), Offset( mController, VTimeLineControl ) );
- addField( "DurationOffset", TypeS32, Offset( mDurationOffset, VTimeLineControl ) );
- }
- //-----------------------------------------------------------------------------
- //
- // Mouse Methods.
- //
- //-----------------------------------------------------------------------------
- void VTimeLineControl::onMouseDown( const GuiEvent &pEvent )
- {
- Parent::onMouseDown( pEvent );
- if ( !mIsController || !mController || mController->isPlaying() )
- {
- return;
- }
- if ( !isMouseLocked() )
- {
- GuiCanvas *canvas = getRoot();
- if ( canvas->getMouseLockedControl() )
- {
- GuiEvent event;
- canvas->getMouseLockedControl()->onMouseLeave( event );
- canvas->mouseUnlock( canvas->getMouseLockedControl() );
- }
- // Lock.
- mouseLock();
- }
- // Calculate Time.
- const Point2I hitPoint = globalToLocalCoord( pEvent.mousePoint );
- const S32 time = mClamp( toTime( hitPoint.x ), 0, mController->getDuration() );
- // Selection?
- if ( pEvent.modifier & SI_SHIFT )
- {
- if ( !mSelection.Active )
- {
- // Selection Active.
- mSelection.Active = true;
- mSelection.StartTime = mController->getTime();
- mSelection.EndTime = time;
- }
- else
- {
- // Update Selection.
- mSelection.EndTime = time;
- }
- // Callback.
- Con::executef( this, "onSelectionUpdate" );
- }
- else
- {
- if ( mSelection.Active )
- {
- // Selection Invalid.
- mSelection.Active = false;
- // Callback.
- Con::executef( this, "onSelectionUpdate" );
- }
- }
- // Set First Responder.
- setFirstResponder();
- if ( pEvent.modifier & SI_CTRL )
- {
- // Set Time, No Reset.
- mController->setTime( time );
- }
- else
- {
- // Reset.
- mController->reset( time );
- }
- }
- void VTimeLineControl::onMouseUp( const GuiEvent &pEvent )
- {
- if ( isMouseLocked() )
- {
- // Unlock.
- mouseUnlock();
- }
- if ( mIsController && mController && !mController->isPlaying() )
- {
- // Stop without Reset.
- mController->stop( false );
- }
- }
- void VTimeLineControl::onMouseDragged( const GuiEvent &pEvent )
- {
- Parent::onMouseDragged( pEvent );
- if ( !mIsController || !mController || mController->isPlaying() )
- {
- return;
- }
- // Calculate Time.
- const Point2I hitPoint = globalToLocalCoord( pEvent.mousePoint );
- const S32 time = mClamp( toTime( hitPoint.x ), 0, mController->getDuration() );
- if ( pEvent.modifier & SI_SHIFT )
- {
- if ( mSelection.Active )
- {
- // Update Selection.
- mSelection.EndTime = time;
- // Callback.
- Con::executef( this, "onSelectionUpdate" );
- }
- }
- else
- {
- if ( mSelection.Active )
- {
- // Selection Invalid.
- mSelection.Active = false;
- // Callback.
- Con::executef( this, "onSelectionUpdate" );
- }
- }
- if ( pEvent.modifier & SI_CTRL )
- {
- // Set Time, No Reset.
- mController->setTime( time );
- }
- else if ( !mSelection.Active )
- {
- // Reset.
- mController->reset( time );
- }
- }
- void VTimeLineControl::onRightMouseDown( const GuiEvent &pEvent )
- {
- Parent::onRightMouseDown( pEvent );
- if ( !mIsController || !mController || mController->isPlaying() )
- {
- return;
- }
- // Calculate Time.
- const Point2I hitPoint = globalToLocalCoord( pEvent.mousePoint );
- const S32 time = mClamp( toTime( hitPoint.x ), 0, mController->getDuration() );
- // Set First Responder.
- setFirstResponder();
- if ( mSelection.Active )
- {
- const S32 minTime = getMin( mSelection.StartTime, mSelection.EndTime );
- const S32 maxTime = getMax( mSelection.StartTime, mSelection.EndTime );
- if ( time >= minTime && time <= maxTime )
- {
- // Callback.
- onMouseEvent( "onSelectionRightClick", pEvent );
- // Don't Update Time.
- return;
- }
- else
- {
- if ( mSelection.Active )
- {
- // Selection Invalid.
- mSelection.Active = false;
- // Callback.
- Con::executef( this, "onSelectionUpdate" );
- }
- }
- }
- // Reset.
- mController->reset( time );
- }
- void VTimeLineControl::onMouseEvent( const char *pEventName, const GuiEvent &pEvent )
- {
- // Argument Buffers.
- char argBuffer[3][32];
- // Format Event-Position Buffer.
- dSprintf( argBuffer[0], 32, "%d %d", pEvent.mousePoint.x, pEvent.mousePoint.y );
- // Format Event-Modifier Buffer.
- dSprintf( argBuffer[1], 32, "%d", pEvent.modifier );
- // Format Mouse-Click Count Buffer.
- dSprintf( argBuffer[2], 32, "%d", pEvent.mouseClickCount );
- // Call Scripts.
- Con::executef( this, pEventName, argBuffer[0], argBuffer[1], argBuffer[2] );
- }
- //-----------------------------------------------------------------------------
- //
- // Render Methods.
- //
- //-----------------------------------------------------------------------------
- void VTimeLineControl::onPreRender( void )
- {
- setUpdate();
- }
- void VTimeLineControl::onRender( Point2I offset, const RectI &updateRect )
- {
- if ( !mController )
- {
- // Default Render.
- Parent::onRender( offset, updateRect );
- // Quit.
- return;
- }
- // Render Properties.
- const S32 tickOffset = toPoint( 0 );
- const S32 timeLineWidth = toPoint( mController->getDuration() ) - tickOffset;
- const F32 tickStep = 0.5f;
- const S32 tickInterval = ( mIsController ) ? getWidth() : timeLineWidth;
- const S32 tickIntervalCount = ( S32 )mFloor( tickInterval / ( gUnitsPerSec * tickStep ) ) + 1;
- // Tick Render Proeprties.
- const Point2I tickExtent( 0, getHeight() - 1 );
- // Text Render Properties.
- const Point2I textExtent( gUnitsPerSec, mProfile->mFontSize );
- const Point2I textOffset( 4, -mProfile->mFontSize );
- // Render Border.
- GFX->getDrawUtil()->drawRectFill( RectI( offset + Point2I( tickOffset + 1, 1 ), Point2I( timeLineWidth - 1, getHeight() - 1 ) ), mProfile->mFillColorHL );
-
- // Font Color.
- GFX->getDrawUtil()->setBitmapModulation( mProfile->mFontColor );
- for ( S32 i = 0; i < tickIntervalCount; i++ )
- {
- // Tick Position.
- const Point2I tickPosition = offset + Point2I( tickOffset + i * ( gUnitsPerSec * tickStep ), 0 );
- // Line Color.
- const ColorI lineColor = ( ( i % 2 ) ) ? mProfile->mBorderColorHL : mProfile->mBorderColor;
- // Draw Line.
- GFX->getDrawUtil()->drawLine( tickPosition, tickPosition + tickExtent, lineColor );
- if ( mIsController )
- {
- // Render Times.
- renderJustifiedText( tickPosition + tickExtent + textOffset, textExtent, avar( "%.2f", ( F32 )( i * tickStep ) ) );
- }
- }
- // Render Children
- renderChildControls( offset, updateRect );
- if ( mSelection.Active )
- {
- // Selection Width.
- const S32 selectionWidth = mCeil( mAbs( toPoint( mSelection.EndTime ) - toPoint( mSelection.StartTime ) ) );
-
- // Selection Position.
- const S32 selectionPositionX = toPoint( getMin( mSelection.StartTime, mSelection.EndTime ) );
- // Selection Properties.
- const Point2I selectionExtent( selectionWidth, getHeight() );
- const Point2I selectionPosition = offset + Point2I( selectionPositionX, 0 );
- // Render Time Cue.
- GFX->getDrawUtil()->drawRectFill( RectI( selectionPosition, selectionExtent ), ColorI( 0, 0, 0, 128 ) );
- if ( mIsController )
- {
- // Buffer.
- char buffer[2][128];
- dSprintf( buffer[0], 128, "%.2f", ( F32 )( mSelection.StartTime / 1000.f ) );
- dSprintf( buffer[1], 128, "%.2f", ( F32 )( mSelection.EndTime / 1000.f ) );
- if ( mSelection.StartTime < mSelection.EndTime )
- {
- // Fetch Width.
- const S32 textWidth = mProfile->mFont->getStrWidth( buffer[0] );
- // Text Position.
- const Point2I startText = Point2I( getMax( ( S32 )( selectionPosition.x - ( textWidth + 2 ) ), updateRect.point.x + 4 ), selectionPosition.y + 2 );
- const Point2I endText = Point2I( getMin( ( S32 )( selectionPosition.x + selectionWidth + 4 ), updateRect.point.x + updateRect.extent.x - ( textWidth + 2 ) ), selectionPosition.y + 2 );
- // Render Time Text.
- renderJustifiedText( startText, textExtent, buffer[0] );
- renderJustifiedText( endText, textExtent, buffer[1] );
- }
- else
- {
- // Fetch Width.
- const S32 textWidth = mProfile->mFont->getStrWidth( buffer[1] );
- // Text Position.
- const Point2I startText = Point2I( getMax( ( S32 )( selectionPosition.x - ( textWidth + 2 ) ), updateRect.point.x + 4 ), selectionPosition.y + 2 );
- const Point2I endText = Point2I( getMin( ( S32 )( selectionPosition.x + selectionWidth + 4 ), updateRect.point.x + updateRect.extent.x - ( textWidth + 2 ) ), selectionPosition.y + 2 );
- // Render Time Text.
- renderJustifiedText( startText, textExtent, buffer[1] );
- renderJustifiedText( endText, textExtent, buffer[0] );
- }
- }
- }
- if ( mController && !mSelection.Active )
- {
- // Time Cue Properties.
- const Point2I timeCueExtent( ( mIsController ) ? 4 : 2, getHeight() );
- const Point2I timeCuePosition = offset + Point2I( toPoint( mController->getTime() ) - ( timeCueExtent.x / 2 ), 0 );
- // Render Time Cue.
- GFX->getDrawUtil()->drawRectFill( RectI( timeCuePosition, timeCueExtent ), ColorI( 0,0,0,128 ) );
- if ( mIsController )
- {
- // Buffer.
- char buffer[128];
- dSprintf( buffer, 128, "%.2f", ( F32 )( mController->getTime() / 1000.f ) );
- // Fetch Width.
- const S32 textWidth = mProfile->mFont->getStrWidth( buffer );
- // Text Position.
- const Point2I textPosition( getMin( getMax( timeCuePosition.x + 6, updateRect.point.x + 4 ), updateRect.point.x + updateRect.extent.x - ( textWidth + 2 ) ), timeCuePosition.y + 2 );
- // Render Time Text.
- renderJustifiedText( textPosition, textExtent, buffer );
- }
- }
- }
- //-----------------------------------------------------------------------------
- //
- // Console Methods.
- //
- //-----------------------------------------------------------------------------
- DefineEngineMethod( VTimeLineControl, toPoint, S32, (S32 time), (0), "( pTime )" )
- {
- return object->toPoint(time);
- }
- S32 VTimeLineControl::toTime( const S32 &pPoint )
- {
- return ( ( S32 )( 1000.f * ( F32 )pPoint / gUnitsPerSec ) - mDurationOffset );
- }
- DefineEngineMethod( VTimeLineControl, toTime, S32, (S32 point), (0), "( pPoint )" )
- {
- return object->toTime(point);
- }
- S32 VTimeLineControl::toPoint( const S32 &pTime )
- {
- return ( S32 )( gUnitsPerSec * ( ( F32 )( pTime + mDurationOffset ) / 1000.f ) );
- }
- DefineEngineMethod( VTimeLineControl, getSelection, const char *, (),, "( )" )
- {
- const S32 minTime = getMin( object->mSelection.StartTime, object->mSelection.EndTime );
- const S32 maxTime = getMax( object->mSelection.StartTime, object->mSelection.EndTime );
- // Fetch Return Buffer.
- char *retBuffer = Con::getReturnBuffer( 256 );
- // Write.
- dSprintf( retBuffer, 256, "%d %d %d", object->mSelection.Active, minTime, maxTime - minTime );
- // Return.
- return retBuffer;
- }
- DefineEngineMethod( VTimeLineControl, setSelection, void, (bool active, S32 time, S32 duration), (true, -1, 1), "( pActive, [pTime, pDuration] )" )
- {
- object->mSelection.Active = active;
- if (time != -1)
- {
- object->mSelection.StartTime = time;
- object->mSelection.EndTime = object->mSelection.StartTime + duration;
- }
- }
- DefineEngineMethod( VTimeLineControl, updateDuration, void, (),, "( )" )
- {
- object->updateDuration();
- }
- void VTimeLineControl::updateDuration( void )
- {
- if ( !mController )
- {
- // No Controller.
- return;
- }
- // Add 500ms.
- const S32 length = toPoint( mController->getDuration() + 500 );
- // Set Min Extent.
- setMinExtent( Point2I( length, getHeight() ) );
- if ( getWidth() < length )
- {
- // Conform to Min Extent.
- setExtent( length, getHeight() );
- }
- }
|