/** * @file XTPGaugeCtrl.cpp * * @copyright * (c) 1998-2025 Codejock Software, All Rights Reserved. * * This source file is the property of Codejock Software and must not be * redistributed by any means without the explicit written permission of * Codejock Software. * * The use of this source code is governed by the terms and conditions specified * in the Toolkit Pro license agreement. Codejock Software grants you, as a * single software developer, the limited right to use this software on one * computer only. * * Contact Information: * support@codejock.com * http://www.codejock.com * */ // TODO: Make printf-like labels format #include "stdafx.h" #include "Common/XTPTypeId.h" #include "Common/XTPCasting.h" #include "Common/XTPFramework.h" #include "Common/XTPSystemHelpers.h" #include "Common/XTPSynchro.h" #include "Common/XTPApplication.h" #include "Common/XTPSingleton.h" #include "Common/XTPGdiObjects.h" #include "Common/XTPDrawHelpers.h" #include "Common/XTPMarkupRender.h" #include "GraphicLibrary/GdiPlus/XTPGdiPlus.h" #include #include "Markup/XTPMarkupObject.h" #include "Markup/XTPMarkupContext.h" #include "Gauge/XTPGaugeCtrl.h" #include "Gauge/XTPGaugeTraits.h" #include "Gauge/XTPGaugeBaseType.h" #include "Gauge/Types/XTPGaugeMeterType.h" #include "Gauge/Types/XTPGaugeStateType.h" #include "Common/Base/Diagnostic/XTPDisableNoisyWarnings.h" #ifdef _DEBUG # undef THIS_FILE static char THIS_FILE[] = __FILE__; # define new DEBUG_NEW #endif #ifndef LWA_COLORKEY # define LWA_COLORKEY 0x00000001 #endif #ifndef WS_EX_LAYERED # define WS_EX_LAYERED 0x00080000 #endif #define XTP_GAUGE_CLASSNAME _T("XTPGaugeCtrl") IMPLEMENT_DYNAMIC(CXTPGaugeCtrl, CWnd); const UINT CXTPGaugeCtrl::m_XTP_WM_GAUGEUPDATE = ::RegisterWindowMessage( _T("CXTPGaugeCtrl::m_XTP_WM_GAUGEUPDATE")); const UINT CXTPGaugeCtrl::m_XTP_WM_GAUGEDELAYREDRAW = ::RegisterWindowMessage( _T("CXTPGaugeCtrl::m_XTP_WM_GAUGEDELAYREDRAW")); CXTPGaugeCtrl::CXTPGaugeCtrl() : m_bSubclassed(TRUE) , m_bTabStopEnabled(FALSE) , m_bFocused(FALSE) , m_pMarkupContext(NULL) , m_pType(NULL) , m_crTransparent(COLORREF_NULL) , m_crBackground(COLORREF_NULL) , m_pClientSite(NULL) { VERIFY(RegisterWindowClass()); } CXTPGaugeCtrl::~CXTPGaugeCtrl() { _ASSERTE(NULL == m_pMarkupContext); _ASSERTE(NULL == m_pType); } BOOL CXTPGaugeCtrl::RegisterWindowClass(HINSTANCE hInstance /*= NULL*/) { return XTPDrawHelpers()->RegisterWndClass(hInstance, XTP_GAUGE_CLASSNAME, CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, NULL, reinterpret_cast(COLOR_3DFACE + 1)); } BOOL CXTPGaugeCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext /*= NULL*/) { return CWnd::Create(XTP_GAUGE_CLASSNAME, NULL, dwStyle, rect, pParentWnd, nID, pContext); } BOOL CXTPGaugeCtrl::CreateEx(DWORD dwExStyle, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam /*= NULL*/) { return CWnd::CreateEx(dwExStyle, XTP_GAUGE_CLASSNAME, NULL, dwStyle, x, y, nWidth, nHeight, hWndParent, nIDorHMenu, lpParam); } BOOL CXTPGaugeCtrl::CreateEx(DWORD dwExStyle, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, LPVOID lpParam /*= NULL*/) { return CWnd::CreateEx(dwExStyle, XTP_GAUGE_CLASSNAME, NULL, dwStyle, rect, pParentWnd, nID, lpParam); } CXTPGaugeBaseType* CXTPGaugeCtrl::Load(CRuntimeClass* pClass, IStream& source, const CXTPGaugeTraits& traits) { _ASSERTE(NULL != pClass); _ASSERTE(RUNTIME_CLASS(CXTPGaugeBaseType) != pClass); _ASSERTE(pClass->IsDerivedFrom(RUNTIME_CLASS(CXTPGaugeBaseType))); Unload(); m_pMarkupContext = XTPMarkupCreateContext(m_hWnd, TRUE); if (NULL == m_pMarkupContext) { Unload(); return NULL; } m_pType = STATIC_DOWNCAST(CXTPGaugeBaseType, pClass->CreateObject()); if (NULL == m_pType) { TRACE(_T("Unable to create '%s' gauge instance\n"), pClass->m_lpszClassName); Unload(); return NULL; } m_pType->Bind(this); if (!m_pType->Load(m_pMarkupContext, source, traits)) { Unload(); return NULL; } return m_pType; } BOOL CXTPGaugeCtrl::IsType(CRuntimeClass* pClass) const { _ASSERTE(NULL != pClass); return (NULL != m_pType ? m_pType->IsKindOf(pClass) : FALSE); } CXTPGaugeMeterType* CXTPGaugeCtrl::LoadMeterType(IStream& source, const CXTPGaugeTraits& traits) { return STATIC_DOWNCAST(CXTPGaugeMeterType, Load(RUNTIME_CLASS(CXTPGaugeMeterType), source, traits)); } CXTPGaugeMeterType* CXTPGaugeCtrl::GetMeterType() { return (NULL != m_pType ? DYNAMIC_DOWNCAST(CXTPGaugeMeterType, m_pType) : NULL); } CXTPGaugeStateType* CXTPGaugeCtrl::LoadStateType(IStream& source, const CXTPGaugeTraits& traits) { return STATIC_DOWNCAST(CXTPGaugeStateType, Load(RUNTIME_CLASS(CXTPGaugeStateType), source, traits)); } CXTPGaugeStateType* CXTPGaugeCtrl::GetStateType() { return (NULL != m_pType ? DYNAMIC_DOWNCAST(CXTPGaugeStateType, m_pType) : NULL); } void CXTPGaugeCtrl::Unload() { if (NULL != m_pType) { m_pType->Unload(); m_pType->InternalRelease(); m_pType = NULL; } if (NULL != m_pMarkupContext) XTPMarkupReleaseContext(m_pMarkupContext, TRUE); } BOOL CXTPGaugeCtrl::IsTabStopEnabled() const { if (!::IsWindow(*this)) return m_bTabStopEnabled; m_bTabStopEnabled = (0 != (GetWindowLong(*this, GWL_STYLE) & WS_TABSTOP)); return m_bTabStopEnabled; } void CXTPGaugeCtrl::EnableTabStop(BOOL bEnable /*= TRUE*/) { m_bTabStopEnabled = bEnable; if (::IsWindow(*this)) { ModifyStyle(DWORD(bEnable ? 0 : WS_TABSTOP), DWORD(bEnable ? WS_TABSTOP : 0), UINT(SWP_FRAMECHANGED)); if (bEnable) SetFocus(); } } void CXTPGaugeCtrl::NotifyUpdate(CXTPGaugeBaseType& type) { if (NULL != m_pClientSite) { m_pClientSite->OnGaugeUpdated(type); return; } GetParent()->SendMessage(XTP_WM_GAUGEUPDATE, 0, XTPToLRESULT(&type)); } void CXTPGaugeCtrl::Draw(CDC* pDC, const CRect& rcPaint) { _ASSERTE(NULL != pDC); CXTPClientRect rcClient(this); if (NULL == m_pType) { COLORREF crBack = (COLORREF_NULL != m_crTransparent ? m_crTransparent : COLORREF_NULL != m_crBackground ? m_crBackground : GetSysColor(COLOR_3DFACE)); pDC->FillSolidRect(rcClient, crBack); return; } CXTPBufferDC memDC(*pDC, rcPaint); if (COLORREF_NULL != m_crTransparent) memDC.FillSolidRect(rcClient, m_crTransparent); else if (COLORREF_NULL != m_crBackground) memDC.FillSolidRect(rcClient, m_crBackground); m_pType->Draw(memDC, rcClient); } #include "Common/Base/Diagnostic/XTPBeginAfxMap.h" BEGIN_MESSAGE_MAP(CXTPGaugeCtrl, CWnd) ON_WM_CREATE() ON_WM_DESTROY() ON_WM_PAINT() ON_WM_ERASEBKGND() ON_WM_SETFOCUS() ON_WM_KILLFOCUS() ON_REGISTERED_MESSAGE(CXTPGaugeCtrl::m_XTP_WM_GAUGEDELAYREDRAW, CXTPGaugeCtrl::OnDelayRedraw) END_MESSAGE_MAP() #include "Common/Base/Diagnostic/XTPEndAfxMap.h" BOOL CXTPGaugeCtrl::PreCreateWindow(CREATESTRUCT& cs) { m_bSubclassed = FALSE; return CWnd::PreCreateWindow(cs); } void CXTPGaugeCtrl::PreSubclassWindow() { CWnd::PreSubclassWindow(); OnInitialSetup(); } BOOL CXTPGaugeCtrl::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) { if (NULL != m_pType && m_pType->OnWndMsg(message, wParam, lParam, *pResult)) return TRUE; return CWnd::OnWndMsg(message, wParam, lParam, pResult); } int CXTPGaugeCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CWnd::OnCreate(lpCreateStruct) == -1) return -1; OnInitialSetup(); return 0; } void CXTPGaugeCtrl::OnDestroy() { Unload(); CWnd::OnDestroy(); } void CXTPGaugeCtrl::OnPaint() { CPaintDC dc(this); Draw(&dc, dc.m_ps.rcPaint); if (m_bFocused) dc.DrawFocusRect(&dc.m_ps.rcPaint); } BOOL CXTPGaugeCtrl::OnEraseBkgnd(CDC* /*pDC*/) { return FALSE; } LRESULT CXTPGaugeCtrl::OnDelayRedraw(WPARAM, LPARAM) { RedrawWindow(); return 0; } void CXTPGaugeCtrl::OnSetFocus(CWnd* pWnd) { XTP_UNUSED_PARAMETER(pWnd); m_bFocused = TRUE; RedrawWindow(); } void CXTPGaugeCtrl::OnKillFocus(CWnd* pWnd) { XTP_UNUSED_PARAMETER(pWnd); m_bFocused = FALSE; RedrawWindow(); } void CXTPGaugeCtrl::OnInitialSetup() { // Required to update tabstop flag IsTabStopEnabled(); if (COLORREF_NULL != m_crTransparent) ApplyTransparentBackgroundColor(); } void CXTPGaugeCtrl::SetTransparentBackgroundColor(COLORREF color) { if (m_crTransparent == color) return; m_crTransparent = color; if (::IsWindow(*this)) ApplyTransparentBackgroundColor(); } void CXTPGaugeCtrl::SetBackgroundColor(COLORREF color) { if (m_crBackground == color) return; m_crBackground = color; if (::IsWindow(*this)) PostMessage(m_XTP_WM_GAUGEDELAYREDRAW); } void CXTPGaugeCtrl::ApplyTransparentBackgroundColor() { ASSERT(::IsWindow(*this)); if (COLORREF_NULL == m_crTransparent) { ModifyStyleEx(WS_EX_LAYERED, 0, SWP_FRAMECHANGED); return; } typedef BOOL(WINAPI * PFNSetLayeredWindowAttributes)(HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags); static PFNSetLayeredWindowAttributes pfnSetLayeredWindowAttributes = NULL; static BOOL bInitAttempted = FALSE; if (!bInitAttempted) { bInitAttempted = TRUE; HMODULE hUser32 = ::GetModuleHandle(_T("user32.dll")); if (NULL == hUser32) { TRACE(_T("Unable to apply transparent background color: User32.dll not detected.\n")); return; } pfnSetLayeredWindowAttributes = XTPToFunctionPtr( ::GetProcAddress(hUser32, "SetLayeredWindowAttributes")); } if (NULL == pfnSetLayeredWindowAttributes) { TRACE(_T("Unable to apply transparent background color: Layered windows are not ") _T("supported.\n")); return; } if (0 == (GetExStyle() & WS_EX_LAYERED)) ModifyStyleEx(0, WS_EX_LAYERED, SWP_FRAMECHANGED); if (!pfnSetLayeredWindowAttributes(m_hWnd, m_crTransparent, 0, LWA_COLORKEY)) { TRACE(_T("Unable to apply transparent background color: Setting LWA colorkey has failed.\n") _T("Refer to Gauge documentation for related necessary application manifest ") _T("configuration.\n")); return; } PostMessage(m_XTP_WM_GAUGEDELAYREDRAW); }