/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ ////////////////////////////////////////////////////////////////////////////// // // // pfGUIEditBoxMod Definition // // // ////////////////////////////////////////////////////////////////////////////// #ifdef PLASMA_EXTERNAL_RELEASE //#define LIMIT_VOICE_CHAT 1 #endif #include "hsTypes.h" #include "pfGUIEditBoxMod.h" #include "pfGameGUIMgr.h" #include "pnMessage/plRefMsg.h" #include "pfMessage/pfGameGUIMsg.h" #include "plMessage/plAnimCmdMsg.h" #include "plAvatar/plAGModifier.h" #include "plGImage/plDynamicTextMap.h" #include "plgDispatch.h" #include "hsResMgr.h" #include "pnInputCore/plKeyMap.h" #include //// Constructor/Destructor ////////////////////////////////////////////////// pfGUIEditBoxMod::pfGUIEditBoxMod() { SetFlag( kWantsInterest ); SetFlag( kTakesSpecialKeys ); fIgnoreNextKey = false; fEscapedFlag = false; fFirstHalfExitKeyPushed = false; fSpecialCaptureKeyEventMode = false; fBuffer = 0; SetBufferSize( 128 ); } pfGUIEditBoxMod::~pfGUIEditBoxMod() { delete [] fBuffer; } //// IEval /////////////////////////////////////////////////////////////////// hsBool pfGUIEditBoxMod::IEval( double secs, hsScalar del, UInt32 dirty ) { return pfGUIControlMod::IEval( secs, del, dirty ); } //// MsgReceive ////////////////////////////////////////////////////////////// hsBool pfGUIEditBoxMod::MsgReceive( plMessage *msg ) { return pfGUIControlMod::MsgReceive( msg ); } //// IPostSetUpDynTextMap //////////////////////////////////////////////////// void pfGUIEditBoxMod::IPostSetUpDynTextMap( void ) { pfGUIColorScheme *scheme = GetColorScheme(); fDynTextMap->SetFont( scheme->fFontFace, scheme->fFontSize, scheme->fFontFlags, HasFlag( kXparentBgnd ) ? false : true ); } //// IUpdate ///////////////////////////////////////////////////////////////// void pfGUIEditBoxMod::IUpdate( void ) { hsColorRGBA c; if( fDynTextMap == nil || !fDynTextMap->IsValid() ) return; c.Set( 0.f, 0.f, 0.f, 1.f ); if ( fFocused && fSpecialCaptureKeyEventMode ) fDynTextMap->ClearToColor( GetColorScheme()->fSelBackColor ); else fDynTextMap->ClearToColor( GetColorScheme()->fBackColor ); if( fBuffer != nil ) { // First, calc the cursor position, so we can adjust the scrollPos as necessary Int16 cursorPos, oldCursorPos; if( fFocused && !fSpecialCaptureKeyEventMode ) { // Really cheap hack here to figure out where to draw the cursor wchar_t backup = fBuffer[ fCursorPos ]; fBuffer[ fCursorPos ] = 0; cursorPos = fDynTextMap->CalcStringWidth( fBuffer ); fBuffer[ fCursorPos ] = backup; oldCursorPos = cursorPos; cursorPos -= (Int16)fScrollPos; if( 4 + cursorPos > fDynTextMap->GetVisibleWidth() - 18 ) { fScrollPos += ( 4 + cursorPos ) - ( fDynTextMap->GetVisibleWidth() - 18 ); } else if( 4 + cursorPos < 4 ) { fScrollPos -= 4 - ( 4 + cursorPos ); if( fScrollPos < 0 ) fScrollPos = 0; } cursorPos = (Int16)(oldCursorPos - fScrollPos); } if ( fFocused && fSpecialCaptureKeyEventMode ) // if special and has focus then use select fDynTextMap->SetTextColor( GetColorScheme()->fSelForeColor, GetColorScheme()->fTransparent && GetColorScheme()->fSelBackColor.a == 0.f ); else fDynTextMap->SetTextColor( GetColorScheme()->fForeColor, GetColorScheme()->fTransparent && GetColorScheme()->fBackColor.a == 0.f ); fDynTextMap->DrawClippedString( (Int16)(4 - fScrollPos), 4, fBuffer, 4, 4, fDynTextMap->GetVisibleWidth() - 8, fDynTextMap->GetVisibleHeight() - 8 ); if( fFocused && !fSpecialCaptureKeyEventMode ) { fDynTextMap->FrameRect( 4 + cursorPos, 4, 2, fDynTextMap->GetVisibleHeight() - 8, GetColorScheme()->fSelForeColor ); } } fDynTextMap->FlushToHost(); } void pfGUIEditBoxMod::PurgeDynaTextMapImage() { if ( fDynTextMap != nil ) fDynTextMap->PurgeImage(); } //// Read/Write ////////////////////////////////////////////////////////////// void pfGUIEditBoxMod::Read( hsStream *s, hsResMgr *mgr ) { pfGUIControlMod::Read(s, mgr); } void pfGUIEditBoxMod::Write( hsStream *s, hsResMgr *mgr ) { pfGUIControlMod::Write( s, mgr ); } //// HandleMouseDown ///////////////////////////////////////////////////////// // What we do: normal click deselects all and selects the item clicked on // (if any). Shift-click and ctrl-click avoids the deselect and toggles // the item clicked on. void pfGUIEditBoxMod::HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers ) { wchar_t backup; UInt16 width; if( fBuffer != nil && fDynTextMap != nil ) { if( !fBounds.IsInside( &mousePt ) ) return; IScreenToLocalPt( mousePt ); mousePt.fX *= fDynTextMap->GetVisibleWidth(); mousePt.fX += fScrollPos - 4; for( fCursorPos = 0; fCursorPos < wcslen( fBuffer ); fCursorPos++ ) { backup = fBuffer[ fCursorPos + 1 ]; fBuffer[ fCursorPos + 1 ] = 0; width = fDynTextMap->CalcStringWidth( fBuffer ); fBuffer[ fCursorPos + 1 ] = backup; if( width > mousePt.fX ) break; } IUpdate(); } } //// HandleMouseUp /////////////////////////////////////////////////////////// void pfGUIEditBoxMod::HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers ) { } //// HandleMouseDrag ///////////////////////////////////////////////////////// void pfGUIEditBoxMod::HandleMouseDrag( hsPoint3 &mousePt, UInt8 modifiers ) { } hsBool pfGUIEditBoxMod::HandleKeyPress( wchar_t key, UInt8 modifiers ) { if( fBuffer == nil ) return false; if( fIgnoreNextKey ) { // So we don't process keys that already got handled by HandleKeyEvent() fIgnoreNextKey = false; return true; } int i = wcslen( fBuffer ); // Insert character at the current cursor position, then inc the cursor by one if( i < fBufferSize - 1 && key != 0 ) { memmove( fBuffer + fCursorPos + 1, fBuffer + fCursorPos, (i - fCursorPos + 1) * sizeof(wchar_t) ); fBuffer[ fCursorPos ] = key; fCursorPos++; HandleExtendedEvent( kValueChanging ); } IUpdate(); return true; } hsBool pfGUIEditBoxMod::HandleKeyEvent( pfGameGUIMgr::EventType event, plKeyDef key, UInt8 modifiers ) { if ( fSpecialCaptureKeyEventMode) { // handle doing special caputre mode if ( event == pfGameGUIMgr::kKeyDown ) { #ifdef LIMIT_VOICE_CHAT // don't allow them to map the TAB key to anything! 'cause we'll use it later if ( key == KEY_TAB) { fIgnoreNextKey = true; fFirstHalfExitKeyPushed = false; return true; } #endif // capture the key fSavedKey = key; fSavedModifiers = modifiers; // turn key event into string char keyStr[30]; if (plKeyMap::ConvertVKeyToChar( key )) strcpy(keyStr, plKeyMap::ConvertVKeyToChar( key )); else memset(keyStr, 0, sizeof(keyStr)); static char shortKey[ 2 ]; if( strlen(keyStr) == 0 ) { if( isalnum( key ) ) { shortKey[ 0 ] = (char)key; shortKey[ 1 ] = 0; strcpy(keyStr, shortKey); } else strcpy(keyStr, plKeyMap::GetStringUnmapped()); } else { // check to see the buffer has ForewardSlash and change it to ForwardSlash if ( strcmp(keyStr,"ForewardSlash") == 0) { strcpy(keyStr,"ForwardSlash"); } } static char newKey[ 16 ]; newKey[0] = 0; if( modifiers & kShift ) strcat( newKey, plKeyMap::GetStringShift() ); if( modifiers & kCtrl ) strcat( newKey, plKeyMap::GetStringCtrl() ); strcat( newKey, keyStr ); // set something in the buffer to be displayed wchar_t* temp = hsStringToWString(newKey); wcsncpy( fBuffer, temp , fBufferSize - 1 ); delete [] temp; fCursorPos = 0; SetCursorToEnd(); IUpdate(); // done capturing... tell the handler DoSomething(); } fIgnoreNextKey = true; fFirstHalfExitKeyPushed = false; return true; } else { // HACK for now--pass through caps lock so the runlock stuff will work even while a GUI is up if( key == KEY_CAPSLOCK ) return false; if( event == pfGameGUIMgr::kKeyDown || event == pfGameGUIMgr::kKeyRepeat ) { fFirstHalfExitKeyPushed = false; // Use arrow keys to do our dirty work if( key == KEY_UP || key == KEY_HOME ) { SetCursorToHome(); } else if( key == KEY_DOWN || key == KEY_END ) { SetCursorToEnd(); } else if( key == KEY_LEFT ) { if( fCursorPos > 0 ) fCursorPos--; } else if( key == KEY_RIGHT && fBuffer != nil ) { if( fCursorPos < wcslen( fBuffer ) ) fCursorPos++; } else if( key == KEY_BACKSPACE && fBuffer != nil ) { if( fCursorPos > 0 ) { fCursorPos--; memmove( fBuffer + fCursorPos, fBuffer + fCursorPos + 1, (wcslen( fBuffer + fCursorPos + 1 ) + 1) * sizeof(wchar_t) ); } } else if( key == KEY_DELETE && fBuffer != nil ) { if( fCursorPos < wcslen( fBuffer ) ) memmove( fBuffer + fCursorPos, fBuffer + fCursorPos + 1, (wcslen( fBuffer + fCursorPos + 1 ) + 1) * sizeof(wchar_t) ); } else if( key == KEY_ENTER ) { // do nothing here... wait for the keyup event fFirstHalfExitKeyPushed = true; } else if( key == KEY_ESCAPE ) { // // do nothing here... wait for the keyup event // fFirstHalfExitKeyPushed = true; fEscapedFlag = true; DoSomething(); // Query WasEscaped() to see if it was escape vs enter return true; } else { fIgnoreNextKey = false; return true; } fIgnoreNextKey = true; IUpdate(); return true; } // wait until the Key up for enter and escape to make sure we capture the whole key // ...before we give on focus control else if( event == pfGameGUIMgr::kKeyUp ) { if( key == KEY_ENTER ) { if (fFirstHalfExitKeyPushed) { // Do jack, just here to filter out it being added to the buffer // Well, ok, actually do *something*. *cough*. DoSomething(); fFirstHalfExitKeyPushed = false; return true; } } else if( key == KEY_ESCAPE ) { if (fFirstHalfExitKeyPushed) { // fEscapedFlag = true; // DoSomething(); // Query WasEscaped() to see if it was escape vs enter fFirstHalfExitKeyPushed = false; return true; } } fFirstHalfExitKeyPushed = false; return true; } else { // We don't process them, but we don't want anybody else processing them either return true; } } } std::string pfGUIEditBoxMod::GetBuffer( void ) { char* temp = hsWStringToString(fBuffer); std::string retVal = temp; delete [] temp; return retVal; } void pfGUIEditBoxMod::ClearBuffer( void ) { if( fBuffer != nil ) { memset( fBuffer, 0, (fBufferSize + 1) * sizeof(wchar_t) ); fCursorPos = 0; fScrollPos = 0; IUpdate(); } } void pfGUIEditBoxMod::SetText( const char *str ) { wchar_t* temp = hsStringToWString(str); SetText(temp); delete [] temp; } void pfGUIEditBoxMod::SetText( const wchar_t *str ) { if( fBuffer != nil ) { wcsncpy( fBuffer, str, fBufferSize - 1 ); fCursorPos = 0; fScrollPos = 0; IUpdate(); } } void pfGUIEditBoxMod::SetBufferSize( UInt32 size ) { delete [] fBuffer; fBufferSize = size; if( size > 0 ) { fBuffer = TRACKED_NEW wchar_t[ size + 1 ]; memset( fBuffer, 0, (size + 1) * sizeof(wchar_t) ); } else fBuffer = nil; fCursorPos = 0; fScrollPos = 0; } void pfGUIEditBoxMod::SetCursorToHome( void ) { fCursorPos = 0; } void pfGUIEditBoxMod::SetCursorToEnd( void ) { if( fBuffer != nil ) fCursorPos = wcslen( fBuffer ); } void pfGUIEditBoxMod::SetLastKeyCapture(UInt32 key, UInt8 modifiers) { // capture the key fSavedKey = (plKeyDef)key; fSavedModifiers = modifiers; // turn key event into string char keyStr[30]; if (plKeyMap::ConvertVKeyToChar( key )) strcpy(keyStr, plKeyMap::ConvertVKeyToChar( key )); else memset(keyStr, 0, sizeof(keyStr)); static char shortKey[ 2 ]; if( strlen(keyStr) == 0 ) { if( isalnum( key ) ) { shortKey[ 0 ] = (char)key; shortKey[ 1 ] = 0; strcpy(keyStr, shortKey); } else strcpy(keyStr, plKeyMap::GetStringUnmapped()); } else { // check to see the buffer has ForewardSlash and change it to ForwardSlash if ( strcmp(keyStr,"ForewardSlash") == 0) { strcpy(keyStr,"ForwardSlash"); } } static char newKey[ 16 ]; newKey[0] = 0; if( modifiers & kShift ) strcat( newKey, plKeyMap::GetStringShift() ); if( modifiers & kCtrl ) strcat( newKey, plKeyMap::GetStringCtrl() ); strcat( newKey, keyStr ); // set something in the buffer to be displayed wchar_t* temp = hsStringToWString(newKey); wcsncpy( fBuffer, temp , fBufferSize - 1 ); delete [] temp; fCursorPos = 0; SetCursorToEnd(); IUpdate(); }