//===== Copyright © 1996-2011, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ //===========================================================================// #include #include "vgui/ILocalize.h" #include "vgui_controls/footerpanel.h" #include "vgui_controls/Frame.h" #include "vgui/ISurface.h" #include "vgui_controls/Label.h" #include "vgui_controls/ControllerMap.h" #if defined( _X360 ) #include "xbox/xbox_launch.h" #else #include "xbox/xboxstubs.h" #endif #undef MessageBox // Windows helpfully #define's this to MessageBoxA, we're using vgui::MessageBox // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" using namespace vgui; CFooterPanel::CFooterPanel( Panel *parent, const char *panelName ) : BaseClass( parent, panelName ) { SetVisible( true ); SetAlpha( 0 ); m_pHelpName = NULL; m_pSizingLabel = new vgui::Label( this, "SizingLabel", "" ); m_pSizingLabel->SetVisible( false ); m_nButtonGap = 32; m_nButtonGapDefault = 32; m_ButtonPinRight = 100; m_FooterTall = 80; int wide, tall; surface()->GetScreenSize(wide, tall); if ( tall <= 480 ) { m_FooterTall = 60; } m_ButtonOffsetFromTop = 0; m_ButtonSeparator = 4; m_TextAdjust = 0; m_bPaintBackground = false; m_bCenterHorizontal = false; m_szButtonFont[0] = '\0'; m_szTextFont[0] = '\0'; m_szFGColor[0] = '\0'; m_szBGColor[0] = '\0'; } CFooterPanel::~CFooterPanel() { SetHelpNameAndReset( NULL ); delete m_pSizingLabel; } //----------------------------------------------------------------------------- // Purpose: apply scheme settings //----------------------------------------------------------------------------- void CFooterPanel::ApplySchemeSettings( vgui::IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme ); // $FIXME(hpe) quick hack for PC fonts if ( IsPC() ) { m_hButtonFont = pScheme->GetFont( ( m_szButtonFont[0] != '\0' ) ? m_szButtonFont : "Default" ); m_hTextFont = pScheme->GetFont( ( m_szTextFont[0] != '\0' ) ? m_szTextFont : "Default" ); } else { m_hButtonFont = pScheme->GetFont( ( m_szButtonFont[0] != '\0' ) ? m_szButtonFont : "GameUIButtons" ); m_hTextFont = pScheme->GetFont( ( m_szTextFont[0] != '\0' ) ? m_szTextFont : "X360_Title_1" ); } SetFgColor( pScheme->GetColor( m_szFGColor, Color( 255, 255, 255, 255 ) ) ); SetBgColor( pScheme->GetColor( m_szBGColor, Color( 0, 0, 0, 255 ) ) ); int x, y, w, h; GetParent()->GetBounds( x, y, w, h ); SetBounds( x, h - m_FooterTall, w, m_FooterTall ); } //----------------------------------------------------------------------------- // Purpose: apply settings //----------------------------------------------------------------------------- void CFooterPanel::ApplySettings( KeyValues *inResourceData ) { BaseClass::ApplySettings( inResourceData ); // gap between hints m_nButtonGap = inResourceData->GetInt( "buttongap", 32 ); m_nButtonGapDefault = m_nButtonGap; m_ButtonPinRight = inResourceData->GetInt( "button_pin_right", 100 ); m_FooterTall = inResourceData->GetInt( "tall", 80 ); m_ButtonOffsetFromTop = inResourceData->GetInt( "buttonoffsety", 0 ); m_ButtonSeparator = inResourceData->GetInt( "button_separator", 4 ); m_TextAdjust = inResourceData->GetInt( "textadjust", 0 ); m_bCenterHorizontal = ( inResourceData->GetInt( "center", 0 ) == 1 ); m_bPaintBackground = ( inResourceData->GetInt( "paintbackground", 0 ) == 1 ); // fonts for text and button Q_strncpy( m_szTextFont, inResourceData->GetString( "fonttext", "MenuLarge" ), sizeof( m_szTextFont ) ); Q_strncpy( m_szButtonFont, inResourceData->GetString( "fontbutton", "GameUIButtons" ), sizeof( m_szButtonFont ) ); // fg and bg colors Q_strncpy( m_szFGColor, inResourceData->GetString( "fgcolor", "White" ), sizeof( m_szFGColor ) ); Q_strncpy( m_szBGColor, inResourceData->GetString( "bgcolor", "Black" ), sizeof( m_szBGColor ) ); for ( KeyValues *pButton = inResourceData->GetFirstSubKey(); pButton != NULL; pButton = pButton->GetNextKey() ) { const char *pName = pButton->GetName(); if ( !Q_stricmp( pName, "button" ) ) { // Add a button to the footer const char *pText = pButton->GetString( "text", "NULL" ); const char *pIcon = pButton->GetString( "icon", "NULL" ); AddNewButtonLabel( pText, pIcon ); } } InvalidateLayout( false, true ); // force ApplySchemeSettings to run } //----------------------------------------------------------------------------- // Purpose: adds button icons and help text to the footer panel when activating a menu //----------------------------------------------------------------------------- void CFooterPanel::AddButtonsFromMap( vgui::Frame *pMenu ) { SetHelpNameAndReset( pMenu->GetName() ); CControllerMap *pMap = dynamic_cast( pMenu->FindChildByName( "ControllerMap" ) ); if ( pMap ) { int buttonCt = pMap->NumButtons(); for ( int i = 0; i < buttonCt; ++i ) { const char *pText = pMap->GetBindingText( i ); if ( pText ) { AddNewButtonLabel( pText, pMap->GetBindingIcon( i ) ); } } } } void CFooterPanel::SetStandardDialogButtons() { SetHelpNameAndReset( "Dialog" ); //============================================================================= // HPE_BEGIN: // [tj] Changed "Action" to "Select" //============================================================================= AddNewButtonLabel( "#GameUI_Select", "#GameUI_Icons_A_BUTTON" ); //============================================================================= // HPE_END //============================================================================= AddNewButtonLabel( "#GameUI_Back", "#GameUI_Icons_B_BUTTON" ); } //----------------------------------------------------------------------------- // Purpose: Caller must tag the button layout. May support reserved names // to provide stock help layouts trivially. //----------------------------------------------------------------------------- void CFooterPanel::SetHelpNameAndReset( const char *pName ) { if ( m_pHelpName ) { free( m_pHelpName ); m_pHelpName = NULL; } if ( pName ) { m_pHelpName = strdup( pName ); } ClearButtons(); } //----------------------------------------------------------------------------- // Purpose: Caller must tag the button layout //----------------------------------------------------------------------------- const char *CFooterPanel::GetHelpName() { return m_pHelpName; } void CFooterPanel::ClearButtons( void ) { m_ButtonLabels.PurgeAndDeleteElements(); } //============================================================================= // HPE_BEGIN: // [smessick] //============================================================================= //----------------------------------------------------------------------------- // Purpose: Sets the pin right location with adjustments based on the current // screen width and height. The given pixel offset is assumed to be based on // a 640x480 screen. //----------------------------------------------------------------------------- void CFooterPanel::SetButtonPinRightProportional( int nButtonPinRight ) { int screenWide, screenTall; surface()->GetScreenSize(screenWide, screenTall); float tallDiff = screenTall / 480.0f; m_ButtonPinRight = ( ( screenWide - ( 640 * tallDiff ) ) * 0.5f ) + ( nButtonPinRight * tallDiff ); } //----------------------------------------------------------------------------- // Purpose: Set the y offset from the top of the screen. // The given pixel offset is assumed to be based on a 640x480 screen. //----------------------------------------------------------------------------- void CFooterPanel::SetButtonOffsetFromTopProportional( int yOffset ) { int screenWide, screenTall; surface()->GetScreenSize(screenWide, screenTall); m_ButtonOffsetFromTop = yOffset * screenTall / 480.0f; } //============================================================================= // HPE_END //============================================================================= //----------------------------------------------------------------------------- // Purpose: creates a new button label with icon and text //----------------------------------------------------------------------------- void CFooterPanel::AddNewButtonLabel( const char *text, const char *icon ) { ButtonLabel_t *button = new ButtonLabel_t; Q_strncpy( button->name, text, MAX_PATH ); button->bVisible = true; // Button icons are a single character wchar_t *pIcon = g_pVGuiLocalize->Find( icon ); if ( pIcon ) { button->icon[0] = pIcon[0]; button->icon[1] = '\0'; } else { button->icon[0] = '\0'; } // Set the help text wchar_t *pText = g_pVGuiLocalize->Find( text ); if ( pText ) { wcsncpy( button->text, pText, wcslen( pText ) + 1 ); } else { button->text[0] = '\0'; } m_ButtonLabels.AddToTail( button ); } //----------------------------------------------------------------------------- // Purpose: Shows/Hides a button label //----------------------------------------------------------------------------- void CFooterPanel::ShowButtonLabel( const char *name, bool show ) { for ( int i = 0; i < m_ButtonLabels.Count(); ++i ) { if ( !Q_stricmp( m_ButtonLabels[ i ]->name, name ) ) { m_ButtonLabels[ i ]->bVisible = show; break; } } } //----------------------------------------------------------------------------- // Purpose: Changes a button's text //----------------------------------------------------------------------------- void CFooterPanel::SetButtonText( const char *buttonName, const char *text ) { for ( int i = 0; i < m_ButtonLabels.Count(); ++i ) { if ( !Q_stricmp( m_ButtonLabels[ i ]->name, buttonName ) ) { wchar_t *wtext = g_pVGuiLocalize->Find( text ); if ( text ) { wcsncpy( m_ButtonLabels[ i ]->text, wtext, wcslen( wtext ) + 1 ); } else { m_ButtonLabels[ i ]->text[ 0 ] = '\0'; } break; } } } //----------------------------------------------------------------------------- // Purpose: Footer panel background rendering //----------------------------------------------------------------------------- void CFooterPanel::PaintBackground( void ) { if ( !m_bPaintBackground ) return; BaseClass::PaintBackground(); } //----------------------------------------------------------------------------- // Purpose: Footer panel rendering //----------------------------------------------------------------------------- void CFooterPanel::Paint( void ) { //============================================================================= // HPE_BEGIN: // [smessick] Don't draw if alpha'd out. //============================================================================= if ( GetAlpha() == 0 ) { return; } //============================================================================= // HPE_END //============================================================================= // inset from right edge int wide = GetWide(); int right = wide - m_ButtonPinRight; // center the text within the button int buttonHeight = vgui::surface()->GetFontTall( m_hButtonFont ); int fontHeight = vgui::surface()->GetFontTall( m_hTextFont ); int textY = ( buttonHeight - fontHeight )/2 + m_TextAdjust; if ( textY < 0 ) { textY = 0; } int y = m_ButtonOffsetFromTop; if ( !m_bCenterHorizontal ) { // draw the buttons, right to left int x = right; for ( int i = 0; i < m_ButtonLabels.Count(); ++i ) { ButtonLabel_t *pButton = m_ButtonLabels[i]; if ( !pButton->bVisible ) continue; // Get the string length m_pSizingLabel->SetFont( m_hTextFont ); m_pSizingLabel->SetText( pButton->text ); m_pSizingLabel->SizeToContents(); int iTextWidth = m_pSizingLabel->GetWide(); if ( iTextWidth == 0 ) x += m_nButtonGap; // There's no text, so remove the gap between buttons else x -= iTextWidth; // Draw the string vgui::surface()->DrawSetTextFont( m_hTextFont ); vgui::surface()->DrawSetTextColor( GetFgColor() ); vgui::surface()->DrawSetTextPos( x, y + textY ); vgui::surface()->DrawPrintText( pButton->text, wcslen( pButton->text ) ); // Draw the button // back up button width and a little extra to leave a gap between button and text x -= ( vgui::surface()->GetCharacterWidth( m_hButtonFont, pButton->icon[0] ) + m_ButtonSeparator ); vgui::surface()->DrawSetTextFont( m_hButtonFont ); vgui::surface()->DrawSetTextColor( 255, 255, 255, 255 ); vgui::surface()->DrawSetTextPos( x, y ); vgui::surface()->DrawPrintText( pButton->icon, 1 ); // back up to next string x -= m_nButtonGap; } } else { // center the buttons (as a group) int x = wide / 2; int totalWidth = 0; int i = 0; int nButtonCount = 0; // need to loop through and figure out how wide our buttons and text are (with gaps between) so we can offset from the center for ( i = 0; i < m_ButtonLabels.Count(); ++i ) { ButtonLabel_t *pButton = m_ButtonLabels[i]; if ( !pButton->bVisible ) continue; // Get the string length m_pSizingLabel->SetFont( m_hTextFont ); m_pSizingLabel->SetText( pButton->text ); m_pSizingLabel->SizeToContents(); totalWidth += vgui::surface()->GetCharacterWidth( m_hButtonFont, pButton->icon[0] ); totalWidth += m_ButtonSeparator; totalWidth += m_pSizingLabel->GetWide(); nButtonCount++; // keep track of how many active buttons we'll be drawing } totalWidth += ( nButtonCount - 1 ) * m_nButtonGap; // add in the gaps between the buttons x -= ( totalWidth / 2 ); for ( i = 0; i < m_ButtonLabels.Count(); ++i ) { ButtonLabel_t *pButton = m_ButtonLabels[i]; if ( !pButton->bVisible ) continue; // Get the string length m_pSizingLabel->SetFont( m_hTextFont ); m_pSizingLabel->SetText( pButton->text ); m_pSizingLabel->SizeToContents(); int iTextWidth = m_pSizingLabel->GetWide(); // Draw the icon vgui::surface()->DrawSetTextFont( m_hButtonFont ); vgui::surface()->DrawSetTextColor( 255, 255, 255, 255 ); vgui::surface()->DrawSetTextPos( x, y ); vgui::surface()->DrawPrintText( pButton->icon, 1 ); x += vgui::surface()->GetCharacterWidth( m_hButtonFont, pButton->icon[0] ) + m_ButtonSeparator; // Draw the string vgui::surface()->DrawSetTextFont( m_hTextFont ); vgui::surface()->DrawSetTextColor( GetFgColor() ); vgui::surface()->DrawSetTextPos( x, y + textY ); vgui::surface()->DrawPrintText( pButton->text, wcslen( pButton->text ) ); x += iTextWidth + m_nButtonGap; } } } DECLARE_BUILD_FACTORY( CFooterPanel );