#include "global.h" #if !defined(WITHOUT_NETWORKING) #include "ScreenNetSelectBase.h" #include "ScreenManager.h" #include "ThemeManager.h" #include "RageTimer.h" #include "ActorUtil.h" #include "Actor.h" #include "GameSoundManager.h" #include "MenuTimer.h" #include "NetworkSyncManager.h" #include "RageUtil.h" #include "GameState.h" #include "InputEventPlus.h" #include "RageInput.h" #include "Font.h" #include "RageDisplay.h" #define CHATINPUT_WIDTH THEME->GetMetricF(m_sName,"ChatInputBoxWidth") #define CHATINPUT_HEIGHT THEME->GetMetricF(m_sName,"ChatInputBoxHeight") #define CHATOUTPUT_WIDTH THEME->GetMetricF(m_sName,"ChatOutputBoxWidth") #define CHATOUTPUT_HEIGHT THEME->GetMetricF(m_sName,"ChatOutputBoxHeight") #define SHOW_CHAT_LINES THEME->GetMetricI(m_sName,"ChatOutputLines") #define CHAT_TEXT_OUTPUT_WIDTH THEME->GetMetricF(m_sName,"ChatTextOutputWidth") #define CHAT_TEXT_INPUT_WIDTH THEME->GetMetricF(m_sName,"ChatTextInputWidth") #define USERSALT_Y THEME->GetMetricF(m_sName,"UsersAY") #define USERSDELT_X THEME->GetMetricF(m_sName,"UsersDX") #define USERS_Y THEME->GetMetricF(m_sName,"UsersY") #define USERS_X THEME->GetMetricF(m_sName,"UsersX") AutoScreenMessage( SM_AddToChat ) AutoScreenMessage( SM_UsersUpdate ) AutoScreenMessage( SM_SMOnlinePack ) REGISTER_SCREEN_CLASS( ScreenNetSelectBase ); void ScreenNetSelectBase::Init() { ScreenWithMenuElements::Init(); //ChatBox m_sprChatInputBox.SetName( "ChatInputBox" ); m_sprChatInputBox.Load( THEME->GetPathG( m_sName, "ChatInputBox" ) ); m_sprChatInputBox.SetWidth( CHATINPUT_WIDTH ); m_sprChatInputBox.SetHeight( CHATINPUT_HEIGHT ); LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND( m_sprChatInputBox ); this->AddChild( &m_sprChatInputBox ); m_sprChatOutputBox.SetName( "ChatOutputBox" ); m_sprChatOutputBox.Load( THEME->GetPathG( m_sName, "ChatOutputBox" ) ); m_sprChatOutputBox.SetWidth( CHATOUTPUT_WIDTH ); m_sprChatOutputBox.SetHeight( CHATOUTPUT_HEIGHT ); LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND( m_sprChatOutputBox ); this->AddChild( &m_sprChatOutputBox ); m_textChatInput.LoadFromFont( THEME->GetPathF(m_sName,"chat") ); m_textChatInput.SetHorizAlign( align_left ); m_textChatInput.SetVertAlign( align_top ); m_textChatInput.SetShadowLength( 0 ); m_textChatInput.SetName( "ChatInput" ); m_textChatInput.SetWrapWidthPixels( (int)(CHAT_TEXT_INPUT_WIDTH) ); LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND( m_textChatInput ); this->AddChild( &m_textChatInput ); m_textChatOutput.LoadFromFont( THEME->GetPathF(m_sName,"chat") ); m_textChatOutput.SetWrapWidthPixels( (int)(CHAT_TEXT_OUTPUT_WIDTH) ); m_textChatOutput.SetHorizAlign( align_left ); m_textChatOutput.SetVertAlign( align_bottom ); m_textChatOutput.SetShadowLength( 0 ); m_textChatOutput.SetName( "ChatOutput" ); LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND( m_textChatOutput ); this->AddChild( &m_textChatOutput ); m_textChatOutput.SetText( NSMAN->m_sChatText ); m_textChatOutput.SetMaxLines( SHOW_CHAT_LINES, 1 ); //Users' Background m_rectUsersBG.SetName( "UsersBG" ); SET_QUAD_INIT( m_rectUsersBG ); this->AddChild( &m_rectUsersBG ); //Display users list UpdateUsers(); return; } void ScreenNetSelectBase::Input( const InputEventPlus &input ) { if( m_In.IsTransitioning() || m_Out.IsTransitioning() ) return; if( input.type != IET_FIRST_PRESS && input.type != IET_REPEAT ) return; bool bHoldingCtrl = INPUTFILTER->IsBeingPressed(DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL)) || INPUTFILTER->IsBeingPressed(DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL)) || (!NSMAN->useSMserver); //If we are disconnected, assume no chatting switch( input.DeviceI.button ) { case KEY_ENTER: case KEY_KP_ENTER: if (!bHoldingCtrl) { if ( m_sTextInput != "" ) NSMAN->SendChat( m_sTextInput ); m_sTextInput=""; UpdateTextInput(); return; } break; case KEY_BACK: if(!m_sTextInput.empty()) m_sTextInput = m_sTextInput.erase( m_sTextInput.size()-1 ); UpdateTextInput(); break; default: wchar_t c; c = INPUTMAN->DeviceInputToChar(input.DeviceI, true); if( (c >= ' ') && (!bHoldingCtrl) ) { m_sTextInput += WStringToRString(wstring()+c); UpdateTextInput(); } //Tricky: If both players are playing, allow the 2 button through to the keymapper if( c == '2' && GAMESTATE->IsPlayerEnabled( PLAYER_2 ) && GAMESTATE->IsPlayerEnabled( PLAYER_1 ) ) break; if( c >= ' ' ) return; break; } Screen::Input( input ); // default input handler } void ScreenNetSelectBase::HandleScreenMessage( const ScreenMessage SM ) { if( SM == SM_GoToNextScreen ) SOUND->StopMusic(); else if( SM == SM_AddToChat ) { m_textChatOutput.SetText( NSMAN->m_sChatText ); m_textChatOutput.SetMaxLines( SHOW_CHAT_LINES, 1 ); } else if( SM == SM_UsersUpdate ) { UpdateUsers(); } ScreenWithMenuElements::HandleScreenMessage( SM ); } void ScreenNetSelectBase::TweenOffScreen() { OFF_COMMAND( m_sprChatInputBox ); OFF_COMMAND( m_sprChatOutputBox ); OFF_COMMAND( m_textChatInput ); OFF_COMMAND( m_textChatOutput ); for( unsigned i=0; iRemoveChild( &m_textUsers[i] ); m_textUsers.clear(); m_textUsers.resize( NSMAN->m_ActivePlayer.size() ); for( unsigned i=0; i < NSMAN->m_ActivePlayer.size(); i++) { m_textUsers[i].LoadFromFont( THEME->GetPathF(m_sName,"chat") ); m_textUsers[i].SetHorizAlign( align_center ); m_textUsers[i].SetVertAlign( align_top ); m_textUsers[i].SetShadowLength( 0 ); m_textUsers[i].SetName( "Users" ); tX += USERSDELT_X; if ( (i % 2) == 1) tY = USERSALT_Y + USERS_Y; else tY = USERS_Y; m_textUsers[i].SetXY( tX, tY ); ActorUtil::LoadAllCommands( m_textUsers[i], m_sName ); ActorUtil::OnCommand( m_textUsers[i] ); m_textUsers[i].SetText( NSMAN->m_PlayerNames[NSMAN->m_ActivePlayer[i]] ); m_textUsers[i].RunCommands( THEME->GetMetricA( m_sName, ssprintf("Users%dCommand", NSMAN->m_PlayerStatus[NSMAN->m_ActivePlayer[i]] ) ) ); this->AddChild( &m_textUsers[i] ); } } void ColorBitmapText::SetText( const RString& _sText, const RString& _sAlternateText, int iWrapWidthPixels ) { ASSERT( m_pFont ); RString sNewText = StringWillUseAlternate(_sText,_sAlternateText) ? _sAlternateText : _sText; if( iWrapWidthPixels == -1 ) // wrap not specified iWrapWidthPixels = m_iWrapWidthPixels; if( m_sText == sNewText && iWrapWidthPixels==m_iWrapWidthPixels ) return; m_sText = sNewText; m_iWrapWidthPixels = iWrapWidthPixels; // Set up the first color. m_vColors.clear(); ColorChange change; change.c = RageColor ( 1, 1, 1, 1 ); change.l = 0; m_vColors.push_back( change ); m_wTextLines.clear(); RString sCurrentLine = ""; int iLineWidth = 0; RString sCurrentWord = ""; int iWordWidth = 0; int iGlyphsSoFar = 0; for( unsigned i = 0; i < m_sText.length(); i++ ) { int iCharsLeft = m_sText.length() - i - 1; // First: Check for the special (color) case. RString FirstThree = m_sText.substr( i, 3 ); if( FirstThree.CompareNoCase("|c0") == 0 && iCharsLeft > 8 ) { ColorChange change; int r, g, b; sscanf( m_sText, "|%*c0%2x%2x%2x", &r, &g, &b ); change.c = RageColor( r/255.f, g/255.f, b/255.f, 1.f ); change.l = iGlyphsSoFar; if( iGlyphsSoFar == 0 ) m_vColors[0] = change; else m_vColors.push_back( change ); i+=8; continue; } char curChar = m_sText[0]; int iCharLen = m_pFont->GetLineWidthInSourcePixels( wstring(1, curChar) ); switch( curChar ) { case ' ': if( /* iLineWidth == 0 &&*/ iWordWidth == 0 ) break; sCurrentLine += sCurrentWord + " "; iLineWidth += iWordWidth + iCharLen; sCurrentWord = ""; iWordWidth = 0; iGlyphsSoFar++; break; case '\n': if( iLineWidth + iWordWidth > iWrapWidthPixels ) { SimpleAddLine( sCurrentLine, iLineWidth ); if( iWordWidth > 0 ) iLineWidth = iWordWidth + //Add the width of a space m_pFont->GetLineWidthInSourcePixels( RStringToWstring( " " ) ); sCurrentLine = sCurrentWord + " "; iWordWidth = 0; sCurrentWord = ""; iGlyphsSoFar++; } else { SimpleAddLine( sCurrentLine + sCurrentWord, iLineWidth + iWordWidth ); sCurrentLine = ""; iLineWidth = 0; sCurrentWord = ""; iWordWidth = 0; } break; default: if( iWordWidth + iCharLen > iWrapWidthPixels && iLineWidth == 0 ) { SimpleAddLine( sCurrentWord, iWordWidth ); sCurrentWord = curChar; iWordWidth = iCharLen; } else if( iWordWidth + iLineWidth + iCharLen > iWrapWidthPixels ) { SimpleAddLine( sCurrentLine, iLineWidth ); sCurrentLine = ""; iLineWidth = 0; sCurrentWord += curChar; iWordWidth += iCharLen; } else { sCurrentWord += curChar; iWordWidth += iCharLen; } iGlyphsSoFar++; break; } } if( iWordWidth > 0 ) { sCurrentLine += sCurrentWord; iLineWidth += iWordWidth; } if( iLineWidth > 0 ) SimpleAddLine( sCurrentLine, iLineWidth ); BuildChars(); UpdateBaseZoom(); } void ColorBitmapText::SimpleAddLine( const RString &sAddition, const int iWidthPixels) { m_wTextLines.push_back( RStringToWstring( sAddition ) ); m_iLineWidths.push_back( iWidthPixels ); } void ColorBitmapText::DrawPrimitives( ) { Actor::SetGlobalRenderStates(); // set Actor-specified render states DISPLAY->SetTextureMode( TextureUnit_1, TextureMode_Modulate ); /* Draw if we're not fully transparent or the zbuffer is enabled */ if( m_pTempState->diffuse[0].a != 0 ) { // // render the shadow // if( m_fShadowLength != 0 ) { DISPLAY->PushMatrix(); DISPLAY->TranslateWorld( m_fShadowLength, m_fShadowLength, 0 ); // shift by 5 units RageColor dim(0,0,0,0.5f*m_pTempState->diffuse[0].a); // semi-transparent black for( unsigned i=0; iPopMatrix(); } // // render the diffuse pass // int loc = 0, cur = 0; RageColor c = m_pTempState->diffuse[0]; for( unsigned i=0; i m_vColors[cur].l ) { c = m_vColors[cur].c; cur++; } } for( unsigned j=0; j<4; j++ ) m_aVertices[i+j].c = c; } DrawChars(); } /* render the glow pass */ if( m_pTempState->glow.a > 0.0001f ) { DISPLAY->SetTextureMode( TextureUnit_1, TextureMode_Glow ); for( unsigned i=0; iglow; DrawChars(); } } void ColorBitmapText::SetMaxLines( int iNumLines, int iDirection ) { iNumLines = max( 0, iNumLines ); iNumLines = min( (int)m_wTextLines.size(), iNumLines ); if( iDirection == 0 ) { // Crop all bottom lines m_wTextLines.resize( iNumLines ); m_iLineWidths.resize( iNumLines ); } else { // Because colors are relative to the beginning, we have to crop them back unsigned shift = 0; for( unsigned i = 0; i < m_wTextLines.size() - iNumLines; i++ ) shift += m_wTextLines[i].length(); // When we're cutting out text, we need to maintain the last // color, so our text at the top doesn't become colorless. RageColor LastColor; for( unsigned i = 0; i < m_vColors.size(); i++ ) { m_vColors[i].l -= shift; if( m_vColors[i].l < 0 ) { LastColor = m_vColors[i].c; m_vColors.erase( m_vColors.begin() + i ); i--; } } // If we already have a color set for the first char // do not override it. if( m_vColors.size() > 0 && m_vColors[0].l > 0 ) { ColorChange tmp; tmp.c = LastColor; tmp.l = 0; m_vColors.insert( m_vColors.begin(), tmp ); } m_wTextLines.erase( m_wTextLines.begin(), m_wTextLines.end() - iNumLines ); m_iLineWidths.erase( m_iLineWidths.begin(), m_iLineWidths.end() - iNumLines ); } BuildChars(); } void UtilSetQuadInit( Actor& actor, const RString &sClassName ) { ActorUtil::LoadAllCommandsAndSetXYAndOnCommand( actor, sClassName ); actor.RunCommands( THEME->GetMetricA( sClassName, actor.GetName() + "Command" ) ); actor.SetWidth( THEME->GetMetricF( sClassName, actor.GetName() + "Width" ) ); actor.SetHeight( THEME->GetMetricF( sClassName, actor.GetName() + "Height" ) ); } #endif /* * (c) 2004 Charles Lohr * All rights reserved. * Elements from ScreenTextEntry * * 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, and/or sell copies of the Software, and to permit persons to * whom the Software is furnished to do so, provided that the above * copyright notice(s) and this permission notice appear in all copies of * the Software and that both the above copyright notice(s) and this * permission notice appear in supporting documentation. * * 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 OF * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */