Initial commit: Complete open-source Decal rebuild
All 5 phases of the open-source Decal rebuild: Phase 1: 14 decompiled .NET projects (Interop.*, Adapter, FileService, DecalUtil) Phase 2: 10 native DLLs rewritten as C# COM servers with matching GUIDs - DecalDat, DHS, SpellFilter, DecalInput, DecalNet, DecalFilters - Decal.Core, DecalControls, DecalRender, D3DService Phase 3: C++ shims for Inject.DLL (D3D9 hooking) and LauncherHook.DLL Phase 4: DenAgent WinForms tray application Phase 5: WiX installer and build script 25 C# projects building with 0 errors. Native C++ projects require VS 2022 + Windows SDK (x86). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
commit
d1442e3747
1382 changed files with 170725 additions and 0 deletions
990
Native/DecalControls/Edit.cpp
Normal file
990
Native/DecalControls/Edit.cpp
Normal file
|
|
@ -0,0 +1,990 @@
|
|||
// Edit.cpp : Implementation of cEdit
|
||||
#include "stdafx.h"
|
||||
#include "DecalControls.h"
|
||||
#include "Edit.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// cEdit
|
||||
|
||||
#define TIMER_CARET 1
|
||||
#define TIMER_REPEAT 2
|
||||
|
||||
#define END -1
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
|
||||
cEdit::cEdit()
|
||||
: m_bAllowCapture( true ), // cyn -- 15/10/2002
|
||||
m_bCapture( false ),
|
||||
m_bDrawCaret( false ),
|
||||
m_bSelecting( false ),
|
||||
m_nSelStartChar( 0 ),
|
||||
m_nSelStart( 0 ),
|
||||
m_nCaretChar( 0 ),
|
||||
m_nCaret( 0 ),
|
||||
m_nOffset( 0 ),
|
||||
m_nTextColor( 0 ),
|
||||
m_nCaretHeight( 0 )
|
||||
{
|
||||
m_szMargin.cx = 3;
|
||||
m_szMargin.cy = 1;
|
||||
}
|
||||
|
||||
void cEdit::checkFont()
|
||||
{
|
||||
if( m_pFont.p == NULL )
|
||||
{
|
||||
CComPtr< IPluginSite > pPlugin;
|
||||
m_pSite->get_PluginSite( &pPlugin );
|
||||
|
||||
BSTR bstrFontName;
|
||||
pPlugin->get_FontName(&bstrFontName);
|
||||
pPlugin->CreateFont( bstrFontName /*_bstr_t( _T( "Times New Roman" ) )*/, 14, 0, &m_pFont );
|
||||
}
|
||||
}
|
||||
|
||||
void cEdit::sendTextChange()
|
||||
{
|
||||
long nID;
|
||||
m_pSite->get_ID( &nID );
|
||||
|
||||
Fire_Change( nID, _bstr_t( m_strText.c_str() ) );
|
||||
}
|
||||
|
||||
void cEdit::Delete() {
|
||||
if (m_nCaretChar == m_nSelStartChar) {
|
||||
return;
|
||||
}
|
||||
m_strText.assign( m_strText.substr(0, MIN(m_nCaretChar, m_nSelStartChar)) + m_strText.substr(MAX(m_nCaretChar, m_nSelStartChar), m_strText.length()) );
|
||||
if (m_bPassword) { /* This is bad, someone fix it */
|
||||
m_strPass.assign( m_strPass.substr(0, MIN(m_nCaretChar, m_nSelStartChar)) + m_strPass.substr(MAX(m_nCaretChar, m_nSelStartChar), m_strPass.length()) );
|
||||
}
|
||||
m_nSelStartChar = MIN(m_nCaretChar, m_nSelStartChar);
|
||||
put_Caret( m_nSelStartChar );
|
||||
}
|
||||
|
||||
void cEdit::Copy() {
|
||||
HGLOBAL hMem;
|
||||
HRESULT hr;
|
||||
long hWnd;
|
||||
IPluginSite *Plug;
|
||||
char *lpMem;
|
||||
int Start, Length;
|
||||
|
||||
if (m_bPassword) {
|
||||
return;
|
||||
}
|
||||
|
||||
hr = m_pSite->get_PluginSite(&Plug);
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
hr = Plug->get_HWND(&hWnd);
|
||||
Plug->Release();
|
||||
Plug = NULL;
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_nCaretChar < m_nSelStartChar) {
|
||||
Start = m_nCaretChar;
|
||||
Length = m_nSelStartChar - Start;
|
||||
} else {
|
||||
Start = m_nSelStartChar;
|
||||
Length = m_nCaretChar - Start;
|
||||
}
|
||||
|
||||
hMem = GlobalAlloc(GMEM_MOVEABLE, Length+1);
|
||||
if (!hMem) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
lpMem = (char *)GlobalLock(hMem);
|
||||
if (!lpMem) {
|
||||
GlobalFree(hMem);
|
||||
return;
|
||||
}
|
||||
|
||||
/* This is gauranteed to nul-terminate */
|
||||
lstrcpyn( lpMem, m_strText.c_str() + Start, Length + 1);
|
||||
|
||||
GlobalUnlock(hMem);
|
||||
|
||||
if (!OpenClipboard((HWND)hWnd)) {
|
||||
GlobalFree(hMem);
|
||||
return;
|
||||
}
|
||||
|
||||
EmptyClipboard();
|
||||
GetLastError();
|
||||
SetClipboardData(CF_TEXT, hMem);
|
||||
GetLastError();
|
||||
CloseClipboard();
|
||||
}
|
||||
|
||||
|
||||
void cEdit::Cut() {
|
||||
if (!m_bPassword) {
|
||||
Copy();
|
||||
Delete();
|
||||
}
|
||||
}
|
||||
|
||||
// OK, this paste code isn't pretty, but it's functional for now. Look for a full rewrite later!
|
||||
// cyn, 22/10/2002
|
||||
void cEdit::Paste() {
|
||||
HANDLE hClipboardData;
|
||||
char *sData;
|
||||
int Count, Length;
|
||||
|
||||
Delete();
|
||||
|
||||
if (!OpenClipboard(NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
hClipboardData = GetClipboardData(CF_TEXT);
|
||||
|
||||
if (hClipboardData) {
|
||||
sData = (char *)GlobalLock(hClipboardData);
|
||||
|
||||
if (sData) {
|
||||
Length = lstrlen(sData);
|
||||
for (Count=0;Count<Length;Count++) {
|
||||
if ((sData[Count] == 13) || (sData[Count] == 10)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_strText.insert(m_strText.begin() + m_nCaretChar, sData, sData + Count);
|
||||
if (m_bPassword) {
|
||||
m_strPass.insert(m_strPass.begin(), Count, '*');
|
||||
}
|
||||
put_Caret(m_nCaretChar + Count);
|
||||
GlobalUnlock(hClipboardData);
|
||||
}
|
||||
}
|
||||
|
||||
CloseClipboard();
|
||||
}
|
||||
|
||||
int cEdit::Normalize(int Offset) {
|
||||
int Length;
|
||||
Length = m_strText.length();
|
||||
if (Offset == END) {
|
||||
return Length;
|
||||
} else if (Offset < END) {
|
||||
return 0;
|
||||
} else if (Offset > Length) {
|
||||
return Length;
|
||||
}
|
||||
return Offset;
|
||||
}
|
||||
|
||||
STDMETHODIMP cEdit::Reformat()
|
||||
{
|
||||
// Just a typical post-resize type of behavior, make sure everythign is still visible as
|
||||
// the user likes.
|
||||
if( m_nCaretChar > m_strText.length() )
|
||||
put_Caret( m_strText.length() );
|
||||
else
|
||||
// Force a recalculation for scrolling
|
||||
put_Caret( m_nCaretChar );
|
||||
|
||||
//put_Caret( m_nCaretChar );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cEdit::Render( ICanvas *pCanvas )
|
||||
{
|
||||
HDC RenderDC;
|
||||
HRESULT hr;
|
||||
|
||||
checkFont();
|
||||
|
||||
// Draw the background
|
||||
RECT rcPos;
|
||||
m_pSite->get_Position( &rcPos );
|
||||
|
||||
RECT rcClient = { 0, 0, rcPos.right - rcPos.left, rcPos.bottom - rcPos.top };
|
||||
|
||||
if( m_pBackground.p != NULL )
|
||||
{
|
||||
static POINT ptOff = { 0, 0 };
|
||||
m_pBackground->PatBlt( pCanvas, &rcClient, &ptOff );
|
||||
}
|
||||
|
||||
RECT rcText = { m_szMargin.cx, m_szMargin.cy, rcClient.right - m_szMargin.cx, rcClient.bottom - m_szMargin.cy };
|
||||
VARIANT_BOOL bVisible;
|
||||
pCanvas->SetClipRect( &rcText, &bVisible );
|
||||
|
||||
if( !bVisible )
|
||||
// Nothing to draw huzzah!
|
||||
return S_OK;
|
||||
|
||||
long lFlags = 0;
|
||||
|
||||
if( m_bAA )
|
||||
lFlags |= eAA;
|
||||
|
||||
if( m_bOutline )
|
||||
lFlags |= eOutlined;
|
||||
|
||||
// Draw the text
|
||||
POINT ptText = { -m_nOffset, 0 };
|
||||
if( m_strText.length() > 0 )
|
||||
if (m_bPassword) {
|
||||
m_pFont->DrawTextEx( &ptText, _bstr_t( m_strPass.c_str() ), m_nTextColor, m_nOutlineColor, lFlags, pCanvas );
|
||||
} else {
|
||||
m_pFont->DrawTextEx( &ptText, _bstr_t( m_strText.c_str() ), m_nTextColor, m_nOutlineColor, lFlags, pCanvas );
|
||||
}
|
||||
|
||||
if( m_bCapture && m_bDrawCaret )
|
||||
{
|
||||
// Draw the caret
|
||||
RECT rcCaret = { m_nCaret - m_nOffset, m_szMargin.cy, m_nCaret - m_nOffset + 1, m_szMargin.cy + m_nCaretHeight };
|
||||
pCanvas->Fill( &rcCaret, m_nTextColor );
|
||||
}
|
||||
|
||||
if( m_bCapture ) // - Haz, fix for the annoying multiple edit selection ghosts
|
||||
{
|
||||
if (m_nCaretChar != m_nSelStartChar) {
|
||||
hr = pCanvas->GetDC(&RenderDC);
|
||||
if (SUCCEEDED(hr)) {
|
||||
RECT rcSelect;
|
||||
rcSelect.top = m_szMargin.cy;
|
||||
rcSelect.bottom = m_szMargin.cy + m_nCaretHeight;
|
||||
rcSelect.left = m_nSelStart - m_nOffset;
|
||||
rcSelect.right = m_nCaret - m_nOffset;
|
||||
if (rcSelect.right < rcSelect.left) {
|
||||
int t;
|
||||
t = rcSelect.left;
|
||||
rcSelect.left = rcSelect.right;
|
||||
rcSelect.right = t;
|
||||
}
|
||||
|
||||
|
||||
InvertRect(RenderDC, &rcSelect);
|
||||
pCanvas->ReleaseDC();
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cEdit::MouseDown( MouseState *pMS )
|
||||
{
|
||||
if( !m_bCapture )
|
||||
Capture();
|
||||
else
|
||||
{
|
||||
_ASSERTE(!m_bSelecting);
|
||||
checkFont();
|
||||
|
||||
// Hit test the character and move to that position
|
||||
long nHitChar;
|
||||
if(m_bPassword)
|
||||
m_pFont->HitTest( _bstr_t( m_strPass.c_str() ), pMS->client.x + m_nOffset - m_szMargin.cx, &nHitChar );
|
||||
else
|
||||
m_pFont->HitTest( _bstr_t( m_strText.c_str() ), pMS->client.x + m_nOffset - m_szMargin.cx, &nHitChar );
|
||||
|
||||
// Reset the timer
|
||||
put_Caret( nHitChar );
|
||||
|
||||
m_bSelecting = true;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cEdit::MouseUp(MouseState *pMS) {
|
||||
/* I assume it's possible to trigger a mouse up without a mousedown */
|
||||
m_bSelecting = false;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cEdit::MouseMove(MouseState *pMS) {
|
||||
long nHitChar;
|
||||
|
||||
if (!m_bCapture) {
|
||||
_ASSERTE(!m_bSelecting);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (!m_bSelecting) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
checkFont();
|
||||
if (m_bPassword) {
|
||||
m_pFont->HitTest( _bstr_t( m_strPass.c_str() ), pMS->client.x + m_nOffset - m_szMargin.cx, &nHitChar );
|
||||
} else {
|
||||
m_pFont->HitTest( _bstr_t( m_strText.c_str() ), pMS->client.x + m_nOffset - m_szMargin.cx, &nHitChar );
|
||||
}
|
||||
|
||||
put_Caret(nHitChar);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP cEdit::KeyboardChar( KeyState *pKS )
|
||||
{
|
||||
if (pKS->ctrl && pKS->vkey == 22) {
|
||||
Paste();
|
||||
} else if (pKS->ctrl && pKS->vkey == 3) {
|
||||
Copy();
|
||||
} else if (pKS->ctrl && pKS->vkey == 24) {
|
||||
Cut();
|
||||
} else {
|
||||
// Look for special characters
|
||||
switch( pKS->vkey )
|
||||
{
|
||||
case VK_BACK:
|
||||
if (m_nCaretChar != m_nSelStartChar) {
|
||||
Delete();
|
||||
} else {
|
||||
if( m_nCaretChar > 0 )
|
||||
{
|
||||
// Decrease the caret position
|
||||
put_Caret( m_nCaretChar - 1 );
|
||||
|
||||
// Remove the character
|
||||
m_strText.erase( m_strText.begin() + m_nCaretChar, m_strText.begin() + m_nCaretChar + 1 );
|
||||
|
||||
if(m_bPassword)
|
||||
m_strPass.erase( m_strPass.begin() + m_nCaretChar, m_strPass.begin() + m_nCaretChar + 1 );
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Assume every other character is being added
|
||||
if (m_nCaretChar != m_nSelStartChar) {
|
||||
Delete();
|
||||
}
|
||||
char wc[ 2 ] = { pKS->vkey, L'\0' };
|
||||
m_strText.insert( m_strText.begin() + m_nCaretChar, wc, wc + 1 );
|
||||
if(m_bPassword)
|
||||
{
|
||||
wc[0] = L'*';
|
||||
m_strPass.insert( m_strPass.begin() + m_nCaretChar, wc, wc + 1 );
|
||||
}
|
||||
put_Caret( m_nCaretChar + 1 );
|
||||
}
|
||||
}
|
||||
|
||||
m_pSite->Invalidate();
|
||||
sendTextChange();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cEdit::KeyboardEndCapture( VARIANT_BOOL bCancel )
|
||||
{
|
||||
if (bCancel) { // cyn, 15/10/2002
|
||||
m_bAllowCapture = false;
|
||||
}
|
||||
m_bCapture = false;
|
||||
m_pSite->EndTimer( TIMER_CARET );
|
||||
m_pSite->Invalidate();
|
||||
|
||||
long nID;
|
||||
m_pSite->get_ID( &nID );
|
||||
Fire_End( nID, ( bCancel ) ? VARIANT_FALSE : VARIANT_TRUE );
|
||||
m_bAllowCapture = true; // cyn, 15/10/2002
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cEdit::KeyboardEvent( long nMsg, long wParam, long lParam )
|
||||
{
|
||||
const char *Start;
|
||||
int Search;
|
||||
bool Shift, OldSelecting;
|
||||
int Length;
|
||||
|
||||
if( nMsg != WM_KEYDOWN )
|
||||
// Only looking for keydown messages
|
||||
return S_OK;
|
||||
|
||||
Shift = (GetAsyncKeyState(VK_SHIFT) < 0);
|
||||
OldSelecting = m_bSelecting;
|
||||
m_bSelecting |= Shift; /* Hrrmm.. */
|
||||
|
||||
// Look for special characters
|
||||
switch( wParam )
|
||||
{
|
||||
case VK_DELETE:
|
||||
if (GetAsyncKeyState( VK_SHIFT ) < 0) {
|
||||
Cut();
|
||||
} else {
|
||||
if (m_nCaretChar != m_nSelStartChar) {
|
||||
Delete();
|
||||
} else {
|
||||
if( m_nCaretChar < m_strText.length() ) {
|
||||
// Remove the character
|
||||
m_strText.erase( m_strText.begin() + m_nCaretChar, m_strText.begin() + m_nCaretChar + 1 );
|
||||
if(m_bPassword)
|
||||
m_strPass.erase( m_strPass.begin() + m_nCaretChar, m_strPass.begin() + m_nCaretChar + 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case VK_HOME:
|
||||
put_Caret( 0 );
|
||||
break;
|
||||
|
||||
case VK_END:
|
||||
put_Caret( END );
|
||||
break;
|
||||
|
||||
case VK_INSERT: // cyn, 22/10/2002
|
||||
if (Shift) {
|
||||
m_bSelecting = false;
|
||||
Paste();
|
||||
} else if (GetAsyncKeyState( VK_CONTROL) < 0 ) {
|
||||
Copy();
|
||||
}
|
||||
break;
|
||||
|
||||
case VK_LEFT:
|
||||
if( m_nCaretChar > 0 ) {
|
||||
if (GetAsyncKeyState( VK_CONTROL ) < 0) {
|
||||
if (m_bPassword) {
|
||||
Start = m_strPass.c_str();
|
||||
} else {
|
||||
Start = m_strText.c_str();
|
||||
}
|
||||
|
||||
/* Loop until we find a non-space */
|
||||
for (Search=m_nCaretChar-1;Search>0;Search--) {
|
||||
if (Start[Search] != ' ') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Loop until we find a space */
|
||||
for (;Search>0;Search--) {
|
||||
if (Start[Search] == ' ') {
|
||||
Search++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Search < 0) {
|
||||
_ASSERTE( false );
|
||||
Search = 0;
|
||||
}
|
||||
|
||||
put_Caret( Search );
|
||||
} else {
|
||||
put_Caret( m_nCaretChar - 1 );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case VK_RIGHT:
|
||||
Length = m_strText.length();
|
||||
if( m_nCaretChar < Length ) {
|
||||
if (GetAsyncKeyState( VK_CONTROL ) < 0) {
|
||||
/* Possible change this, AC edit box is slightly different */
|
||||
if (m_bPassword) {
|
||||
Start = m_strPass.c_str();
|
||||
} else {
|
||||
Start = m_strText.c_str();
|
||||
}
|
||||
|
||||
/* Loop until we find a non-space */
|
||||
for (Search=m_nCaretChar+1;Search<Length;Search++) {
|
||||
if (Start[Search] != ' ') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Loop until we find a space */
|
||||
for (;Search<Length;Search++) {
|
||||
if (Start[Search] == ' ') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Loop until we find a non-space again, test it in notepad if you don't believe me */
|
||||
for (;Search<Length;Search++) {
|
||||
if (Start[Search] != ' ') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* It's acceptable to go one character over the end (Search == Length) */
|
||||
if (Search > Length) {
|
||||
_ASSERTE( false );
|
||||
Search = END;
|
||||
}
|
||||
|
||||
put_Caret( Search );
|
||||
} else {
|
||||
put_Caret( m_nCaretChar + 1 );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// No processing
|
||||
m_bSelecting = OldSelecting;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
m_bSelecting = OldSelecting;
|
||||
m_pSite->Invalidate();
|
||||
sendTextChange();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cEdit::get_Text(BSTR *pVal)
|
||||
{
|
||||
_ASSERTE( pVal != NULL );
|
||||
|
||||
*pVal = T2BSTR( m_strText.c_str() );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cEdit::put_Text(BSTR newVal)
|
||||
{
|
||||
USES_CONVERSION;
|
||||
|
||||
m_strText = OLE2T( newVal );
|
||||
|
||||
m_strPass.assign("");
|
||||
|
||||
if(m_bPassword) {
|
||||
m_strPass.append(m_strText.length(), '*');
|
||||
}
|
||||
|
||||
m_nSelStartChar = m_nCaretChar = 0;
|
||||
|
||||
m_pSite->Invalidate();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cEdit::get_Caret(long *pVal)
|
||||
{
|
||||
_ASSERTE( pVal != NULL );
|
||||
|
||||
*pVal = m_nCaretChar;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Only scroll within 10 pixels of the edge
|
||||
#define EDIT_HYSTERESIS 18
|
||||
|
||||
STDMETHODIMP cEdit::put_Caret(long newVal)
|
||||
{
|
||||
std::string strSample;
|
||||
|
||||
checkFont();
|
||||
|
||||
m_nCaretChar = Normalize(newVal);
|
||||
|
||||
if(m_bPassword) {
|
||||
_ASSERTE( m_strPass.length() == m_strText.length() );
|
||||
strSample.assign(m_strPass.begin(), m_strPass.begin() + m_nCaretChar);
|
||||
} else {
|
||||
strSample.assign(m_strText.begin(), m_strText.begin() + m_nCaretChar);
|
||||
}
|
||||
|
||||
|
||||
// Calculate the actual character position
|
||||
SIZE szText;
|
||||
|
||||
if (!SUCCEEDED (m_pFont->MeasureText( _bstr_t( strSample.c_str() ), &szText )))
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
m_nCaretHeight = szText.cy;
|
||||
m_nCaret = szText.cx;
|
||||
|
||||
|
||||
RECT rcPosition;
|
||||
m_pSite->get_Position( &rcPosition );
|
||||
long nWidth = ( rcPosition.right - rcPosition.left ) - m_szMargin.cx * 2 - 2;
|
||||
|
||||
// Check for offset updates
|
||||
if( m_nCaret < ( m_nOffset + EDIT_HYSTERESIS ) )
|
||||
{
|
||||
// The caret has moved in front of the scroll region
|
||||
m_nOffset = m_nCaret - EDIT_HYSTERESIS;
|
||||
if( m_nOffset < 0 )
|
||||
// The offset is less thant the beginning, correct it
|
||||
m_nOffset = 0;
|
||||
}
|
||||
else if( m_nCaret > nWidth + m_nOffset )
|
||||
// The caret has moved off the end of the visible region
|
||||
// NOTE: the +1 is to account for the 1 pixel width of the caret
|
||||
m_nOffset = m_nCaret - nWidth;
|
||||
|
||||
if( m_bCapture )
|
||||
{
|
||||
// Force the caret on for a half second to make sure the user sees the new position
|
||||
m_pSite->EndTimer( TIMER_CARET );
|
||||
m_pSite->StartTimer( TIMER_CARET, 500 );
|
||||
m_bDrawCaret = true;
|
||||
}
|
||||
|
||||
if (m_bSelecting) {
|
||||
if(m_bPassword) {
|
||||
strSample.assign(m_strPass.begin(), m_strPass.begin() + m_nSelStartChar);
|
||||
} else {
|
||||
strSample.assign(m_strText.begin(), m_strText.begin() + m_nSelStartChar);
|
||||
}
|
||||
|
||||
|
||||
if (!SUCCEEDED (m_pFont->MeasureText( _bstr_t( strSample.c_str() ), &szText))) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
m_nSelStart = szText.cx;
|
||||
|
||||
|
||||
} else {
|
||||
m_nSelStartChar = m_nCaretChar;
|
||||
m_nSelStart = m_nCaret;
|
||||
}
|
||||
|
||||
m_pSite->Invalidate();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
nEnd < nStart is a valid condition
|
||||
*/
|
||||
STDMETHODIMP cEdit::Select(long nStart, long nEnd)
|
||||
{
|
||||
bool OldSelection;
|
||||
OldSelection = m_bSelecting;
|
||||
m_bSelecting = false;
|
||||
put_Caret(Normalize(nStart));
|
||||
m_bSelecting = true;
|
||||
put_Caret(Normalize(nEnd));
|
||||
m_bSelecting = OldSelection;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/* I think this is done */
|
||||
STDMETHODIMP cEdit::get_SelectedText(BSTR *pVal) {
|
||||
int Start, Len;
|
||||
|
||||
_ASSERTE(pVal);
|
||||
|
||||
if (m_bPassword) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
if (m_nCaretChar < m_nSelStartChar) {
|
||||
Start = m_nCaretChar;
|
||||
Len = m_nSelStartChar - Start;
|
||||
} else {
|
||||
Start = m_nSelStartChar;
|
||||
Len = m_nCaretChar - Start;
|
||||
}
|
||||
*pVal = T2BSTR( m_strText.substr(Start, Len).c_str() );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cEdit::put_SelectedText(BSTR newVal) {
|
||||
USES_CONVERSION;
|
||||
std::string strInsert;
|
||||
int Length;
|
||||
|
||||
if (m_nCaretChar != m_nSelStartChar) {
|
||||
Delete();
|
||||
}
|
||||
|
||||
strInsert = OLE2T(newVal);
|
||||
Length = strInsert.length();
|
||||
|
||||
m_strText.insert(m_strText.begin() + m_nCaretChar, strInsert.begin(), strInsert.begin() + Length);
|
||||
if (m_bPassword) {
|
||||
m_strPass.insert(m_strPass.begin(), Length, '*');
|
||||
}
|
||||
|
||||
put_Caret( m_nCaretChar + Length );
|
||||
|
||||
m_pSite->Invalidate();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cEdit::TimerTimeout(long nID, long, long, VARIANT_BOOL *pbContinue)
|
||||
{
|
||||
if( nID == TIMER_CARET )
|
||||
{
|
||||
m_bDrawCaret = !m_bDrawCaret;
|
||||
m_pSite->Invalidate();
|
||||
|
||||
*pbContinue = VARIANT_TRUE;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cEdit::SchemaLoad(IView *pView, IUnknown *pSchema)
|
||||
{
|
||||
USES_CONVERSION;
|
||||
|
||||
// Load the font and background image
|
||||
CComPtr< IPluginSite > pPlugin;
|
||||
m_pSite->get_PluginSite( &pPlugin );
|
||||
|
||||
pPlugin->CreateFontSchema( 14, 0, pSchema, &m_pFont );
|
||||
pPlugin->LoadImageSchema( pSchema, &m_pBackground );
|
||||
|
||||
MSXML::IXMLDOMElementPtr pElement = pSchema;
|
||||
|
||||
_variant_t vText = pElement->getAttribute( _T( "text" ) ),
|
||||
vTextColor = pElement->getAttribute( _T( "textcolor" ) ),
|
||||
vMarginX = pElement->getAttribute( _T( "marginx" ) ),
|
||||
vMarginY = pElement->getAttribute( _T( "marginy" ) ),
|
||||
vPassword = pElement->getAttribute( _T( "password" ) ),
|
||||
vOutline = pElement->getAttribute( _T( "outlinecolor" ) ),
|
||||
vAntialias = pElement->getAttribute( _T( "aa" ) );
|
||||
|
||||
if( vText.vt != VT_NULL )
|
||||
{
|
||||
_ASSERTE( vText.vt == VT_BSTR );
|
||||
m_strText = OLE2T( vText.bstrVal );
|
||||
}
|
||||
|
||||
if( vTextColor.vt != VT_NULL )
|
||||
{
|
||||
try
|
||||
{
|
||||
m_nTextColor = static_cast< long >( vTextColor );
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
// Type conversion error
|
||||
_ASSERTE( FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
if( vMarginX.vt != VT_NULL )
|
||||
{
|
||||
try
|
||||
{
|
||||
m_szMargin.cx = static_cast< long >( vMarginX );
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
// Type conversion error
|
||||
_ASSERTE( FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
if( vMarginY.vt != VT_NULL )
|
||||
{
|
||||
try
|
||||
{
|
||||
m_szMargin.cy = static_cast< long >( vMarginY );
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
// Type conversion error
|
||||
_ASSERTE( FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
if( vPassword.vt != VT_NULL)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_bPassword = static_cast< bool >( vPassword );
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
_ASSERTE( FALSE );
|
||||
}
|
||||
}
|
||||
else
|
||||
m_bPassword = false;
|
||||
|
||||
if( vText.vt != VT_NULL )
|
||||
{
|
||||
_ASSERTE( vText.vt == VT_BSTR );
|
||||
m_strText = OLE2T( vText.bstrVal );
|
||||
|
||||
if(m_bPassword)
|
||||
for(int i=0; i<m_strText.length(); i++)
|
||||
m_strPass.append("*");
|
||||
}
|
||||
|
||||
m_nOutlineColor = 0;
|
||||
m_bOutline = false;
|
||||
if( vOutline.vt != VT_NULL )
|
||||
{
|
||||
try
|
||||
{
|
||||
m_bOutline = true;
|
||||
m_nOutlineColor = static_cast< long >( vOutline );
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
// Type conversion error
|
||||
_ASSERTE( FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
m_bAA = true;
|
||||
if( vAntialias.vt != VT_NULL )
|
||||
{
|
||||
try
|
||||
{
|
||||
m_bAA = static_cast< bool >( vAntialias );
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
// Type conversion error
|
||||
_ASSERTE( FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cEdit::get_Background(IImageCacheDisp **pVal)
|
||||
{
|
||||
_ASSERTE( pVal != NULL );
|
||||
|
||||
if( m_pBackground.p == NULL )
|
||||
*pVal = NULL;
|
||||
else
|
||||
m_pBackground->QueryInterface( pVal );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cEdit::putref_Background(IImageCacheDisp *newVal)
|
||||
{
|
||||
if( m_pBackground.p )
|
||||
m_pBackground.Release();
|
||||
|
||||
if( newVal != NULL )
|
||||
{
|
||||
HRESULT hRes = newVal->QueryInterface( &m_pBackground );
|
||||
_ASSERTE( SUCCEEDED( hRes ) );
|
||||
}
|
||||
|
||||
m_pSite->Invalidate();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cEdit::get_Font(IFontCacheDisp **pVal)
|
||||
{
|
||||
_ASSERTE( pVal != NULL );
|
||||
|
||||
if( m_pFont.p == NULL )
|
||||
*pVal = NULL;
|
||||
else
|
||||
m_pFont->QueryInterface( pVal );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cEdit::putref_Font(IFontCacheDisp *newVal)
|
||||
{
|
||||
_ASSERTE( newVal != NULL );
|
||||
|
||||
if( m_pFont.p )
|
||||
m_pFont.Release();
|
||||
|
||||
HRESULT hRes = newVal->QueryInterface( &m_pFont );
|
||||
|
||||
_ASSERTE( SUCCEEDED( hRes ) );
|
||||
|
||||
// Reformat
|
||||
put_Caret( m_nCaretChar );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cEdit::get_TextColor(long *pVal)
|
||||
{
|
||||
_ASSERTE( pVal != NULL );
|
||||
|
||||
*pVal = m_nTextColor;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cEdit::put_TextColor(long newVal)
|
||||
{
|
||||
_ASSERTE( ( newVal & 0xFF000000 ) == 0 );
|
||||
|
||||
m_nTextColor = newVal;
|
||||
m_pSite->Invalidate();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cEdit::SetMargins(long nX, long nY)
|
||||
{
|
||||
_ASSERTE( nX >= 0 && nY >= 0 );
|
||||
|
||||
m_szMargin.cx = nX;
|
||||
m_szMargin.cy = nY;
|
||||
put_Caret( m_nCaretChar );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cEdit::Capture()
|
||||
{
|
||||
_ASSERTE( !m_bCapture );
|
||||
|
||||
if ( m_bAllowCapture ) {
|
||||
m_pSite->CaptureKeyboard();
|
||||
|
||||
/* Until we actually capture the keyboard, other code can still execute */
|
||||
/* If that other code calls put_Caret (eg, put_SelectedText), the timer is set */
|
||||
/* If that timer is set, and we then try to set it again, it has an error */
|
||||
m_bCapture = true;
|
||||
m_bDrawCaret = true;
|
||||
|
||||
m_pSite->Invalidate();
|
||||
m_pSite->StartTimer( TIMER_CARET, 500 );
|
||||
|
||||
if (m_nCaretChar == m_nSelStartChar) {
|
||||
Select(0, END);
|
||||
}
|
||||
|
||||
long nID;
|
||||
m_pSite->get_ID( &nID );
|
||||
Fire_Begin( nID );
|
||||
|
||||
return S_OK;
|
||||
} else {
|
||||
return S_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue