openDecal/Native/DecalControls/Static.cpp
erik d1442e3747 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>
2026-02-08 18:27:56 +01:00

372 lines
7.1 KiB
C++

// Static.cpp : Implementation of cStatic
#include "stdafx.h"
#include "DecalControls.h"
#include "Static.h"
/////////////////////////////////////////////////////////////////////////////
// cStatic
STDMETHODIMP cStatic::get_Font(IFontCacheDisp **pVal)
{
_ASSERTE( pVal != NULL );
if( m_pFont.p == NULL )
*pVal = NULL;
else
m_pFont->QueryInterface( pVal );
return S_OK;
}
STDMETHODIMP cStatic::putref_Font(IFontCacheDisp *newVal)
{
_ASSERTE( newVal != NULL );
if( m_pFont.p )
m_pFont.Release();
HRESULT hRes = newVal->QueryInterface( &m_pFont );
_ASSERTE( SUCCEEDED( hRes ) );
m_pSite->Invalidate();
return S_OK;
}
STDMETHODIMP cStatic::get_Text(BSTR *pVal)
{
_ASSERTE( pVal != NULL );
*pVal = OLE2BSTR( m_strText );
return S_OK;
}
STDMETHODIMP cStatic::put_Text(BSTR newVal)
{
_ASSERTE( newVal != NULL );
m_strText = newVal;
m_pSite->Invalidate();
return S_OK;
}
STDMETHODIMP cStatic::SchemaLoad(IView *pView, IUnknown *pSchema)
{
CComPtr< IPluginSite > pPlugin;
m_pSite->get_PluginSite( &pPlugin );
pPlugin->CreateFontSchema( 14, 0, pSchema, &m_pFont );
MSXML::IXMLDOMElementPtr pElement = pSchema;
_variant_t vText = pElement->getAttribute( _T( "text" ) ),
vTextColor = pElement->getAttribute( _T( "textcolor" ) ),
vWidth = pElement->getAttribute( _T( "width" ) ),
vHeight = pElement->getAttribute( _T( "height" ) ),
vJustify = pElement->getAttribute( _T( "justify" ) ),
vOutline = pElement->getAttribute( _T( "outlinecolor" ) ),
vAntialias = pElement->getAttribute( _T( "aa" ) );
// This is a required element
_ASSERTE( vText.vt == VT_BSTR );
// Store the text, assume left justification
m_strText = vText.bstrVal;
m_eJustify = eFontLeft;
// Determine the proper justification
if (vJustify.vt != VT_NULL)
{
_bstr_t bstrJustify = vJustify.bstrVal;
if (::_wcsicmp(L"left", bstrJustify) == 0)
{
m_eJustify = eFontLeft;
}
else if (::_wcsicmp(L"right", bstrJustify) == 0)
{
m_eJustify = eFontRight;
}
else if (::_wcsicmp(L"center", bstrJustify) == 0)
{
m_eJustify = eFontCenter;
}
}
// Determine the color
if( vTextColor.vt != VT_NULL )
{
try
{
m_nTextColor = static_cast< long >( vTextColor );
}
catch( ... )
{
// Type conversion error
_ASSERTE( FALSE );
}
}
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 );
}
}
/*
// Set the width of the static (not same as text width)
if( vWidth.vt != VT_NULL )
{
try
{
m_nWidth = static_cast< long >( vWidth );
}
catch( ... )
{
// Type conversion error
_ASSERTE( FALSE );
}
}
// Set the height of the static (not same as text height or fontsize)
if( vHeight.vt != VT_NULL )
{
try
{
m_nHeight = static_cast< long >( vHeight );
}
catch( ... )
{
// Type conversion error
_ASSERTE( FALSE );
}
}
*/
return S_OK;
}
STDMETHODIMP cStatic::Render( ICanvas *pCanvas )
{
if( m_pFont.p == NULL )
{
// Create the default font
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 );
}
SIZE Size;
char *token;
POINT ptText = { 0, 0 };
//_bstr_t strText= m_strText.copy();
//_bstr_t temp=_bstr_t("");
// Determine control size
RECT rcPos;
m_pSite->get_Position(&rcPos);
int nWidth = rcPos.right - rcPos.left;
int nHeight = rcPos.bottom - rcPos.top;
// Copy the string for parsing
std::string strText((const char *) m_strText);
// Determine line height
m_pFont->MeasureText(_bstr_t(strText.data()), &Size);
int height = Size.cy;
// Break it into lines (can't use strtok or we miss blank lines)
std::vector<_bstr_t> lines;
int nStart = 0, nEnd;
bool bDone = false;
while (!bDone)
{
// Get the next CR
nEnd = strText.find("\n", nStart);
if (nEnd == std::string::npos)
{
bDone = true;
nEnd = strText.length();
}
// Store the line
lines.push_back(strText.substr(nStart, nEnd - nStart).data());
// Move one character beyond
nStart = nEnd + 1;
}
// Loop through the lines
_bstr_t bstrSpace(" "), bstrEmpty("");
int nIndex, nLines = lines.size();
for (nIndex = 0, bDone = false; !bDone && (nIndex < nLines); nIndex++)
{
// Copy the line for parsing
_bstr_t strLine((const char *) lines[nIndex]);
// Line to be built
_bstr_t strOut = bstrEmpty;
// Loop through the "words" on the line
for (token = ::strtok((char *) strLine, " "); !bDone && (token != NULL); token = ::strtok(NULL, " "))
{
_bstr_t bstrToken(token);
// Measure this token
m_pFont->MeasureText(strOut + bstrToken, &Size);
// Is this line full???
if (Size.cx > nWidth)
{
DrawText(&ptText, strOut, pCanvas);
ptText.y += height;
// Does the next line put us over the top
bDone = ((ptText.y + height) > nHeight) ? true : false;
// Clear the line
strOut = bstrEmpty;
}
// Store the token
strOut += bstrToken + bstrSpace;
}
// Draw as needed
if (!bDone)
{
DrawText(&ptText, strOut, pCanvas);
ptText.y += height;
}
// Does the next line put us over the top
bDone = ((ptText.y + height) > nHeight) ? true : false;
}
/*
if(Size.cx > nWidth)
{
for( token = ::strtok( (char*)strText, " " ); token !=NULL; token = ::strtok( NULL, " " ) )
{
m_pFont->MeasureText(temp + _bstr_t(token), &Size);
if(Size.cx > nWidth)
{
DrawText( &ptText, temp, pCanvas );
ptText.y+=height;//14;
if(ptText.y+height>nHeight)
return S_OK;
temp = _bstr_t(token) + _bstr_t(" ");
}
else
temp += _bstr_t(token) + _bstr_t(" ");
}
DrawText( &ptText, temp, pCanvas );
}
else
{
DrawText( &ptText, strText, pCanvas );
}
*/
return S_OK;
}
STDMETHODIMP cStatic::get_TextColor(long *pVal)
{
_ASSERTE( pVal != NULL );
*pVal = m_nTextColor;
return S_OK;
}
STDMETHODIMP cStatic::put_TextColor(long newVal)
{
_ASSERTE( ( newVal & 0xFF000000L ) == 0 );
m_nTextColor = newVal;
m_pSite->Invalidate();
return S_OK;
}
void cStatic::DrawText(LPPOINT ppt, BSTR szText, ICanvas *pCanvas)
{
POINT pt = *ppt;
RECT rcPos;
m_pSite->get_Position(&rcPos);
int nWidth = rcPos.right - rcPos.left;
int nHeight = rcPos.bottom - rcPos.top;
// Act based on justification style
switch (m_eJustify)
{
case eFontRight:
{
SIZE Size;
m_pFont->MeasureText(szText, &Size);
pt.x = nWidth - Size.cx;
}
break;
case eFontCenter:
{
SIZE Size;
m_pFont->MeasureText(szText, &Size);
pt.x = (nWidth / 2) - (Size.cx / 2);
}
break;
case eFontLeft:
default:
{
// No-Op
}
break;
}
long lFlags = 0;
if( m_bAA )
lFlags |= eAA;
if( m_bOutline )
lFlags |= eOutlined;
m_pFont->DrawTextEx( &pt, szText, m_nTextColor, m_nOutlineColor, lFlags, pCanvas );
}