//========= Copyright Valve Corporation, All rights reserved. ============// // //=======================================================================================// #include "cbase.h" #include "game_controls/slideshowpanel.h" #include "vgui/IVGui.h" #include "filesystem.h" //----------------------------------------------------------------------------- using namespace vgui; //----------------------------------------------------------------------------- DECLARE_BUILD_FACTORY( CCrossfadableImagePanel ); DECLARE_BUILD_FACTORY( CSlideshowPanel ); //----------------------------------------------------------------------------- CCrossfadableImagePanel::CCrossfadableImagePanel( Panel* pParent, const char *pName ) : EditablePanel( pParent, pName ), m_iSrcImg( 0 ), m_flBlend( 0.0f ), m_flBlendTime( 0.0f ), m_flStartBlendTime( 0.0f ), m_bBlending( false ) { m_pImages[ 0 ] = new ImagePanel( this, "Image0" ); m_pImages[ 1 ] = new ImagePanel( this, "Image1" ); ivgui()->AddTickSignal( GetVPanel(), 10 ); } CCrossfadableImagePanel::~CCrossfadableImagePanel() { ivgui()->RemoveTickSignal( GetVPanel() ); } void CCrossfadableImagePanel::ApplySettings( KeyValues *pInResourceData ) { BaseClass::ApplySettings( pInResourceData ); } void CCrossfadableImagePanel::ApplySchemeSettings( IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme ); SrcImg()->SetTileImage( false ); DstImg()->SetTileImage( false ); } void CCrossfadableImagePanel::PerformLayout() { BaseClass::PerformLayout(); for ( int i = 0; i < 2; ++i ) { m_pImages[ i ]->SetBounds( 0, 0, GetWide(), GetTall() ); m_pImages[ i ]->SetVisible( true ); } } // Helper macro to perform a call on both images #define CALL_FUNC_ON_BOTH_IMAGES( _call ) \ AssertMsg( m_pImages[ 0 ], "m_pImages[ 0 ] is NULL!" ); \ AssertMsg( m_pImages[ 1 ], "m_pImages[ 1 ] is NULL!" ); \ m_pImages[0]->_call; \ m_pImages[1]->_call; void CCrossfadableImagePanel::SetShouldScaleImage( bool bState ) { CALL_FUNC_ON_BOTH_IMAGES( SetShouldScaleImage( bState ) ); } void CCrossfadableImagePanel::SetScaleAmount( float flScale ) { CALL_FUNC_ON_BOTH_IMAGES( SetScaleAmount( flScale ) ); } void CCrossfadableImagePanel::SetFillColor( Color c ) { CALL_FUNC_ON_BOTH_IMAGES( SetFillColor( c ) ); } void CCrossfadableImagePanel::SetDrawColor( Color clrDrawColor ) { CALL_FUNC_ON_BOTH_IMAGES( SetDrawColor( clrDrawColor ) ); } void CCrossfadableImagePanel::InstallMouseHandler( Panel *pHandler ) { CALL_FUNC_ON_BOTH_IMAGES( InstallMouseHandler( pHandler ) ); } IImage *CCrossfadableImagePanel::GetImage() { return SrcImg()->GetImage(); } const char *CCrossfadableImagePanel::GetImageName() { return SrcImg()->GetImageName(); } float CCrossfadableImagePanel::GetScaleAmount() { return SrcImg()->GetScaleAmount(); } bool CCrossfadableImagePanel::GetShouldScaleImage() { return SrcImg()->GetShouldScaleImage(); } Color CCrossfadableImagePanel::GetFillColor() { return SrcImg()->GetFillColor(); } Color CCrossfadableImagePanel::GetDrawColor() { return SrcImg()->GetDrawColor(); } void CCrossfadableImagePanel::SetImage( IImage *pImage, float flBlendTime/*=0.0f*/ ) { DstImg()->SetImage( pImage ); SetupImageBlend( flBlendTime ); } void CCrossfadableImagePanel::SetImage( const char *pImageName, float flBlendTime/*=0.0f*/ ) { DstImg()->SetImage( pImageName ); SetupImageBlend( flBlendTime ); } void CCrossfadableImagePanel::SetupImageBlend( float flBlendTime ) { m_bBlending = true; m_flBlendTime = flBlendTime; m_flStartBlendTime = gpGlobals->realtime; m_flBlend = 0.0f; } void CCrossfadableImagePanel::OnSizeChanged( int nWide, int nTall ) { m_pImages[ 0 ]->SetSize( nWide, nTall ); m_pImages[ 1 ]->SetSize( nWide, nTall ); } void CCrossfadableImagePanel::OnTick() { if ( m_bBlending ) { // Compute current blend value if ( m_flBlendTime == 0.0f ) { m_flBlend = 1.0f; } else { float t = clamp( ( gpGlobals->realtime - m_flStartBlendTime ) / m_flBlendTime, 0.0f, 1.0f ); m_flBlend = clamp( t * t * (3 - 2*t), 0.0f, 1.0f ); // S-curve } // Set alpha channel on source image Color clrDraw; clrDraw = SrcImg()->GetDrawColor(); clrDraw[ 3 ] = ( int )( 255 * ( 1 - m_flBlend ) ); SrcImg()->SetDrawColor( clrDraw ); // Set alpha channel on destination image clrDraw = DstImg()->GetDrawColor(); clrDraw[ 3 ] = ( int )( 255 * m_flBlend ); DstImg()->SetDrawColor( clrDraw ); // If we're done, don't blend next think if ( m_flBlend >= 1.0f ) { m_bBlending = false; m_iSrcImg = !m_iSrcImg; m_flBlend = 0.0f; } } } //----------------------------------------------------------------------------- CSlideshowPanel::CSlideshowPanel( Panel *pParent, const char *pName ) : EditablePanel( pParent, pName ), m_iCurImg( 0 ), m_flInterval( 3.0f ), m_flTransitionLength( 0.5f ) { m_pImagePanel = new CCrossfadableImagePanel( this, "CrossfadableImage" ); // Setup the first transition time UpdateNextTransitionTime(); // Add tick signal ivgui()->AddTickSignal( GetVPanel(), 10 ); } CSlideshowPanel::~CSlideshowPanel() { // Remove tick signal ivgui()->RemoveTickSignal( GetVPanel() ); } void CSlideshowPanel::SetInterval( float flInterval ) { m_flInterval = flInterval; UpdateNextTransitionTime(); } void CSlideshowPanel::SetTransitionTime( float flTransitionLength ) { m_flTransitionLength = flTransitionLength; UpdateNextTransitionTime(); } void CSlideshowPanel::UpdateNextTransitionTime() { m_flNextTransitionTime = gpGlobals->realtime + m_flInterval; } void CSlideshowPanel::AddImage( const char *pImageName ) { if ( pImageName && strlen( pImageName ) > 0 ) { AddImage( scheme()->GetImage( pImageName, m_pImagePanel->GetShouldScaleImage() ) ); } } void CSlideshowPanel::AddImage( IImage *pImage ) { // Cache a pointer to the image m_vecImages.AddToTail( pImage ); if ( m_vecImages.Count() == 1 ) { GetImagePanel()->SetImage( pImage ); } } void CSlideshowPanel::FillWithImages( const char *pBasePath ) { int i = 0; while ( 1 ) { CFmtStr fmtImagePath( "materials/vgui/%s%i.vmt", pBasePath, i ); V_FixDoubleSlashes( fmtImagePath.Access() ); if ( !g_pFullFileSystem->FileExists( fmtImagePath.Access() ) ) break; fmtImagePath.sprintf( "%s%i.vmt", pBasePath, i ); AddImage( fmtImagePath.Access() ); ++i; } } void CSlideshowPanel::ApplySettings( KeyValues *pInResourceData ) { BaseClass::ApplySettings( pInResourceData ); int iDefaultImage = pInResourceData->GetInt( "default_index", 0 ); int i = 0; while ( 1 ) { CFmtStr fmtImageKeyName( "image_%i", i ); const char *pImagePath = pInResourceData->GetString( fmtImageKeyName.Access(), NULL ); if ( !pImagePath ) break; AddImage( pImagePath ); if ( iDefaultImage == i ) { GetImagePanel()->SetImage( pImagePath ); } ++i; } GetImagePanel()->SetSize( XRES( pInResourceData->GetInt( "wide" ) ), YRES( pInResourceData->GetInt( "tall" ) ) ); GetImagePanel()->SetShouldScaleImage( pInResourceData->GetBool( "scaleImage" ) ); GetImagePanel()->SetScaleAmount( pInResourceData->GetFloat( "scaleAmount" ) ); } void CSlideshowPanel::OnSizeChanged( int nWide, int nTall ) { GetImagePanel()->SetSize( nWide, nTall ); } void CSlideshowPanel::OnTick() { if ( GetImageCount() > 1 && gpGlobals->realtime >= m_flNextTransitionTime ) { // Iterate to next image m_iCurImg = ( m_iCurImg + 1 ) % GetImageCount(); // Setup new image GetImagePanel()->SetImage( m_vecImages[ m_iCurImg ], m_flTransitionLength ); // Set transition time to be the end of the blend m_flNextTransitionTime = gpGlobals->realtime + m_flInterval; } }