123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813 |
- #define AEDIT_CPP
- /*************************************************************************************************\
- aEdit.cpp : Implementation of the aEdit component of the GUI library.
- //---------------------------------------------------------------------------//
- // Copyright (C) Microsoft Corporation. All rights reserved. //
- //===========================================================================//
- \*************************************************************************************************/
- #include "aEdit.h"
- #include "userInput.h"
- #include "cType.h"
- #include "IniFile.h"
- #include "mclib.h"
- #include <windows.h>
- #include <mbstring.h>
- #include <winnls.h>
- #include "soundSys.h"
- #include "..\resource.h"
- #define ENTRY_MAX_CHARS 1000
- #define ENTRY_MARGIN 4.f
- #define HalfColorValue(color) (((color >> 1) & 0x007f0000) | ((color >> 1) & 0x00007f00) | ((color >> 1) & 0x0000007f))
- static long acp = 0;
- static bool g_bUseLangDll;
- static gosIME_Appearance g_ia;
- extern SoundSystem *sndSystem;
- aEdit::aEdit( )
- {
- if (acp == 0) {
- acp = GetACP();
- gos_SetIMELevel( 2 );
- gos_GetIMEAppearance( &g_ia );
- char szSetting[8];
- szSetting[0] = '1';
- cLoadString( IDS_IME_USE_LANGDLL_SETTING, szSetting, sizeof( szSetting ) );
- g_bUseLangDll = szSetting[0] == '1';
- if (!g_bUseLangDll) {
- // setup fixed colors
- g_ia.symbolColor = 0xff5c96c2;
- g_ia.symbolColorText = 0x7f000000;
- g_ia.symbolTranslucence = 0x7f;
- g_ia.symbolPlacement = 0;
- g_ia.candColorBase = 0xff43311c;
- g_ia.compColorTargetConv = 0xff5c96c2;
- g_ia.compColorTargetNotConv = 0xff002f55;
- g_ia.compColorInputErr = 0xffff00ff;
- g_ia.compTranslucence = 0x7f;
- if (acp != 949) { // other than Korean version, reduce color value by half so that composition string can be seen
- g_ia.compColorTargetConv = HalfColorValue(g_ia.compColorTargetConv);
- g_ia.compColorTargetNotConv = HalfColorValue(g_ia.compColorTargetNotConv);
- g_ia.compColorInputErr = HalfColorValue(g_ia.compColorInputErr);
- }
- }
- }
- nLimit = ENTRY_MAX_CHARS;
- nInsertion1 = nInsertion2 = 0;
- nLeftOffset = 0;
- bMouseDown=0;
- bCursorVisible=FALSE;
- bFocus = 0;
- dwStyleFlags = 0;
- cursorTime = 0.f;
- setColor( 0xff000000 );
- bAllowIME = true;
- bIMEInitialized = false;
- bWierdChars = true;
- //MarkForBackSurfaceUpdate();
- }
- aEdit& aEdit::operator =( const aEdit& src )
- {
- aObject::operator=( src );
- nLimit = src.nLimit;
- nInsertion1 = nInsertion2 = 0;
- nLeftOffset = src.nLeftOffset;
- bMouseDown = 0;
- bCursorVisible = FALSE;
- dwStyleFlags = src.dwStyleFlags;
- text = src.text;
- textColor = src.textColor;
- highlightColor = src.highlightColor;
-
- cursorColor = src.cursorColor;
- selectedColor = src.selectedColor; // selected text
- outlineColor = src.outlineColor;
- font = src.font;
- bAllowIME = src.bAllowIME;
- return *this;
-
- }
- //-------------------------------------------------------------------------------------------------
- aEdit::~aEdit()
- {
- setFocus( 0 );
- }
- void aEdit::update()
- {
- cursorTime += frameLength;
- if ( cursorTime > .5 )
- {
- bCursorVisible ^= 1;
- if ( !bFocus )
- bFocus = bCursorVisible = 0;
- cursorTime = 0.f;
- }
- handleMouse();
- handleKeyboard();
- }
- void aEdit::handleMouse()
- {
- int mouseX = userInput->getMouseX();
- int mouseY = userInput->getMouseY();
- bool bLeftClick = userInput->isLeftClick();
- bool bRightClick = userInput->isRightClick();
-
-
- int nOffset = mouseX - (globalX() + ENTRY_MARGIN);
- nOffset += nLeftOffset;
-
- // find char position of nOffset and set insertion point there
- int nChar = findChar(nOffset);
- if ( bMouseDown && userInput->isLeftDrag() && bFocus )
- {
- nInsertion2 = nChar;
- }
- if ( pointInside( mouseX, mouseY ) )
- {
- if ( bLeftClick && !( dwStyleFlags & ES_EDITREADONLY ) )
- {
- setFocus( true );
- bMouseDown = true;
- bCursorVisible=TRUE;
- nInsertion1 = nChar;
- if (gos_GetKeyStatus(KEY_LSHIFT) == KEY_FREE)
- nInsertion2 = nInsertion1;
- }
- else if ( bRightClick )
- {
-
- }
- }
- else if ( bLeftClick )
- setFocus( false );
-
- }
- void aEdit::handleKeyboard()
- {
- if ( !bFocus )
- return;
- while( true ) // keep getting keys until buffer is empty
- {
- DWORD key = gos_GetKey();
- if ( !key )
- return;
- if (!handleFormattingKeys(key))
- {
- // hack to eat control keys, must be a real way to do this
- if ( ((key & 0x00ff) + ((key & 0x00ff)<<8) + 0x4000) == key
- && key != 0x00006e2e )
- return;
-
- key &= 0x00ff;
- // this does happen when IME is enabled.
- if (key == 0)
- return;
- DWORD key2 = 0;
- if ( isleadbyte( key ) )
- {
- key2 = gos_GetKey( );
- key2 &= 0x00ff;
- }
- if (dwStyleFlags & ES_EDITNUM)
- {
- if (!isdigit(key) && key != ' ' && key != '.')
- return;
- }
- else if (dwStyleFlags & ES_EDITALPHA)
- {
- if (!isalpha(key) && key != ' ')
- return;
- }
- else if (dwStyleFlags & ES_EDITALPHANUM)
- {
- if (!isalpha(key) && !isdigit(key) && key != ' ')
- return;
- }
- if((dwStyleFlags & ES_EDITNOBLANK) && (key==' '))
- return;
- // if there is a selection range, bolt the text within it
- if (gos_GetKeyStatus(KEY_LMENU) != KEY_FREE )
- {
- return;
- }
- if ( key == '%'
- || key == '\\'
- || key == '/'
- || key == '\"') // eat these so andy doesn't try and sprintf on us
- return;
- if ( !bWierdChars )
- {
- if ( (key == '\\') ||
- (key == ':') ||
- (key == '*') ||
- (key == '\'') ||
- (key == '.') ||
- (key == ',') ||
- (key == '/') ||
- (key == '<') ||
- (key == '>') ||
- (key == '?') ||
- (key == '"') ||
- (key == '|') )
- return;
- }
- // is there space to insert a character?
- if (text.Length() - labs( nInsertion2 - nInsertion1 ) + (key2 ? 1 : 0) >= nLimit)
- {
- sndSystem->playDigitalSample( LOG_WRONGBUTTON );
- gos_FinalizeStringIME();
- gos_KeyboardFlush();
- return;
- }
- // insert the character
- if ( key )
- {
- clearSelection();
- char str[3];
- str[0] = key;
- int amountToAdd = 1;
- if ( key2 )
- {
- str[1] = key2;
- str[2] = NULL;
- amountToAdd = 2;
- }
- else
- str[1] = NULL;
-
- if (nInsertion1 < text.Length() )
- {
- text.Insert( nInsertion1, str );
- }
- else
- text += str;
- nInsertion1 += amountToAdd;
- nInsertion2 = nInsertion1;
- }
- }
-
-
- makeCursorVisible();
- }
- }
- void aEdit::renderWithDropShadow()
- {
- // do not do this for .ttf where we already are having performance issues
- if ( font.getSize() == 1 )
- {
- long realTextColor = textColor;
- textColor = 0xff000000;
- move( -1, 1 );
- render();
- move( 1, -1 );
- textColor = realTextColor;
- render();
- }
- else
- render();
- }
- void aEdit::render()
- {
- if ( !isShowing() )
- return;
- aObject::render();
- EString textToDraw = text;
- textToDraw += ' '; // have to do this for loc, some fonts are getting clipped in millenium
- // draw selection range
- if (nInsertion1 != nInsertion2)
- {
- int nMin = nInsertion1<nInsertion2?nInsertion1:nInsertion2;
- int nMax = nInsertion1<nInsertion2?nInsertion2:nInsertion1;
- if ( nMax > text.Length() )
- nMax = text.Length();
- if ( nMax > 1 )
- {
- if (isleadbyte( nMax -2 ) )
- nMax -= 2;
- }
- int nXSelStart = (int)(globalX() + charXPos(nMin) - nLeftOffset + ENTRY_MARGIN);
- int nXSelEnd = (int)(globalX() + charXPos(nMax) - nLeftOffset + ENTRY_MARGIN);
- if (nXSelStart < globalX())
- nXSelStart = globalX();
- if (nXSelEnd > globalX() + width())
- nXSelEnd = globalX() + width();
-
- GUI_RECT rect = { (int)nXSelStart,
- (int)globalY(),
- (int)nXSelEnd,
- (int)(globalY() + height()) };
- int startChar = 0;
- if ( nLeftOffset )
- {
- // need to find character where this position is
- startChar = findChar( nLeftOffset );
- }
- if ( text.Length() )
- {
- font.render( &textToDraw[startChar],
- (int)(globalX() + ENTRY_MARGIN),
- (int)globalY(), (int)width(), (int)height(),
- textColor, 0, 0 );
- }
- drawRect( rect, highlightColor);
- if ( text.Length() )
- {
- char tmp = textToDraw[nMax];
- textToDraw[nMax] = NULL;
- font.render( &textToDraw[nMin], (int)nXSelStart, (int)globalY(),
- nXSelEnd, (int)height(), selectedColor, 0, 0 );
- textToDraw[nMax] = tmp;
- }
- }
- else
- {
- int startChar = 0;
- if ( nLeftOffset )
- {
- // need to find character where this position is
- startChar = findChar( nLeftOffset );
- }
- if ( textToDraw.Length() )
- {
- font.render( &textToDraw[startChar],
- (int)(globalX() + ENTRY_MARGIN),
- (int)globalY(), (int)width(), (int)height(),
- textColor, 0, 0 );
- }
- else
- {
- font.render( "",
- (int)(globalX() + ENTRY_MARGIN),
- (int)globalY(), (int)width(), (int)height(),
- textColor, 0, 0 );
- }
- }
- if ( bFocus && bAllowIME )
- {
- gos_TextSetRegion( globalX() + ENTRY_MARGIN, globalY(), globalX() + width(), globalY() + height() - 1 );
- long pos = charXPos( nInsertion1 );
- if ( acp == 949 && nInsertion1 > nInsertion2 && gos_GetMachineInformation(gos_Info_GetIMEStatus))
- pos = charXPos( nInsertion2 );
- gos_PositionIME( globalX() + pos - nLeftOffset + ENTRY_MARGIN, globalY() );
- }
- drawCursor();
- }
- void aEdit::getEntry(EString& str)
- {
- str = text;
- }
- void aEdit::setEntry(const EString& str, BYTE byHighlight)
- {
- text = str;
- if (byHighlight)
- {
- nInsertion2 = text.Length();
- nInsertion1 = 0;
- }
- else
- {
- nInsertion2 = nInsertion1 = text.Length();
- flushCursorRight();
- }
- }
- void aEdit::setFocus(bool bHasFocus)
- {
- bool bFocusSave = bFocus;
- bFocus = bHasFocus;
- gos_KeyboardFlush();
- if ( bAllowIME && bHasFocus )
- {
- gos_EnableIME( true );
- bCursorVisible = bFocus;
- if (!g_bUseLangDll || g_ia.symbolPlacement == 0)
- g_ia.symbolHeight = height() - 2;
- if (!g_bUseLangDll) {
- // setup dynamic colors
- g_ia.candColorBorder = textColor;
- g_ia.candColorText = textColor;
- g_ia.compColorInput = textColor;
- g_ia.compColorConverted = textColor;
- g_ia.compColorText = textColor;
- if (acp != 949) { // other than Korean version, reduce color value by half
- g_ia.compColorInput = HalfColorValue(g_ia.compColorInput);
- g_ia.compColorConverted = HalfColorValue(g_ia.compColorConverted);
- g_ia.compColorInputErr = HalfColorValue(g_ia.compColorInputErr);
- }
- }
- gos_SetIMEAppearance( &g_ia );
-
- if ( !bIMEInitialized )
- {
- if ( acp == 932 || acp == 874 || acp == 936 || acp == 949 || acp == 950 )
- {
- // only want to do this if using IME
- resize( width() - height() - 2, height() );
- }
- bIMEInitialized = true;
- }
- }
- else {
- // bug #4862 - diable IME only when the edit box had the focus.
- if (bFocusSave)
- gos_EnableIME( false );
- }
- }
- bool aEdit::clearSelection()
- {
- if (nInsertion1 != nInsertion2)
- { // delete selection range
- int nMin = nInsertion1<nInsertion2?nInsertion1:nInsertion2;
- int nMax = nInsertion1<nInsertion2?nInsertion2:nInsertion1;
- int len = 1;
- text.Remove( nMin, nMax-len );
- nInsertion1 = nMin;
- nInsertion2 = nInsertion1;
- flushCursorRight();
- return true;
- }
- return false;
- }
- void aEdit:: backSpace(int nPosition)
- {
- int nCharCount = text.Length();
- if (nPosition>nCharCount)
- return;
- if (nPosition<=0)
- {
- nPosition = 0;
- return;
- }
-
- nCharCount = 1;
- if ( nPosition > 1 )
- {
- unsigned char* pPrev = _mbsdec( (const unsigned char*)(const char*)text, (const unsigned char*)(const char*)text + nPosition );
- nCharCount = (const unsigned char*)(const char*)text + nPosition - pPrev;
- }
- text.Remove( nPosition-nCharCount, nPosition-1 );
- nInsertion2 = nInsertion1 = nPosition-nCharCount;
-
- }
- void aEdit:: drawCursor()
- {
- if ( nInsertion1 != nInsertion2 || !bFocus || !gos_GetMachineInformation( gos_Info_GetIMECaretStatus ) )
- return;
- if (bCursorVisible && !( dwStyleFlags & ES_EDITREADONLY ))
- {
- gos_VERTEX v[2];
- memset( v, 0, sizeof( gos_VERTEX ) * 2 );
- v[0].rhw = v[1].rhw = .5;
- v[0].argb = v[1].argb = cursorColor;
- int nCursorX = charXPos(nInsertion1);
- nCursorX -= nLeftOffset;
- v[0].y = globalY();
- v[1].y = globalY() + height();
- v[0].x = globalX() + nCursorX + ENTRY_MARGIN;
- v[1].x = v[0].x;
-
- gos_DrawLines( v, 2 );
- }
- }
- void aEdit:: hideCursor()
- {
- bCursorVisible=FALSE;
- }
- bool aEdit::handleFormattingKeys(int keycode)
- {
- int key = (keycode & 0xFF00)>>8;
- bool bExtendedKey = true;
- switch (key)
- {
- case KEY_LCONTROL:
- return true;
- break;
- case KEY_RETURN:
- {
- if ( gos_GetKeyStatus(KEY_RETURN) == KEY_PRESSED ) // don't want this called more than 1 time if held
- setFocus( false );
- return true;
- }
- break;
- case KEY_TAB:
- return true;
- break;
- case KEY_GRAVE: // if there is a selection range, bolt the text within it
- if (gos_GetKeyStatus(KEY_LMENU) != KEY_FREE && bAllowIME )
- {
- gos_ToggleIME( true );
- return true;
- }
- break;
- case KEY_HOME:
- if (gos_GetKeyStatus(KEY_LSHIFT) != KEY_FREE)
- nInsertion2 = 0;
- else
- nInsertion2 = nInsertion1=0;
- nLeftOffset = 0;
- bCursorVisible=TRUE;
- return true;
- case KEY_END:
- if (gos_GetKeyStatus(KEY_LSHIFT) != KEY_FREE)
- nInsertion2 = text.Length();
- else
- nInsertion2 = nInsertion1=text.Length();
- makeCursorVisible();
- bCursorVisible=TRUE;
- return true;
- case KEY_LEFT:
- if (gos_GetKeyStatus(KEY_LSHIFT) != KEY_FREE)
- {
- if (nInsertion2)
- {
- int decrementCount = 1;
- if ( nInsertion2 > 1 )
- {
- unsigned char* pPrev = _mbsdec( (const unsigned char*)(const char*)text, (const unsigned char*)(const char*)text + nInsertion2 );
- decrementCount = (const unsigned char*)(const char*)text + nInsertion2 - pPrev;
- }
- nInsertion2-= decrementCount;
- }
- }
- else
- {
- if (nInsertion1 != nInsertion2)
- nInsertion1 = nInsertion1<nInsertion2?nInsertion1:nInsertion2;
- else if (nInsertion1)
- {
- int decrementCount = 1;
- if ( nInsertion1 > 1 )
- {
- unsigned char* pPrev = _mbsdec( (const unsigned char*)(const char*)text, (const unsigned char*)(const char*)text + nInsertion2 );
- decrementCount = (const unsigned char*)(const char*)text + nInsertion2 - pPrev;
- }
- nInsertion1 -= decrementCount;
- }
- nInsertion2 = nInsertion1;
- }
- makeCursorVisible();
- bCursorVisible=TRUE;
- return true;
- case KEY_RIGHT:
- if (gos_GetKeyStatus(KEY_LSHIFT) != KEY_FREE)
- {
- nInsertion2 += charLength(nInsertion2);
- }
- else
- {
- if (nInsertion1 != nInsertion2)
- nInsertion1 = nInsertion1>nInsertion2?nInsertion1:nInsertion2;
- else if (nInsertion1<text.Length())
- nInsertion1 += charLength( nInsertion1 );
- nInsertion2 = nInsertion1;
- }
- makeCursorVisible();
- bCursorVisible=TRUE;
- return true;
- case KEY_DELETE:
- if (bExtendedKey) // must check this, the period key will get mixed up with this
- {
- if (!clearSelection())
- backSpace(nInsertion1+charLength(nInsertion1));
- makeCursorVisible();
- bCursorVisible=TRUE;
- return true;
- }
- break;
- case KEY_BACK:
- if (!clearSelection())
- backSpace(nInsertion1);
- flushCursorRight();
- makeCursorVisible();
- bCursorVisible=TRUE;
- return true;
- break;
- case KEY_UP:
- case KEY_DOWN:
- return true;
- break;
- case KEY_8:
- if ( !bWierdChars && userInput->getKeyDown( KEY_LSHIFT ) )
- return true;
- break;
- // case \*/?:<>|
- }
- return false;
- }
- int aEdit::charXPos(int nCharIndex)
- {
- if (nCharIndex > text.Length() || !text.Length())
- return 0;
- int nXPos = 0;
- if ( nCharIndex != text.Length() )
- {
- int oldChar = text[nCharIndex];
- text[nCharIndex] = 0;
- nXPos = font.width( text );
- text[nCharIndex] = oldChar;
- }
- else
- {
- nXPos = font.width( text );
- }
- return nXPos;
- }
- void aEdit::makeCursorVisible()
- {
- int nXPos = charXPos(nInsertion2);
- if (nXPos < nLeftOffset)
- nLeftOffset = nXPos;
- if (nXPos > nLeftOffset + width() - (ENTRY_MARGIN*2.f))
- nLeftOffset = nXPos - (int)(width() - (ENTRY_MARGIN*2.f));
- }
- void aEdit::flushCursorRight()
- {
- int nXPos = charXPos(nInsertion2);
- if (nXPos < width() - ENTRY_MARGIN*2)
- nLeftOffset = 0;
- else
- nLeftOffset = nXPos - (int)(width()- ENTRY_MARGIN*2.f);
- }
- int aEdit::findChar(int nXPos)
- {
- int nLastPos,nNextPos,n;
- nNextPos = nLastPos = 0;
- n=0;
- unsigned char* pBegin = (unsigned char*)&text[0];
- unsigned char* pCur = pBegin;
- unsigned char* pNext = pBegin;
- if ( text.Length() )
- {
- do
- {
- pNext = _mbsinc( pCur );
- unsigned char tmp = *pNext;
- *pNext = NULL;
- nLastPos = nNextPos;
- nNextPos = font.width(text);
- *pNext = tmp;
- if ( nXPos > nNextPos )
- pCur = pNext;
- } while ( *pCur && nXPos > nNextPos);
- }
- if ( nXPos - nLastPos < nNextPos - nXPos )
- n = pCur - pBegin;
- else
- n = pNext - pBegin;
- if (n>text.Length())
- n=text.Length();
- return n;
- }
- void aEdit::init( FitIniFile* file, const char* header )
- {
- int result = file->seekBlock( header );
-
- if ( result != NO_ERR )
- {
- char errorStr[256];
- sprintf( errorStr, "couldn't find the text block%s", header );
- Assert( result == NO_ERR, 0, errorStr );
- return;
- }
- long left, top, width, height;
- file->readIdLong( "XLocation", left );
- file->readIdLong( "YLocation", top );
- file->readIdLong( "Width", width );
- file->readIdLong( "Height", height );
- aObject::init( left, top, width, height );
-
- file->readIdLong( "Color", textColor );
- long lfont;
- file->readIdLong( "Font", lfont );
- font.init( lfont );
- file->readIdLong( "CursorColor", cursorColor );
- file->readIdLong( "HighlightColor", highlightColor );
- file->readIdLong( "SelectedColor", selectedColor );
- file->readIdLong( "HelpCaption", helpHeader );
- file->readIdLong( "HelpDesc", helpID );
- }
- int aEdit::charLength( int index )
- {
- if ( index < 0 )
- return 0;
- if ( index > text.Length() )
- return 0;
- char tmp = text[index];
- if ( isleadbyte( tmp ) )
- return 2;
- return 1;
- }
- void aEdit::setFont( long resID )
- {
- font.init( resID );
- }
- //*************************************************************************************************
- // end of file ( aEdit.cpp )
|