//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #include #include #include #include #include #include "vgui/IInput.h" // memdbgon must be the last include file in a .cpp file!!! #include using namespace vgui; DECLARE_BUILD_FACTORY( CChannelGraphPanel ); //----------------------------------------------------------------------------- // Purpose: Constructor //----------------------------------------------------------------------------- CChannelGraphPanel::CChannelGraphPanel( Panel *parent, const char *name ) : BaseClass( parent, name ), m_font( 0 ), m_graphMinTime( 0 ), m_graphMaxTime( 0 ), m_graphMinValue( 0.0f ), m_graphMaxValue( 0.0f ), m_nMouseStartX( -1 ), m_nMouseStartY( -1 ), m_nMouseLastX( -1 ), m_nMouseLastY( -1 ), m_nTextBorder( 2 ), m_nGraphOriginX( 40 ), m_nGraphOriginY( 10 ) { } void CChannelGraphPanel::SetChannel( CDmeChannel *pChannel ) { m_hChannel = pChannel; CDmeLog *pLog = m_hChannel->GetLog(); m_graphMinTime = pLog->GetBeginTime(); m_graphMaxTime = pLog->GetEndTime(); m_graphMinValue = FLT_MAX; m_graphMaxValue = -FLT_MAX; int nComponents = NumComponents( pLog->GetDataType() ); int nKeys = pLog->GetKeyCount(); for ( int k = 0; k < nKeys; ++k ) { DmeTime_t t = pLog->GetKeyTime( k ); for ( int i = 0; i < nComponents; ++i ) { float f = pLog->GetComponent( t, i ); m_graphMinValue = MIN( m_graphMinValue, f ); m_graphMaxValue = MAX( m_graphMaxValue, f ); } } } //----------------------------------------------------------------------------- // input methods //----------------------------------------------------------------------------- void CChannelGraphPanel::OnSizeChanged( int newWide, int newTall ) // called after the size of a panel has been changed { int wide = newWide - m_nGraphOriginX; int tall = newTall - m_nGraphOriginY; m_flTimeToPixel = wide / ( m_graphMaxTime - m_graphMinTime ).GetSeconds(); m_flValueToPixel = tall / ( m_graphMaxValue - m_graphMinValue ); } void CChannelGraphPanel::OnMousePressed( MouseCode code ) { BaseClass::OnMousePressed( code ); if ( code != MOUSE_LEFT ) return; vgui::input()->GetCursorPos( m_nMouseStartX, m_nMouseStartY ); ScreenToLocal( m_nMouseStartX, m_nMouseStartY ); m_nMouseLastX = m_nMouseStartX; m_nMouseLastY = m_nMouseStartY; input()->SetMouseCapture( GetVPanel() ); } void CChannelGraphPanel::OnMouseReleased( MouseCode code ) { BaseClass::OnMouseReleased( code ); if ( code != MOUSE_LEFT ) return; m_nMouseStartX = m_nMouseStartY = -1; m_nMouseLastX = m_nMouseLastY = -1; input()->SetMouseCapture( NULL ); } void CChannelGraphPanel::OnCursorMoved( int mx, int my ) { BaseClass::OnCursorMoved( mx, my ); if ( !vgui::input()->IsMouseDown( MOUSE_LEFT ) ) return; bool bInValueLegend = m_nMouseStartX < m_nGraphOriginX; bool bInTimeLegend = m_nMouseStartY > GetTall() - m_nGraphOriginY - 1; if ( bInTimeLegend && bInValueLegend ) { bInTimeLegend = bInValueLegend = false; } int dx = mx - m_nMouseLastX; int dy = my - m_nMouseLastY; if ( bInTimeLegend ) { if ( abs( dy ) > abs( dx ) ) { m_graphMinTime -= DmeTime_t( dy / m_flTimeToPixel ); m_graphMaxTime += DmeTime_t( dy / m_flTimeToPixel ); m_flTimeToPixel = ( GetWide() - m_nGraphOriginX ) / ( m_graphMaxTime - m_graphMinTime ).GetSeconds(); int x = mx = m_nMouseLastX; int y = my = m_nMouseLastY; LocalToScreen( x, y ); vgui::input()->SetCursorPos( x, y ); } else { m_graphMinTime -= DmeTime_t( dx / m_flTimeToPixel ); m_graphMaxTime -= DmeTime_t( dx / m_flTimeToPixel ); } } else if ( bInValueLegend ) { if ( abs( dx ) > abs( dy ) ) { m_graphMinValue += dx / m_flValueToPixel; m_graphMaxValue -= dx / m_flValueToPixel; m_flValueToPixel = ( GetTall() - m_nGraphOriginY ) / ( m_graphMaxValue - m_graphMinValue ); int x = mx = m_nMouseLastX; int y = my = m_nMouseLastY; LocalToScreen( x, y ); vgui::input()->SetCursorPos( x, y ); } else { m_graphMinValue += dy / m_flValueToPixel; m_graphMaxValue += dy / m_flValueToPixel; } } m_nMouseLastX = mx; m_nMouseLastY = my; } void CChannelGraphPanel::OnMouseWheeled( int delta ) { // TODO - zoom in around current time? } //----------------------------------------------------------------------------- // Purpose: lays out the graph //----------------------------------------------------------------------------- void CChannelGraphPanel::PerformLayout() { BaseClass::PerformLayout(); } float GetDisplayIncrement( int windowpixels, int fontpixels, float valuerange, int *pDecimalPlaces = NULL ) { float ratio = valuerange * fontpixels / ( windowpixels ); int nPower = ( int )ceil( log10( ratio ) ); if ( pDecimalPlaces ) { *pDecimalPlaces = MAX( 0, -nPower ); } return pow( 10.0f, nPower ); } int CChannelGraphPanel::TimeToPixel( DmeTime_t time ) { return m_nGraphOriginX + ( int )floor( m_flTimeToPixel * ( time - m_graphMinTime ).GetSeconds() + 0.5f ); } int CChannelGraphPanel::ValueToPixel( float flValue ) { return m_nGraphOriginY + ( int )floor( m_flValueToPixel * ( flValue - m_graphMinValue ) + 0.5f ); } //----------------------------------------------------------------------------- // Purpose: draws the graph //----------------------------------------------------------------------------- void CChannelGraphPanel::Paint() { // estimate the size of the graph marker text int wide = GetWide() - m_nGraphOriginX; int tall = GetTall() - m_nGraphOriginY; int textwidth = 40, textheight = 10; surface()->GetTextSize( m_font, L"999.999", textwidth, textheight ); // draw current time marker DmeTime_t curtime = m_hChannel->GetCurrentTime(); if ( curtime >= m_graphMinTime && curtime <= m_graphMaxTime ) { Color cyan( 0, 255, 255, 255 ); surface()->DrawSetColor( cyan ); int x = TimeToPixel( curtime ); surface()->DrawLine( x, 0, x, GetTall() - m_nGraphOriginY - 1 ); } // draw left/bottom graph border Color black( 0, 0, 0, 255 ); surface()->DrawSetColor( black ); surface()->DrawLine( m_nGraphOriginX, GetTall() - m_nGraphOriginY - 1, GetWide(), GetTall() - m_nGraphOriginY - 1 ); surface()->DrawLine( m_nGraphOriginX, GetTall() - m_nGraphOriginY - 1, m_nGraphOriginX, 0 ); surface()->DrawSetTextColor( black ); surface()->DrawSetTextFont( m_font ); // draw graph tickmarks and values along the left border int nDecimalPlaces = 0; float flValueIncrement = GetDisplayIncrement( tall, ( int )( 1.5f * textheight ), m_graphMaxValue - m_graphMinValue, &nDecimalPlaces ); int nMinValueIndex = ( int )ceil ( m_graphMinValue / flValueIncrement ); int nMaxValueIndex = ( int )floor( m_graphMaxValue / flValueIncrement ); float flValue = nMinValueIndex * flValueIncrement; for ( int i = nMinValueIndex; i <= nMaxValueIndex; ++i, flValue += flValueIncrement ) { wchar_t pFormat[ 32 ]; _snwprintf( pFormat, ARRAYSIZE( pFormat ), L"%%.%df", nDecimalPlaces ); wchar_t wstring[ 32 ]; _snwprintf( wstring, ARRAYSIZE( wstring ), pFormat, flValue ); int tw = 0, th = 0; surface()->GetTextSize( m_font, wstring, tw, th ); int y = GetTall() - ValueToPixel( flValue ) - 1; surface()->DrawSetTextPos( m_nGraphOriginX - m_nTextBorder - tw, y - textheight / 2 ); surface()->DrawPrintText( wstring, wcslen( wstring ) ); surface()->DrawLine( m_nGraphOriginX - m_nTextBorder, y, m_nGraphOriginX, y ); } // draw graph tickmarks and times along the bottom border float flTimeIncrement = GetDisplayIncrement( wide, textwidth, ( m_graphMaxTime - m_graphMinTime ).GetSeconds(), &nDecimalPlaces ); int nMinTimeIndex = ( int )ceil ( m_graphMinTime.GetSeconds() / flTimeIncrement ); int nMaxTimeIndex = ( int )floor( m_graphMaxTime.GetSeconds() / flTimeIncrement ); float flTime = nMinTimeIndex * flTimeIncrement; for ( int i = nMinTimeIndex; i <= nMaxTimeIndex; ++i, flTime += flTimeIncrement ) { wchar_t pFormat[ 32 ]; _snwprintf( pFormat, ARRAYSIZE( pFormat ), L"%%.%df", nDecimalPlaces ); wchar_t wstring[ 32 ]; _snwprintf( wstring, ARRAYSIZE( wstring ), pFormat, flTime ); int tw = 0, th = 0; surface()->GetTextSize( m_font, wstring, tw, th ); int x = TimeToPixel( DmeTime_t( flTime ) ); surface()->DrawSetTextPos( x - tw / 2, GetTall() - m_nGraphOriginY + m_nTextBorder - 1 ); surface()->DrawPrintText( wstring, wcslen( wstring ) ); surface()->DrawLine( x, GetTall() - m_nGraphOriginY + m_nTextBorder - 1, x, GetTall() - m_nGraphOriginY - 1 ); } static Color s_componentColors[] = { Color( 255, 0, 0, 255 ), Color( 0, 255, 0, 255 ), Color( 0, 0, 255, 255 ), Color( 0, 0, 0, 255 ), }; CDmeLog *pLog = m_hChannel->GetLog(); int nComponents = NumComponents( pLog->GetDataType() ); int nKeys = pLog->GetKeyCount(); // draw plotted graph for ( int i = 0; i < nComponents; ++i ) { Color &color = s_componentColors[ i % ARRAYSIZE( s_componentColors ) ]; surface()->DrawSetColor( color ); int lastx = -1; int lasty = -1; for ( int k = 0; k < nKeys; ++k ) { DmeTime_t t = pLog->GetKeyTime( k ); float f = pLog->GetComponent( t, i ); int x = TimeToPixel( t ); int y = GetTall() - ValueToPixel( f ) - 1; if ( k ) { surface()->DrawLine( lastx, lasty, x, y ); } surface()->DrawLine( x-1, y, x+1, y ); surface()->DrawLine( x, y-1, x, y+1 ); lastx = x; lasty = y; } } } //----------------------------------------------------------------------------- // Purpose: sets up colors //----------------------------------------------------------------------------- void CChannelGraphPanel::ApplySchemeSettings(IScheme *pScheme) { BaseClass::ApplySchemeSettings(pScheme); m_font = pScheme->GetFont( "DefaultVerySmall" ); surface()->GetTextSize( m_font, L"999.9", m_nGraphOriginX, m_nGraphOriginY ); m_nGraphOriginX += 2 * m_nTextBorder; m_nGraphOriginY += 2 * m_nTextBorder; SetFgColor(GetSchemeColor("CChannelGraphPanel.FgColor", pScheme)); SetBgColor(GetSchemeColor("CChannelGraphPanel.BgColor", pScheme)); SetBorder(pScheme->GetBorder("ButtonDepressedBorder")); } //----------------------------------------------------------------------------- // // CChannelGraphFrame methods // //----------------------------------------------------------------------------- CChannelGraphFrame::CChannelGraphFrame( Panel *parent, const char *pTitle ) : BaseClass( parent, "CChannelGraphFrame" ) { SetTitle( pTitle, true ); SetSizeable( true ); SetCloseButtonVisible( true ); SetMinimumSize( 200, 100 ); SetVisible( true ); SetSize( 400, 200 ); SetPos( 100, 100 ); m_pChannelGraph = new CChannelGraphPanel( this, "ChannelGraph" ); SetScheme( vgui::scheme()->LoadSchemeFromFile( "Resource/BoxRocket.res", "BoxRocket" ) ); } void CChannelGraphFrame::SetChannel( CDmeChannel *pChannel ) { m_pChannelGraph->SetChannel( pChannel ); } void CChannelGraphFrame::OnCommand( const char *cmd ) { BaseClass::OnCommand( cmd ); m_pChannelGraph->OnCommand( cmd ); } void CChannelGraphFrame::PerformLayout() { BaseClass::PerformLayout(); int border = 5; int iWidth, iHeight; GetSize( iWidth, iHeight ); m_pChannelGraph->SetPos( border, GetCaptionHeight() + border ); m_pChannelGraph->SetSize( iWidth - 2 * border, iHeight - GetCaptionHeight() - 2 * border ); }