/** * @file XTButton.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 * */ #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/XTPColorManager.h" #include "Common/XTPDrawHelpers.h" #include "Common/XTPImageManager.h" #include "XTThemeManager.h" #include "XTButtonTheme.h" #include "XTButton.h" #include "Common/Base/Diagnostic/XTPDisableNoisyWarnings.h" #ifdef _DEBUG # define new DEBUG_NEW # undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #ifndef WM_QUERYUISTATE # define WM_UPDATEUISTATE 0x0128 # define WM_QUERYUISTATE 0x0129 # define UISF_HIDEACCEL 0x2 # define UISF_HIDEFOCUS 0x1 #endif ///////////////////////////////////////////////////////////////////////////// // CXTButton ///////////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNAMIC(CXTButton, CButton) IMPLEMENT_THEME_HOST(CXTButton) IMPLEMENT_THEME_REFRESH(CXTButton, CButton) CXTButton::CXTButton(CRuntimeClass* pThemeFactoryClass /*=NULL*/) : CXTThemeManagerStyleHost(pThemeFactoryClass ? pThemeFactoryClass : GetThemeFactoryClass()) , m_nBorderGap(4) , m_nImageGap(8) , m_bPreSubclassInit(true) , m_bUserPosition(false) , m_bChecked(false) , m_dwxStyle(BS_XT_FLAT | BS_XT_SHOWFOCUS) , m_sizeImage(CSize(0, 0)) , m_ptImage(CPoint(0, 0)) , m_ptText(CPoint(0, 0)) , m_pIcon(NULL) { m_bOwnerDraw = FALSE; m_bPushed = FALSE; m_bHot = FALSE; } CXTButton::~CXTButton() { CleanUpGDI(); CMDTARGET_RELEASE(m_pIcon); } HICON CXTButton::GetNormalIcon() { return m_pIcon ? (HICON)m_pIcon->GetIcon() : NULL; } HICON CXTButton::GetSelectedIcon() { return m_pIcon ? (HICON)m_pIcon->GetHotIcon() : NULL; } #include "Common/Base/Diagnostic/XTPBeginAfxMap.h" BEGIN_MESSAGE_MAP(CXTButton, CButton) //{{AFX_MSG_MAP(CXTButton) ON_WM_ERASEBKGND() ON_WM_MOUSEMOVE() ON_WM_CREATE() ON_WM_SETFOCUS() ON_WM_KILLFOCUS() ON_MESSAGE(WM_PRINTCLIENT, OnPrintClient) ON_WM_PAINT() ON_WM_SYSCOLORCHANGE() //}}AFX_MSG_MAP ON_MESSAGE_VOID(WM_MOUSELEAVE, OnMouseLeave) ON_MESSAGE(BM_SETSTYLE, OnDefaultAndInvalidate) ON_MESSAGE(BM_SETCHECK, OnDefaultAndInvalidate) ON_MESSAGE(WM_CAPTURECHANGED, OnDefaultAndInvalidate) ON_MESSAGE_VOID(WM_ENABLE, OnInvalidate) ON_MESSAGE(WM_UPDATEUISTATE, OnUpdateUIState) ON_MESSAGE(BM_SETSTATE, OnSetState) ON_MESSAGE(WM_SETTEXT, OnSetText) //}}AFX_MSG_MAP ON_WM_GETDLGCODE() ON_MESSAGE(BM_SETSTYLE, OnSetStyle) END_MESSAGE_MAP() #include "Common/Base/Diagnostic/XTPEndAfxMap.h" void CXTButton::DrawItem(LPDRAWITEMSTRUCT lpDIS) { GetTheme()->DrawItem(lpDIS, this); } void CXTButton::OnMouseMove(UINT nFlags, CPoint point) { if (GetButtonStyle() == BS_GROUPBOX) return; CButton::OnMouseMove(nFlags, point); CRect rc; GetClientRect(&rc); BOOL bHot = rc.PtInRect(point); if (bHot != m_bHot) { m_bHot = bHot; Invalidate(FALSE); if (m_bHot) { TRACKMOUSEEVENT tme = { sizeof(TRACKMOUSEEVENT), TME_LEAVE, m_hWnd, HOVER_DEFAULT }; _TrackMouseEvent(&tme); } } } LRESULT CXTButton::OnSetState(WPARAM wParam, LPARAM /*lParam*/) { BOOL bVisible = (0 != (GetStyle() & WS_VISIBLE)); if (bVisible) ModifyStyle(WS_VISIBLE, 0); Default(); if (bVisible) ModifyStyle(0, WS_VISIBLE); m_bPushed = (wParam != 0); Invalidate(FALSE); return 0; } void CXTButton::OnSetFocus(CWnd* pOldWnd) { CButton::OnSetFocus(pOldWnd); Invalidate(FALSE); } void CXTButton::OnKillFocus(CWnd* pNewWnd) { CButton::OnKillFocus(pNewWnd); Invalidate(FALSE); } LRESULT CXTButton::OnDefaultAndInvalidate(WPARAM, LPARAM) { LRESULT lResult = Default(); Invalidate(FALSE); return lResult; } void CXTButton::OnInvalidate() { Invalidate(FALSE); } LRESULT CXTButton::OnPrintClient(WPARAM wParam, LPARAM lParam) { if ((lParam & PRF_CLIENT) == 0) return Default(); CDC* pDC = CDC::FromHandle((HDC)wParam); if (pDC) OnDraw(pDC); return 1; } void CXTButton::OnPaint() { CPaintDC dcPaint(this); CXTPBufferDC dc(dcPaint); // device context for painting OnDraw(&dc); } void CXTButton::OnDraw(CDC* pDC) { DRAWITEMSTRUCT dis; ZeroMemory(&dis, sizeof(DRAWITEMSTRUCT)); dis.CtlType = ODT_BUTTON; dis.CtlID = XTPToUInt(GetDlgCtrlID()); dis.itemState = 0; if (::GetFocus() == m_hWnd) dis.itemState |= ODS_FOCUS; if (m_bPushed) dis.itemState |= ODS_SELECTED; LRESULT dwState = SendMessage(WM_QUERYUISTATE); if (dwState & UISF_HIDEACCEL) dis.itemState |= ODS_NOACCEL; if (dwState & UISF_HIDEFOCUS) dis.itemState |= ODS_NOFOCUSRECT; if (!IsWindowEnabled()) dis.itemState |= ODS_DISABLED; dis.hwndItem = m_hWnd; dis.hDC = pDC->GetSafeHdc(); dis.rcItem = CXTPClientRect(this); DrawItem(&dis); } BYTE CXTButton::GetButtonStyle() const { BYTE bStyle = BYTE(GetStyle() & 0xF); return bStyle; } LRESULT CXTButton::OnUpdateUIState(WPARAM wParam, LPARAM lParam) { LRESULT lResult = ::DefWindowProc(m_hWnd, WM_UPDATEUISTATE, wParam, lParam); Invalidate(FALSE); return lResult; } LRESULT CXTButton::OnSetText(WPARAM wParam, LPARAM lParam) { BOOL bVisible = (0 != (GetStyle() & WS_VISIBLE)); if (bVisible) ModifyStyle(WS_VISIBLE, 0); LRESULT lResult = DefWindowProc(WM_SETTEXT, wParam, lParam); if (bVisible) ModifyStyle(0, WS_VISIBLE); Invalidate(FALSE); return lResult; } BOOL CXTButton::OnEraseBkgnd(CDC* /*pDC*/) { return TRUE; } bool CXTButton::Init() { GetTheme()->RefreshMetrics(); m_bOwnerDraw = m_hWnd && ((GetStyle() & 0xF) == BS_OWNERDRAW); if (m_hWnd) Invalidate(FALSE); return true; } void CXTButton::PreSubclassWindow() { CButton::PreSubclassWindow(); if (m_bPreSubclassInit) { // Initialize the control. Init(); } } int CXTButton::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CButton::OnCreate(lpCreateStruct) == -1) return -1; // Initialize the control. Init(); return 0; } BOOL CXTButton::PreCreateWindow(CREATESTRUCT& cs) { if (!CButton::PreCreateWindow(cs)) return FALSE; // When creating controls dynamically Init() must // be called from OnCreate() and not from // PreSubclassWindow(). m_bPreSubclassInit = false; return TRUE; } UINT CXTButton::OnGetDlgCode() { if (m_bOwnerDraw) { if (GetFocus() == this) return DLGC_DEFPUSHBUTTON | DLGC_BUTTON; return DLGC_BUTTON; } return CButton::OnGetDlgCode(); } LRESULT CXTButton::OnSetStyle(WPARAM wParam, LPARAM lParam) { if (m_bOwnerDraw) { DWORD dwOldStyle = GetStyle(); ModifyStyle(0, DWORD(wParam | BS_OWNERDRAW), 0); if ((dwOldStyle != GetStyle()) && LOWORD(lParam)) Invalidate(); return 0; } return OnDefaultAndInvalidate(wParam, lParam); } void CXTButton::OnMouseLeave() { OnMouseMove(0, CPoint(-1, -1)); } ////////////////////////////////////////////////////////////////////////// // CSize CXTButton::GetImageSize() const { if (!GetTheme()->IsIconVisible()) return CSize(0, 0); return m_sizeImage; } CPoint CXTButton::GetImagePoint() const { if (!GetTheme()->IsIconVisible()) return CPoint(0, 0); return m_ptImage; } CPoint CXTButton::GetTextPoint() const { if (!GetTheme()->IsIconVisible()) return CPoint(0, 0); return m_ptText; } void CXTButton::CleanUpGDI() { if (m_pIcon) { m_pIcon->Refresh(); } } BOOL CXTButton::SetIcon(CSize size, UINT nID, UINT nHotID /*= 0*/, BOOL bRedraw /*= TRUE*/) { return CXTButton::SetIcon(size, MAKEINTRESOURCE(nID), MAKEINTRESOURCE(nHotID), bRedraw); } BOOL CXTButton::SetIcon(CSize size, LPCTSTR lpszID, LPCTSTR lpszHotID /*= NULL*/, BOOL bRedraw /*= TRUE*/) { CXTPImageManagerIconHandle hIcon; CXTPImageManagerIconHandle hIconHot; hIcon.CreateIconFromResource(lpszID, size); // Return false if the icon handle is NULL. if (hIcon.IsEmpty()) { TRACE0("Failed to load Icon resource.\n"); return FALSE; } // If we are using a pushed image as well... if (lpszHotID) { hIconHot.CreateIconFromResource(lpszHotID, size); // Return false if the icon handle is NULL. if (hIconHot.IsEmpty()) { TRACE0("Failed to load Icon resource.\n"); return FALSE; } } return CXTButton::SetIcon(size, hIcon, hIconHot, bRedraw); } BOOL CXTButton::SetIcon(CSize size, CXTPImageManagerIcon* pIcon, BOOL bRedraw /*= TRUE*/) { m_sizeImage = size; // Construct the icon manager. CMDTARGET_RELEASE(m_pIcon); m_pIcon = pIcon; // Redraw the button. if (::IsWindow(m_hWnd) && bRedraw) Invalidate(); return TRUE; } BOOL CXTButton::SetIcon(CSize size, const CXTPImageManagerIconHandle& hIcon, const CXTPImageManagerIconHandle& hIconHot, BOOL bRedraw /*= TRUE*/) { _ASSERTE(!hIcon.IsEmpty()); // Save the image size and set the icon // handles to NULL. size = size != CSize(0) ? size : hIcon.GetExtent(); CXTPImageManagerIcon* pIcon = new CXTPImageManagerIcon(0, size.cx, size.cy); pIcon->SetIcon(hIcon); if (!hIconHot.IsEmpty()) pIcon->SetHotIcon(hIconHot); return SetIcon(size, pIcon, bRedraw); } BOOL CXTButton::SetIcon(CSize size, HICON hIcon, HICON hIconHot /*= NULL*/, BOOL bRedraw /*= TRUE*/) { return SetIcon(size, CXTPImageManagerIconHandle(hIcon), CXTPImageManagerIconHandle(hIconHot), bRedraw); } BOOL CXTButton::SetBitmap(CSize size, UINT nID, BOOL bRedraw /*= TRUE*/) { // Free previous resources (if any). CXTPImageManagerIconHandle hIconHandle; BOOL bAlphaBitmap = FALSE; HBITMAP hBitmap = CXTPImageManagerIcon::LoadBitmapFromResource(MAKEINTRESOURCE(nID), &bAlphaBitmap); if (!hBitmap) return FALSE; if (bAlphaBitmap) { hIconHandle.Attach(hBitmap, FALSE); } else { CBitmap bmpIcon; bmpIcon.Attach(hBitmap); // convert the bitmap to a transparent icon. HICON hIcon = CXTPTransparentBitmap(bmpIcon).ConvertToIcon(); hIconHandle.Attach(hIcon, FALSE); } if (hIconHandle.IsEmpty()) return FALSE; return CXTButton::SetIcon(size, hIconHandle, CXTPImageManagerIconHandle(), bRedraw); } BOOL CXTButton::SetTextAndImagePos(CPoint ptImage, CPoint ptText, BOOL bRedraw /*= TRUE*/) { m_ptImage = ptImage; m_ptText = ptText; // Redraw the button. if (::IsWindow(m_hWnd) && bRedraw) Invalidate(); m_bUserPosition = TRUE; return TRUE; } DWORD CXTButton::SetXButtonStyle(DWORD dwxStyle, BOOL bRedraw /*= TRUE*/) { DWORD dwOldStyle = m_dwxStyle; m_dwxStyle = dwxStyle; if ((m_dwxStyle & BS_XT_XPFLAT) == BS_XT_XPFLAT) SetTheme(new CXTButtonThemeOfficeXP()); else if ((m_dwxStyle & BS_XT_FLAT) == BS_XT_FLAT) SetTheme(new CXTButtonTheme()); // Redraw the button. if (::IsWindow(m_hWnd) && bRedraw) Invalidate(); return dwOldStyle; } BOOL CXTButton::IsThemeValid() const { return (GetTheme() != NULL); } CXTPImageManagerIcon* CXTButton::GetIcon() const { return m_pIcon; } CString CXTButton::GetButtonText(BOOL bRemoveAmpersand) { CString strText; GetWindowText(strText); if (bRemoveAmpersand) XTPDrawHelpers()->StripMnemonics(strText); return strText; } void CXTButton::SetAlternateColors(COLORREF clr3DFace, COLORREF clr3DHilight, COLORREF clr3DShadow, COLORREF clrBtnText) { if (IsThemeValid()) { GetTheme()->SetAlternateColors(clr3DFace, clr3DHilight, clr3DShadow, clrBtnText); } } void CXTButton::SetColorFace(COLORREF clrFace) { if (IsThemeValid()) { GetTheme()->SetColorFace(clrFace); } } COLORREF CXTButton::GetColorFace() { if (IsThemeValid()) { return GetTheme()->GetColorFace(); } return GetXtremeColor(COLOR_3DFACE); } void CXTButton::SetColorHilite(COLORREF clrHilite) { if (IsThemeValid()) { GetTheme()->SetColorHilite(clrHilite); } } void CXTButton::SetColorShadow(COLORREF clrShadow) { if (IsThemeValid()) { GetTheme()->SetColorShadow(clrShadow); } } void CXTButton::SetColorText(COLORREF clrText) { if (IsThemeValid()) { GetTheme()->SetColorText(clrText); } } void CXTButton::SetXPFlatColors(COLORREF clrBorder, COLORREF clrHighlight, COLORREF clrPressed) { if (IsThemeValid()) { CXTButtonTheme* pButtonTheme = GetTheme(); if (pButtonTheme->GetTheme() == xtThemeOfficeXP) { ((CXTButtonThemeOfficeXP*)pButtonTheme)->SetColorHilite(clrBorder); ((CXTButtonThemeOfficeXP*)pButtonTheme)->SetColorShadow(clrBorder); ((CXTButtonThemeOfficeXP*)pButtonTheme)->SetBackHiliteColor(clrHighlight); ((CXTButtonThemeOfficeXP*)pButtonTheme)->SetBackPushedColor(clrPressed); } } } void CXTButton::ResetImage() { if (IsThemeValid()) { if (GetTheme()->IsIconVisible()) { GetTheme()->ShowIcon(FALSE); } else { GetTheme()->ShowIcon(TRUE); } Invalidate(); } } CFont* CXTButton::SetFontEx(CFont* pFont) { CFont* pOldFont = GetFont(); CButton::SetFont(pFont); return pOldFont; }