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>
515 lines
No EOL
12 KiB
C++
515 lines
No EOL
12 KiB
C++
#include "stdafx.h"// Slider.cpp : Implementation of cSlider
|
|
#include <stdio.h>
|
|
#include "DecalControls.h"
|
|
#include "Slider.h"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// cSlider
|
|
|
|
cSlider::cSlider() : m_nTextColor(RGB(0, 0, 0)),
|
|
m_bMouseIn(VARIANT_FALSE),
|
|
m_bGrappled(VARIANT_FALSE),
|
|
m_nMinimum(0),
|
|
m_nMaximum(100),
|
|
m_nMinSliderColor( RGB(200,0,0) ),
|
|
m_nMaxSliderColor( RGB(0,200,0) ),
|
|
m_nSliderPos(0),
|
|
m_strTextLeft(NULL),
|
|
m_strTextRight(NULL),
|
|
m_bVertical(VARIANT_FALSE) {
|
|
}
|
|
|
|
cSlider::~cSlider() {
|
|
if (m_strTextLeft)
|
|
free(m_strTextLeft);
|
|
|
|
if (m_strTextRight)
|
|
free(m_strTextRight);
|
|
}
|
|
|
|
STDMETHODIMP cSlider::get_Font(IFontCacheDisp **pVal) {
|
|
_ASSERTE(pVal != NULL);
|
|
|
|
if (m_pFont.p == NULL)
|
|
*pVal = NULL;
|
|
else
|
|
m_pFont->QueryInterface(pVal);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cSlider::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->Reformat();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cSlider::get_TextColor(long *pVal) {
|
|
_ASSERTE(pVal != NULL);
|
|
|
|
*pVal = m_nTextColor;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cSlider::put_TextColor(long newVal) {
|
|
_ASSERTE((newVal & 0xFF000000L) == 0);
|
|
|
|
m_nTextColor = newVal;
|
|
m_pSite->Invalidate();
|
|
Reformat();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP cSlider::get_SliderPosition(long *pVal) {
|
|
_ASSERTE(pVal != NULL);
|
|
|
|
*pVal = m_nSliderPos;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cSlider::put_SliderPosition(long newVal) {
|
|
if (m_nSliderPos == newVal)
|
|
return S_OK;
|
|
|
|
if (newVal < m_nMinimum || newVal > m_nMaximum)
|
|
return S_FALSE;
|
|
|
|
m_nSliderPos = newVal;
|
|
Reformat();
|
|
m_pSite->Invalidate();
|
|
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cSlider::get_Minimum(long *pVal) {
|
|
_ASSERTE(pVal != NULL);
|
|
|
|
*pVal = m_nMinimum;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cSlider::put_Minimum(long newVal) {
|
|
if (m_nMinimum == newVal)
|
|
return S_OK;
|
|
|
|
m_nMinimum = newVal;
|
|
Reformat();
|
|
m_pSite->Invalidate();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cSlider::get_Maximum(long *pVal) {
|
|
_ASSERTE(pVal != NULL);
|
|
|
|
*pVal = m_nMaximum;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cSlider::put_Maximum(long newVal) {
|
|
if (m_nMaximum == newVal)
|
|
return S_OK;
|
|
|
|
m_nMaximum = newVal;
|
|
Reformat();
|
|
m_pSite->Invalidate();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cSlider::SchemaLoad(IView *pView, IUnknown *pSchema)
|
|
{
|
|
// First attempt to load the font
|
|
CComPtr< IPluginSite > pPlugin;
|
|
m_pSite->get_PluginSite( &pPlugin );
|
|
|
|
pPlugin->CreateFontSchema(14, 0, pSchema, &m_pFont);
|
|
|
|
MSXML::IXMLDOMElementPtr pElement = pSchema;
|
|
|
|
_variant_t vTextColor = pElement->getAttribute(_T("textcolor")),
|
|
vMinSliderColor = pElement->getAttribute(_T("mincolor")),
|
|
vMaxSliderColor = pElement->getAttribute(_T("maxcolor")),
|
|
vVertical = pElement->getAttribute(_T("vertical")),
|
|
vDefault = pElement->getAttribute(_T("default")),
|
|
vMaximum = pElement->getAttribute(_T("maximum")),
|
|
vMinimum = pElement->getAttribute(_T("minimum")),
|
|
vName = pElement->getAttribute(_T("name"));
|
|
|
|
// Maximum must exist
|
|
_ASSERTE(vMaximum.vt == VT_INT);
|
|
|
|
if (vTextColor.vt != VT_NULL) {
|
|
try {
|
|
m_nTextColor = static_cast<long>(vTextColor);
|
|
} catch(...) {
|
|
// Type conversion error
|
|
_ASSERTE(FALSE);
|
|
}
|
|
}
|
|
|
|
if (vMinSliderColor.vt != VT_NULL) {
|
|
try {
|
|
_bstr_t szWhat = vMinSliderColor.bstrVal;
|
|
m_nMinSliderColor = wcstoul( szWhat, 0, 16 );
|
|
} catch( ... ) {
|
|
// Type conversion error
|
|
_ASSERTE(FALSE);
|
|
}
|
|
}
|
|
|
|
if (vMaxSliderColor.vt != VT_NULL) {
|
|
try {
|
|
_bstr_t szWhat = vMaxSliderColor.bstrVal;
|
|
m_nMaxSliderColor = wcstoul( szWhat, 0, 16 );
|
|
} catch( ... ) {
|
|
// Type conversion error
|
|
_ASSERTE(FALSE);
|
|
}
|
|
}
|
|
|
|
if (vVertical.vt != VT_NULL) {
|
|
try {
|
|
m_bVertical = (static_cast<bool>(vVertical)) ? VARIANT_TRUE : VARIANT_FALSE;
|
|
} catch( ... ) {
|
|
// Type conversion error
|
|
_ASSERTE(FALSE);
|
|
}
|
|
}
|
|
|
|
if (vMaximum.vt != VT_NULL) {
|
|
try {
|
|
m_nMaximum = static_cast<long>(vMaximum);
|
|
} catch( ... ) {
|
|
// Type conversion error
|
|
_ASSERTE(FALSE);
|
|
}
|
|
}
|
|
|
|
if (vMinimum.vt != VT_NULL) {
|
|
try {
|
|
m_nMinimum = static_cast<long>(vMinimum);
|
|
} catch( ... ) {
|
|
// Type conversion error
|
|
_ASSERTE(FALSE);
|
|
}
|
|
}
|
|
|
|
if (vDefault.vt != VT_NULL) {
|
|
try {
|
|
m_nSliderPos = static_cast<long>(vDefault);
|
|
} catch( ... ) {
|
|
m_nSliderPos = m_nMinimum;
|
|
}
|
|
}
|
|
|
|
/* fprintf( f, "name - %s\n", OLE2A(vName.bstrVal) );
|
|
fprintf( f, "textcolor - %08X\n", m_nTextColor );
|
|
fprintf( f, "mincolor - %08X\n", m_nMinSliderColor );
|
|
fprintf( f, "maxcolor - %08X\n", m_nMaxSliderColor );
|
|
fprintf( f, "vertical - %X\n", m_bVertical );
|
|
fprintf( f, "maximum - %08X\n", m_nMaximum );
|
|
fprintf( f, "minimum - %08X\n\n", m_nMinimum ); */
|
|
|
|
/* // it's a pain in the ass that we need set the min and max for them to work, aye? let's fix it
|
|
RECT rc;
|
|
m_pSite->get_Position(&rc);
|
|
|
|
long siteHHalf = (rc.bottom - rc.top) / 2;
|
|
|
|
// The background bar
|
|
m_rcBackground.left = 0;
|
|
m_rcBackground.top = siteHHalf - 4;
|
|
m_rcBackground.bottom = siteHHalf + 6;
|
|
m_rcBackground.right = rc.right - rc.left;
|
|
|
|
// The middle bar
|
|
m_rcBar.top = siteHHalf;
|
|
m_rcBar.left = 0;
|
|
m_rcBar.bottom = siteHHalf + 3;
|
|
m_rcBar.right = rc.right - rc.left;
|
|
|
|
// Ensure sane slider position
|
|
if (m_nSliderPos < m_nMinimum)
|
|
m_nSliderPos = m_nMinimum;
|
|
|
|
if (m_nSliderPos > m_nMaximum)
|
|
m_nSliderPos = m_nMaximum;
|
|
|
|
long siteDiff = abs(m_rcBar.right - m_rcBar.left);
|
|
long extentDiff = abs(m_nMaximum - m_nMinimum);
|
|
long valDiff = m_nSliderPos - m_nMinimum;
|
|
|
|
if (valDiff == 0) {
|
|
m_ptSlider.x = m_rcBar.left;
|
|
|
|
} else {
|
|
long diff = (long)(((float)valDiff / (float)extentDiff) * (float)siteDiff);
|
|
|
|
m_ptSlider.x = m_rcBar.left + diff;
|
|
|
|
if (m_ptSlider.x >= m_rcBar.right - 6)
|
|
m_ptSlider.x = m_rcBar.right - 6;
|
|
}
|
|
|
|
m_ptSlider.y = siteHHalf - 5;
|
|
*/
|
|
|
|
// fclose( f );
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cSlider::Reformat() {
|
|
USES_CONVERSION;
|
|
|
|
char strTemp[16];
|
|
|
|
if (m_strTextLeft)
|
|
free(m_strTextLeft);
|
|
|
|
if (m_strTextRight)
|
|
free(m_strTextRight);
|
|
|
|
_snprintf(strTemp, 15, "%i", m_nMinimum);
|
|
m_strTextLeft = strdup(strTemp);
|
|
|
|
_snprintf(strTemp, 15, "%i", m_nMaximum);
|
|
m_strTextRight = strdup(strTemp);
|
|
|
|
if (m_pFont.p == NULL) {
|
|
// No font was specified, 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);
|
|
}
|
|
|
|
RECT rc;
|
|
m_pSite->get_Position(&rc);
|
|
|
|
SIZE textRight;
|
|
|
|
m_pFont->MeasureText(_bstr_t(m_strTextRight), &textRight);
|
|
|
|
long siteHHalf = (rc.bottom - rc.top) / 2;
|
|
|
|
// The background bar
|
|
m_rcBackground.left = 0;
|
|
m_rcBackground.top = siteHHalf - 4;
|
|
m_rcBackground.bottom = siteHHalf + 6;
|
|
m_rcBackground.right = rc.right - rc.left;
|
|
|
|
// The middle bar
|
|
m_rcBar.top = siteHHalf;
|
|
m_rcBar.left = 0;
|
|
m_rcBar.bottom = siteHHalf + 3;
|
|
m_rcBar.right = rc.right - rc.left;
|
|
|
|
m_ptLeftText.x = m_rcBackground.left + 1;
|
|
m_ptLeftText.y = m_rcBackground.bottom + 1;
|
|
m_ptRightText.x = m_rcBackground.right - (textRight.cx + 1);
|
|
m_ptRightText.y = m_rcBackground.bottom + 1;
|
|
|
|
// Ensure sane slider position
|
|
if (m_nSliderPos < m_nMinimum)
|
|
m_nSliderPos = m_nMinimum;
|
|
|
|
if (m_nSliderPos > m_nMaximum)
|
|
m_nSliderPos = m_nMaximum;
|
|
|
|
long siteDiff = abs(m_rcBar.right - m_rcBar.left);
|
|
long extentDiff = abs(m_nMaximum - m_nMinimum);
|
|
long valDiff = m_nSliderPos - m_nMinimum;
|
|
|
|
if (valDiff == 0) {
|
|
m_ptSlider.x = m_rcBar.left;
|
|
|
|
} else {
|
|
long diff = (long)(((float)valDiff / (float)extentDiff) * (float)siteDiff);
|
|
|
|
m_ptSlider.x = m_rcBar.left + diff;
|
|
|
|
if (m_ptSlider.x >= m_rcBar.right - 6)
|
|
m_ptSlider.x = m_rcBar.right - 6;
|
|
}
|
|
|
|
m_ptSlider.y = siteHHalf - 5;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cSlider::Render(ICanvas *pCanvas)
|
|
{
|
|
// intensity to lose or gain for 3d effect
|
|
#define COLOR_BAND 20
|
|
|
|
USES_CONVERSION;
|
|
|
|
CComPtr<IPluginSite> pPlugin;
|
|
m_pSite->get_PluginSite(&pPlugin);
|
|
|
|
CComPtr<IIconCache> pIcon;
|
|
SIZE szIcon = {7, 12};
|
|
pPlugin->GetIconCache(&szIcon, &pIcon);
|
|
|
|
// we're averaging color differences w/bias...
|
|
float fractional = m_nSliderPos / m_nMaximum;
|
|
float lFraction = (1 - fractional) * 2;
|
|
float rFraction = fractional * 2;
|
|
|
|
long lMinSliderRed = lFraction * (BYTE) m_nMinSliderColor;
|
|
long lMinSliderGreen = lFraction * (BYTE) (m_nMinSliderColor >> 8);
|
|
long lMinSliderBlue = lFraction * (BYTE) (m_nMinSliderColor >> 16);
|
|
|
|
long lMaxSliderRed = rFraction * (BYTE) m_nMaxSliderColor;
|
|
long lMaxSliderGreen = rFraction * (BYTE) (m_nMaxSliderColor >> 8);
|
|
long lMaxSliderBlue = rFraction * (BYTE) (m_nMaxSliderColor >> 16);
|
|
|
|
long lFillColorTop, lFillColorMiddle, lFillColorBottom;
|
|
|
|
long lFillColorRed = (lMinSliderRed + lMaxSliderRed) / 2,
|
|
lFillColorGreen = (lMinSliderGreen + lMaxSliderGreen) / 2,
|
|
lFillColorBlue = (lMinSliderBlue + lMaxSliderBlue) / 2;
|
|
|
|
if( m_nMinSliderColor && m_nMaxSliderColor ) // not black .. who would choose all black for both bars anyway? grr.
|
|
{
|
|
// find the most intense color channel to maul for our evil purposes (we're using std::max here)
|
|
long lMax = max( max( lFillColorRed, lFillColorGreen ), lFillColorBlue );
|
|
|
|
// if we're dark, don't overflow
|
|
long lOffset = lMax > (COLOR_BAND - 1) ? COLOR_BAND : 0;
|
|
long lOffset2 = lMax > (COLOR_BAND - 1) ? 0 : COLOR_BAND;
|
|
|
|
// red
|
|
if( lMax == lFillColorRed )
|
|
{
|
|
lFillColorTop = RGB( lFillColorRed - lOffset, lFillColorGreen, lFillColorBlue );
|
|
lFillColorMiddle = RGB( lFillColorRed + lOffset2, lFillColorGreen, lFillColorBlue );
|
|
lFillColorBottom = RGB( lFillColorRed - lOffset, lFillColorGreen, lFillColorBlue );
|
|
}
|
|
|
|
// green
|
|
else if( lMax == lFillColorGreen )
|
|
{
|
|
lFillColorTop = RGB( lFillColorRed, lFillColorGreen - lOffset, lFillColorBlue );
|
|
lFillColorMiddle = RGB( lFillColorRed, lFillColorGreen + lOffset2, lFillColorBlue );
|
|
lFillColorBottom = RGB( lFillColorRed, lFillColorGreen - lOffset, lFillColorBlue );
|
|
}
|
|
|
|
// has to be blue
|
|
else
|
|
{
|
|
lFillColorTop = RGB( lFillColorRed, lFillColorGreen, lFillColorBlue - lOffset );
|
|
lFillColorMiddle = RGB( lFillColorRed, lFillColorGreen, lFillColorBlue + lOffset2 );
|
|
lFillColorBottom = RGB( lFillColorRed, lFillColorGreen, lFillColorBlue - lOffset );
|
|
}
|
|
}
|
|
|
|
// someone's a GOTH
|
|
else
|
|
{
|
|
lFillColorTop = 0;
|
|
lFillColorMiddle = 0x00161616;
|
|
lFillColorBottom = 0;
|
|
}
|
|
|
|
pCanvas->Fill( &m_rcBar, lFillColorMiddle );
|
|
|
|
RECT topBar = {m_rcBar.left, m_rcBar.top, m_rcBar.right, m_rcBar.top + 1};
|
|
pCanvas->Fill( &topBar, lFillColorTop );
|
|
|
|
RECT bottomBar = {m_rcBar.left, m_rcBar.bottom - 1, m_rcBar.right, m_rcBar.bottom};
|
|
pCanvas->Fill( &bottomBar, lFillColorBottom );
|
|
|
|
pIcon->DrawIcon(&m_ptSlider, 0x06001286, 0, pCanvas);
|
|
|
|
m_pFont->DrawText(&m_ptLeftText, _bstr_t(m_strTextLeft), RGB(0, 0, 0), pCanvas);
|
|
m_pFont->DrawText(&m_ptRightText, _bstr_t(m_strTextRight), RGB(0, 0, 0), pCanvas);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cSlider::MouseDown(struct MouseState *mouseState) {
|
|
_ASSERTE(m_pSite != NULL);
|
|
|
|
POINT pt = mouseState->client;
|
|
|
|
if (pt.x >= (m_ptSlider.x) && (pt.x <= m_ptSlider.x + 6) &&
|
|
pt.y >= (m_ptSlider.y) && (pt.y <= m_ptSlider.y + 12)) {
|
|
// They hit the grapple point!
|
|
m_ptLastMouse = mouseState->client;
|
|
m_bGrappled = VARIANT_TRUE;
|
|
} else {
|
|
// The hit the bar - see if that's within the bar rect
|
|
|
|
if (pt.x > m_rcBar.left && pt.x < m_rcBar.right &&
|
|
pt.y > (m_rcBar.top - 3) && pt.y < (m_rcBar.bottom + 3)) {
|
|
|
|
// Calcuate the new slider position
|
|
float pixelValue = (float)((float)(m_nMaximum - m_nMinimum) / (float)(m_rcBar.right - m_rcBar.left));
|
|
|
|
m_nSliderPos = (pt.x - m_rcBar.left) * pixelValue;
|
|
|
|
Reformat();
|
|
m_pSite->Invalidate();
|
|
|
|
long nID;
|
|
m_pSite->get_ID(&nID);
|
|
_ASSERTE(m_pSite.p != NULL);
|
|
Fire_Change(nID, m_nSliderPos);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cSlider::MouseUp(struct MouseState *mouseState) {
|
|
m_bGrappled = VARIANT_FALSE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cSlider::MouseMove(struct MouseState *mouseState) {
|
|
if (m_bGrappled) {
|
|
long dx;
|
|
POINT pt = mouseState->client;
|
|
|
|
dx = m_ptLastMouse.x - pt.x;
|
|
m_ptLastMouse = pt;
|
|
|
|
float pixelValue = (float)((float)(m_nMaximum - m_nMinimum) / (float)(m_rcBar.right - m_rcBar.left));
|
|
m_nSliderPos -= ((float)dx * pixelValue);
|
|
|
|
// I personally like being able to drag the slider
|
|
// PAST THE EDGE OF THE SLIDE BAR without needing pixel accuracy...
|
|
if( pt.x >= m_rcBar.right )
|
|
m_nSliderPos = m_nMaximum;
|
|
|
|
Reformat();
|
|
m_pSite->Invalidate();
|
|
|
|
long nID;
|
|
m_pSite->get_ID(&nID);
|
|
_ASSERTE(m_pSite.p != NULL);
|
|
Fire_Change(nID, m_nSliderPos);
|
|
}
|
|
|
|
return S_OK;
|
|
} |