//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #include "vgui_basebudgetpanel.h" #include "vgui_controls/Label.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" CBaseBudgetPanel::CBaseBudgetPanel( vgui::Panel *pParent, const char *pElementName ) : vgui::Panel( pParent, pElementName ) { m_BudgetHistoryOffset = 0; SetProportional( false ); SetKeyBoardInputEnabled( false ); SetMouseInputEnabled( false ); SetVisible( true ); m_pBudgetHistoryPanel = NULL; m_pBudgetBarGraphPanel = NULL; SetZPos( 1001 ); m_bDedicated = false; } CBaseBudgetPanel::~CBaseBudgetPanel() { } float CBaseBudgetPanel::GetBudgetGroupPercent( float value ) { if ( m_ConfigData.m_flBarGraphRange == 0.0f ) return 1.0f; return value / m_ConfigData.m_flBarGraphRange; } const double *CBaseBudgetPanel::GetBudgetGroupData( int &nGroups, int &nSamplesPerGroup, int &nSampleOffset ) const { nGroups = m_ConfigData.m_BudgetGroupInfo.Count(); nSamplesPerGroup = BUDGET_HISTORY_COUNT; nSampleOffset = m_BudgetHistoryOffset; if( m_BudgetGroupTimes.Count() == 0 ) { return NULL; } else { return &m_BudgetGroupTimes[0].m_Time[0]; } } void CBaseBudgetPanel::ClearTimesForAllGroupsForThisFrame( void ) { int i; for( i = 0; i < m_ConfigData.m_BudgetGroupInfo.Count(); i++ ) { m_BudgetGroupTimes[i].m_Time[m_BudgetHistoryOffset] = 0.0; } } void CBaseBudgetPanel::ClearAllTimesForGroup( int groupID ) { int i; for( i = 0; i < BUDGET_HISTORY_COUNT; i++ ) { m_BudgetGroupTimes[groupID].m_Time[i] = 0.0; } } void CBaseBudgetPanel::OnConfigDataChanged( const CBudgetPanelConfigData &data ) { int oldNumGroups = m_ConfigData.m_BudgetGroupInfo.Count(); // Copy in the config data and rebuild everything. Rebuild( data ); if ( m_ConfigData.m_BudgetGroupInfo.Count() > m_BudgetGroupTimes.Count() ) { m_BudgetGroupTimes.EnsureCount( m_ConfigData.m_BudgetGroupInfo.Count() ); for ( int i = oldNumGroups; i < m_ConfigData.m_BudgetGroupInfo.Count(); i++ ) { ClearAllTimesForGroup( i ); } } else { m_BudgetGroupTimes.SetSize( m_ConfigData.m_BudgetGroupInfo.Count() ); for ( int i = 0; i < m_BudgetGroupTimes.Count(); i++ ) { ClearAllTimesForGroup( i ); } } InvalidateLayout( false, true ); } void CBaseBudgetPanel::ResetAll() { m_ConfigData.m_BudgetGroupInfo.Purge(); for ( int i=0; i < m_GraphLabels.Count(); i++ ) m_GraphLabels[i]->MarkForDeletion(); m_GraphLabels.Purge(); for ( int i=0; i < m_TimeLabels.Count(); i++ ) m_TimeLabels[i]->MarkForDeletion(); m_TimeLabels.Purge(); } void CBaseBudgetPanel::Rebuild( const CBudgetPanelConfigData &data ) { int oldNumBudgetGroups = m_ConfigData.m_BudgetGroupInfo.Count(); int oldNumHistoryLabels = m_ConfigData.m_HistoryLabelValues.Count(); int oldNumTimeLabels = m_TimeLabels.Count(); // Copy the new config in. m_ConfigData = data; int nParentWidth, nParentHeight; GetParent()->GetSize( nParentWidth, nParentHeight ); if ( m_ConfigData.m_Width > nParentWidth ) { m_ConfigData.m_Width = nParentWidth; } if ( m_ConfigData.m_Height > nParentHeight ) { m_ConfigData.m_Height = nParentHeight; } if ( m_ConfigData.m_xCoord + m_ConfigData.m_Width > nParentWidth ) { m_ConfigData.m_xCoord = nParentWidth - m_ConfigData.m_Width; } if ( m_ConfigData.m_yCoord + m_ConfigData.m_Height > nParentHeight ) { m_ConfigData.m_yCoord = nParentHeight - m_ConfigData.m_Height; } // Recreate the history and bar graph panels. if( m_pBudgetHistoryPanel ) { m_pBudgetHistoryPanel->MarkForDeletion(); } m_pBudgetHistoryPanel = new CBudgetHistoryPanel( this, "FrametimeHistory" ); if( m_pBudgetBarGraphPanel ) { m_pBudgetBarGraphPanel->MarkForDeletion(); } m_pBudgetBarGraphPanel = new CBudgetBarGraphPanel( this, "BudgetBarGraph" ); // Create any new labels we need. int i; if ( m_ConfigData.m_BudgetGroupInfo.Count() > m_GraphLabels.Count() ) { m_GraphLabels.EnsureCount( m_ConfigData.m_BudgetGroupInfo.Count() ); for( i = oldNumBudgetGroups; i < m_ConfigData.m_BudgetGroupInfo.Count(); i++ ) { const char *pBudgetGroupName = m_ConfigData.m_BudgetGroupInfo[i].m_Name.String(); m_GraphLabels[i] = new vgui::Label( this, pBudgetGroupName, pBudgetGroupName ); } } else { while ( m_GraphLabels.Count() > m_ConfigData.m_BudgetGroupInfo.Count() ) { m_GraphLabels[m_GraphLabels.Count()-1]->MarkForDeletion(); m_GraphLabels.Remove( m_GraphLabels.Count()-1 ); } } Assert( m_GraphLabels.Count() == m_ConfigData.m_BudgetGroupInfo.Count() ); // Create new history labels. if ( m_ConfigData.m_HistoryLabelValues.Count() > m_HistoryLabels.Count() ) { m_HistoryLabels.EnsureCount( m_ConfigData.m_HistoryLabelValues.Count() ); for ( i=oldNumHistoryLabels; i < m_HistoryLabels.Count(); i++ ) { m_HistoryLabels[i] = new vgui::Label( this, "history label", "history label" ); } } else { while ( m_HistoryLabels.Count() > m_ConfigData.m_HistoryLabelValues.Count() ) { m_HistoryLabels[m_HistoryLabels.Count()-1]->MarkForDeletion(); m_HistoryLabels.Remove( m_HistoryLabels.Count()-1 ); } } SetHistoryLabelText(); // Note: the time lines still use milliseconds for the computations about where to draw them, // but each BudgetGroupDataType_t has its own scale. int nTimeLabels = m_ConfigData.m_flBarGraphRange + data.m_flTimeLabelInterval; if ( data.m_flTimeLabelInterval != 0.0f ) { nTimeLabels /= data.m_flTimeLabelInterval; } if ( nTimeLabels > m_TimeLabels.Count() ) { m_TimeLabels.EnsureCount( nTimeLabels ); for( i = oldNumTimeLabels; i < m_TimeLabels.Count(); i++ ) { char name[1024]; Q_snprintf( name, sizeof( name ), "time_label_%d", i ); m_TimeLabels[i] = new vgui::Label( this, name, "TEXT NOT SET YET" ); } } else { while ( m_TimeLabels.Count() > nTimeLabels ) { m_TimeLabels[m_TimeLabels.Count()-1]->MarkForDeletion(); m_TimeLabels.Remove( m_TimeLabels.Count()-1 ); } } SetTimeLabelText(); } void CBaseBudgetPanel::UpdateWindowGeometry() { if( m_ConfigData.m_Width > BUDGET_HISTORY_COUNT ) { m_ConfigData.m_Width = BUDGET_HISTORY_COUNT; } SetPos( m_ConfigData.m_xCoord, m_ConfigData.m_yCoord ); SetSize( m_ConfigData.m_Width, m_ConfigData.m_Height ); } void CBaseBudgetPanel::PerformLayout() { if ( !m_pBudgetHistoryPanel || !m_pBudgetBarGraphPanel ) return; int maxFPSLabelWidth = 0; int i; for( i = 0; i < m_HistoryLabels.Count(); i++ ) { int labelWidth, labelHeight; m_HistoryLabels[i]->GetContentSize( labelWidth, labelHeight ); if( labelWidth > maxFPSLabelWidth ) { maxFPSLabelWidth = labelWidth; } } m_pBudgetHistoryPanel->SetRange( 0, m_ConfigData.m_flHistoryRange ); float bottomOfHistoryPercentage = m_ConfigData.m_flBottomOfHistoryFraction; UpdateWindowGeometry(); int x, y, totalWidth, totalHeight; int totalHeightMinusTimeLabels; GetPos( x, y ); GetSize( totalWidth, totalHeight ); int maxTimeLabelHeight = 0; for( i = 0; i < m_TimeLabels.Count(); i++ ) { int labelWidth, labelHeight; m_TimeLabels[i]->GetContentSize( labelWidth, labelHeight ); maxTimeLabelHeight = MAX( maxTimeLabelHeight, labelHeight ); } totalHeightMinusTimeLabels = totalHeight - maxTimeLabelHeight; m_pBudgetHistoryPanel->SetPos( 0, 0 ); int budgetHistoryHeight = totalHeightMinusTimeLabels * bottomOfHistoryPercentage; m_pBudgetHistoryPanel->SetSize( totalWidth - maxFPSLabelWidth, budgetHistoryHeight ); int maxLabelWidth = 0; for( i = 0; i < m_GraphLabels.Count(); i++ ) { int width, height; m_GraphLabels[i]->GetContentSize( width, height ); if( maxLabelWidth < width ) { maxLabelWidth = width; } } m_pBudgetBarGraphPanel->SetPos( maxLabelWidth, totalHeightMinusTimeLabels * bottomOfHistoryPercentage ); m_pBudgetBarGraphPanel->SetSize( totalWidth - maxLabelWidth, totalHeightMinusTimeLabels * ( 1 - bottomOfHistoryPercentage ) ); for( i = 0; i < m_GraphLabels.Count(); i++ ) { m_GraphLabels[i]->SetPos( 0, ( bottomOfHistoryPercentage * totalHeightMinusTimeLabels ) + ( i * totalHeightMinusTimeLabels * ( 1 - bottomOfHistoryPercentage ) ) / m_ConfigData.m_BudgetGroupInfo.Count() ); // fudge height by 1 for rounding m_GraphLabels[i]->SetSize( maxLabelWidth, 1 + ( totalHeightMinusTimeLabels * ( 1 - bottomOfHistoryPercentage ) ) / m_ConfigData.m_BudgetGroupInfo.Count() ); m_GraphLabels[i]->SetContentAlignment( vgui::Label::a_east ); } // Note: the time lines still use milliseconds for the computations about where to draw them, // but each BudgetGroupDataType_t has its own scale. float fRange = m_ConfigData.m_flBarGraphRange; for( i = 0; i < m_TimeLabels.Count(); i++ ) { int labelWidth, labelHeight; m_TimeLabels[i]->GetContentSize( labelWidth, labelHeight ); int x = maxLabelWidth + ( i * m_ConfigData.m_flTimeLabelInterval ) / fRange * ( totalWidth - maxLabelWidth ); m_TimeLabels[i]->SetPos( x - ( labelWidth * 0.5 ), totalHeight - labelHeight ); m_TimeLabels[i]->SetSize( labelWidth, labelHeight ); m_TimeLabels[i]->SetContentAlignment( vgui::Label::a_east ); } // position the fps labels fRange = m_ConfigData.m_flHistoryRange; for( i = 0; i < m_HistoryLabels.Count(); i++ ) { int labelWidth, labelHeight; m_HistoryLabels[i]->GetContentSize( labelWidth, labelHeight ); float y = (fRange != 0) ? budgetHistoryHeight * m_ConfigData.m_HistoryLabelValues[i] / ( float )fRange : 0.0f; int top = ( int )( budgetHistoryHeight - y - 1 - labelHeight * 0.5f ); m_HistoryLabels[i]->SetPos( totalWidth - maxFPSLabelWidth, top ); m_HistoryLabels[i]->SetSize( labelWidth, labelHeight ); m_HistoryLabels[i]->SetContentAlignment( vgui::Label::a_east ); } } void CBaseBudgetPanel::ApplySchemeSettings( vgui::IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme ); int i; for( i = 0; i < m_ConfigData.m_BudgetGroupInfo.Count(); i++ ) { m_GraphLabels[i]->SetFgColor( m_ConfigData.m_BudgetGroupInfo[i].m_Color ); m_GraphLabels[i]->SetBgColor( Color( 0, 0, 0, 255 ) ); m_GraphLabels[i]->SetPaintBackgroundEnabled( false ); m_GraphLabels[i]->SetFont( pScheme->GetFont( "BudgetLabel", IsProportional() ) ); if ( m_bDedicated ) { m_GraphLabels[i]->SetBgColor( pScheme->GetColor( "ControlBG", Color( 0, 0, 0, 255 ) ) ); } } for( i = 0; i < m_TimeLabels.Count(); i++ ) { int red, green, blue, alpha; red = green = blue = alpha = 255; m_TimeLabels[i]->SetFgColor( Color( red, green, blue, alpha ) ); m_TimeLabels[i]->SetBgColor( Color( 0, 0, 0, 255 ) ); m_TimeLabels[i]->SetPaintBackgroundEnabled( false ); m_TimeLabels[i]->SetFont( pScheme->GetFont( "BudgetLabel", IsProportional() ) ); if ( m_bDedicated ) { m_TimeLabels[i]->SetBgColor( pScheme->GetColor( "ControlBG", Color( 0, 0, 0, 255 ) ) ); } } for( i = 0; i < m_HistoryLabels.Count(); i++ ) { int red, green, blue, alpha; red = green = blue = alpha = 255; m_HistoryLabels[i]->SetFgColor( Color( red, green, blue, alpha ) ); m_HistoryLabels[i]->SetBgColor( Color( 0, 0, 0, 255 ) ); m_HistoryLabels[i]->SetPaintBackgroundEnabled( false ); m_HistoryLabels[i]->SetFont( pScheme->GetFont( "BudgetLabel", IsProportional() ) ); if ( m_bDedicated ) { m_HistoryLabels[i]->SetBgColor( pScheme->GetColor( "ControlBG", Color( 0, 0, 0, 255 ) ) ); } } m_hFont = pScheme->GetFont( "DefaultFixed" ); if ( m_bDedicated ) { SetBgColor( pScheme->GetColor( "ControlBG", Color( 0, 0, 0, 255 ) ) ); } SetPaintBackgroundEnabled( true ); } void CBaseBudgetPanel::PaintBackground() { if ( m_bDedicated ) { m_pBudgetBarGraphPanel->SetBgColor( GetBgColor() ); } else { SetBgColor( Color( 0, 0, 0, m_ConfigData.m_flBackgroundAlpha ) ); } BaseClass::PaintBackground(); } void CBaseBudgetPanel::Paint() { m_pBudgetHistoryPanel->SetData( &m_BudgetGroupTimes[0].m_Time[0], GetNumCachedBudgetGroups(), BUDGET_HISTORY_COUNT, m_BudgetHistoryOffset ); BaseClass::Paint(); } void CBaseBudgetPanel::MarkForFullRepaint() { Repaint(); m_pBudgetHistoryPanel->Repaint(); m_pBudgetBarGraphPanel->Repaint(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBaseBudgetPanel::GetGraphLabelScreenSpaceTopAndBottom( int id, int &top, int &bottom ) { int x = 0; int y = 0; m_GraphLabels[id]->LocalToScreen( x, y ); top = y; bottom = top + m_GraphLabels[id]->GetTall(); }