Files
envi-code/SourceCode/Code2026/Dimension/CaptionButton.cpp
T
gjm 164968b62e chore
把非utf8-bom编码的cpp/h文件改为 utf8 bom 编码, msvc识别utf8编码时,如果不是bom格式的,会使用当前cp_oem来解码.
2026-10-04 00:04:20 +08:00

464 lines
12 KiB
C++

#include "stdafx.h"
#include "CaptionButton.h"
#include "globalFunc.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CCaptionButton::CCaptionButton(const TCHAR* sTip,
UINT ID_Bmp_up, UINT ID_Bmp_down,
BOOL bCheckBtn)
{
m_pParent=NULL;
m_sTip=sTip;
m_idBmpUp = ID_Bmp_up;
m_idBmpDown = ID_Bmp_down;
m_bCheckBtn = bCheckBtn;
m_bEnable = TRUE;
m_bBtnChecked = FALSE;
m_bHighLight = FALSE;
m_rc = CRect(0,0,0,0);
m_uiBtnCount = 0;
m_CAdj = new COLORADJUSTMENT;
m_TME.cbSize = sizeof(TRACKMOUSEEVENT);
m_TME.dwFlags = TME_LEAVE;
m_TME.dwHoverTime = HOVER_DEFAULT;
}
CCaptionButton::~CCaptionButton()
{
delete m_CAdj;
}
// announce the user defined message:
DECLARE_USER_MESSAGE(WMU_HITCAPBUTTON)
// point = the position where the hit occured
// bHover = check if mouse was only hovering(TRUE) or clicked(FALSE)
// return value = button hovered/clicked
BOOL CCaptionButton::ButtonHitTest(CPoint point, BOOL bHover)
{
if(m_pParent==NULL)
return FALSE;
if(m_bEnable)
{
CPoint hitPoint;
::ScreenToClient(GetHWnd(), &point);
hitPoint.x = point.x;
hitPoint.y = point.y *(-1); // *(-1) because the point.y has coordinates of
// the client area (i.e. -12) and we need the point in the NC area (i.e. 12)
if(m_rc.PtInRect(hitPoint))
{
if(bHover)
{
if(!m_bHighLight)
{
m_bHighLight = TRUE;
::RedrawWindow(GetHWnd(), m_rc, NULL, RDW_INVALIDATE | RDW_FRAME);
return TRUE;
}
}
else
{
m_bHighLight = TRUE;
if(m_bCheckBtn)
m_bBtnChecked ? m_bBtnChecked = FALSE : m_bBtnChecked = TRUE;
::RedrawWindow(GetHWnd(), m_rc, NULL, RDW_INVALIDATE | RDW_FRAME);
::SendMessage(GetHWnd(), WMU_HITCAPBUTTON , (WPARAM)m_uiBtnCount, (LPARAM)m_bBtnChecked);
return TRUE;
}
}
else if(m_bHighLight)
{
m_bHighLight = FALSE;
//::RedrawWindow(m_hWndCap, m_rc,NULL, RDW_INVALIDATE | RDW_FRAME|RDW_ERASE);//不能正确erase局部!
::RedrawWindow(GetHWnd(), NULL,NULL, RDW_INVALIDATE | RDW_FRAME|RDW_NOCHILDREN);
CRect rect;
::GetClientRect(GetHWnd(),rect);
::ValidateRect(GetHWnd(),rect);
}
}
return FALSE;
}
#define ICON_SIZE 13
// uiBtnCount = the no. of the button to paint
// return value = button checked TRUE/FALSE
BOOL CCaptionButton::PaintBmpCheckBtn()
{
if(m_pParent==NULL)
return FALSE;
UINT BmpID = 0;
CSize sizeButton(0,0);
CDC dcMemo;
CWnd *pWnd=CWnd::FromHandle(GetHWnd());
if(pWnd==NULL)
return FALSE;
CDC *dc =CWnd::FromHandle(GetHWnd())->GetWindowDC();
if(dc==NULL)
return FALSE;
// calculate the caption rectangle:
CalcCapRect();
CRect rect(m_rc);
GlobalFunc::Exchange(rect.top,rect.bottom);
rect.top*=-1;
rect.bottom*=-1;
m_pParent->m_ctrlTip.SetToolRect(CWnd::FromHandle(GetHWnd()),m_uiBtnCount,rect);
CRect iconRect=m_rc;
if(iconRect.Width()>ICON_SIZE)
{
iconRect.left+=(iconRect.Width()-ICON_SIZE)/2;
iconRect.right=iconRect.left +ICON_SIZE;
}
if(iconRect.Height()>ICON_SIZE)
{
iconRect.top+=(iconRect.Height()-ICON_SIZE)/2;
iconRect.bottom=iconRect.top +ICON_SIZE;
}
// find state and load bitmap from the resource:
if(m_bCheckBtn)
m_bBtnChecked ? BmpID = m_idBmpDown : BmpID = m_idBmpUp;
else
m_bHighLight ? BmpID = m_idBmpDown : BmpID = m_idBmpUp;
if(m_bHighLight)
{
CBrush brush(RGB(120,195,240));
//CBrush brush(RGB(202,236,255));
CBrush* pOldBrush=dc->SelectObject(&brush);
dc->Rectangle(m_rc);
dc->SelectObject(pOldBrush);
}
HGDIOBJ hOldBitmap;
HBITMAP hBmp;
{
CTemporaryResourceOverride vTemp;
// load the bitmap into the handle:
hBmp= (HBITMAP)::LoadImage(AfxGetResourceHandle(),
MAKEINTRESOURCE(BmpID),
IMAGE_BITMAP,
ICON_SIZE,
ICON_SIZE,
LR_LOADMAP3DCOLORS);
dcMemo.CreateCompatibleDC(dc);
hOldBitmap=dcMemo.SelectObject(hBmp);
}
if(!m_bEnable)
{ // set the stretch-draw-mode to HALFTONE:
dc->SetStretchBltMode(HALFTONE);
// get the current COLORADJUSTMET struct:
dc->GetColorAdjustment(m_CAdj);
// change some values of the struct:
m_CAdj->caColorfulness = -80;
m_CAdj->caBrightness = -25;
// set the changed struct:
dc->SetColorAdjustment(m_CAdj);
}
// blow the bitmap to the titlebar:
OSVERSIONINFO osvi;
ZeroMemory( &osvi, sizeof( osvi ) );
osvi.dwOSVersionInfoSize = sizeof( osvi );
GetVersionEx( &osvi );
if(osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)//9X
{
dc->StretchBlt( iconRect.left, iconRect.top,
ICON_SIZE, ICON_SIZE,
&dcMemo,
0, 0,
ICON_SIZE, ICON_SIZE,
SRCCOPY);
}
else
::TransparentBlt(dc->m_hDC,iconRect.left,iconRect.top,ICON_SIZE,ICON_SIZE,dcMemo.m_hDC,
0,0,ICON_SIZE,ICON_SIZE,GetSysColor(COLOR_3DFACE));
dcMemo.SelectObject(hOldBitmap);
DeleteObject(hBmp);
if(m_bHighLight)
dc->Draw3dRect(m_rc,RGB(0, 0, 0),RGB(0, 0, 0));
// clean up:
::ReleaseDC(GetHWnd() ,dcMemo.m_hDC);
::ReleaseDC(GetHWnd() ,dc->m_hDC);
return m_bBtnChecked;
}
// pCapRect = pointer to the caption rectangle
void CCaptionButton::CalcCapRect()
{
CRect *pCapRect=&m_rc;
if(m_pParent==NULL)
return;
CSize sizeButton(0,0);
CSize sizeCaption(0,0);
// Get the needed system metrics:
CSize sizeFrame (GetSystemMetrics(SM_CXFRAME), GetSystemMetrics(SM_CYFRAME));
#ifndef _WIN64
if(GetWindowLong(GetHWnd(), GWL_EXSTYLE) & WS_EX_TOOLWINDOW)
#else
if(GetWindowLongPtr(GetHWnd(), GWL_EXSTYLE) & WS_EX_TOOLWINDOW)
#endif
{
sizeButton.cy = sizeButton.cx = GetSystemMetrics(SM_CYSMSIZE);
sizeCaption.cy= GetSystemMetrics(SM_CYSMCAPTION);
}
else
{
sizeButton.cy = sizeButton.cx = GetSystemMetrics(SM_CYSIZE);
sizeCaption.cy= GetSystemMetrics(SM_CYCAPTION);
}
// Get the window rectangle and window style:
CRect rcWindow;
CWnd::FromHandle(GetHWnd())->GetWindowRect(rcWindow);
DWORD dwStyle = CWnd::FromHandle(GetHWnd())->GetStyle();
// Set the rectangle based on the system metrics:
//if (dwStyle & WS_THICKFRAME)
//{
// pCapRect->left = 0;
// pCapRect->top = ((sizeCaption.cy+sizeFrame.cy)-sizeButton.cy);
// // assume there are already 3 buttons
// pCapRect->right = rcWindow.Width()-(((1+m_uiBtnCount)*sizeButton.cx))-3;
//}
if (dwStyle & WS_MINIMIZEBOX||dwStyle & WS_MAXIMIZEBOX)
{
pCapRect->left = 0;
pCapRect->top = ((sizeCaption.cy+sizeFrame.cy)-sizeButton.cy);
// assume there are already 3 buttons
pCapRect->right = rcWindow.Width()-(((2+m_uiBtnCount)*sizeButton.cx))-3;
}
else if (dwStyle & WS_SYSMENU)
{
pCapRect->left = 0;
pCapRect->top = ((sizeCaption.cy+sizeFrame.cy)-sizeButton.cy);
// assume there is only 1 button
pCapRect->right = rcWindow.Width()-(((m_uiBtnCount+1)*sizeButton.cx))-2;
}
else if (dwStyle & WS_CAPTION)
{
pCapRect->left = 0;
pCapRect->top = ((sizeCaption.cy+sizeFrame.cy)-sizeButton.cy);
// assume there is no button
// gjm modify 100811,解决“专业词库”对话框,在WIN7和VISTA操作系统下,“X”符号必须点击在对话框之外才起作用的BUG
// pCapRect->right = rcWindow.Width()-(m_uiBtnCount*sizeButton.cx)-2;
pCapRect->right = rcWindow.Width()-(m_uiBtnCount*sizeButton.cx)-7;
}
pCapRect->bottom = ((pCapRect->top - sizeFrame.cy)) + sizeButton.cy;
pCapRect->right -=3;
pCapRect->left = pCapRect->right - sizeButton.cx+2;
}
// return value = previous button state
BOOL CCaptionButton::EnableButton(BOOL bEnable)
{
if(m_pParent==NULL)
return FALSE;
if(m_bEnable == bEnable) return m_bEnable;
BOOL bOld = m_bEnable;
m_bEnable = bEnable;
::RedrawWindow(GetHWnd(), m_rc, NULL, RDW_INVALIDATE | RDW_FRAME);
return bOld;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL CCapToolTip::AddToolTip( UINT nID, LPRECT lpRect, LPCTSTR lpszText )
{
TOOLINFO Tips;
memset(&Tips, 0, sizeof(TOOLINFO));
Tips.cbSize = sizeof(TOOLINFO);
Tips.hwnd = GetOwner()->GetSafeHwnd();
Tips.uFlags = TTF_SUBCLASS;
Tips.uId = nID;
memcpy(&Tips.rect, lpRect, sizeof(RECT));
Tips.lpszText = (LPTSTR)lpszText;
return (BOOL)SendMessage(TTM_ADDTOOL, 0, (LPARAM)&Tips);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DualPtrList<CCapBtnWnd*> g_lstCapWnd;//全局CCapBtnWnd
CCapBtnWnd::CCapBtnWnd():m_hWndCap(NULL),m_pWndProcOld(NULL)
{
g_lstCapWnd.AddTail(this);
}
CCapBtnWnd::~CCapBtnWnd()
{
g_lstCapWnd.FindAndDel(this);
}
LRESULT CALLBACK HookedWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
CCapBtnWnd *pBtnWnd=NULL;
for(g_lstCapWnd.MoveToFirst();!g_lstCapWnd.IsOut();g_lstCapWnd.MoveToNext())
{
if(g_lstCapWnd.GetCurData()->GetHWnd()==hWnd)
{
pBtnWnd=g_lstCapWnd.GetCurData();
break;
}
}
if(pBtnWnd==NULL)
return 0;
return pBtnWnd->HookProc(message,wParam,lParam);
}
void CCapBtnWnd::Hook(HWND hWnd)
{
m_hWndCap=hWnd;
if(m_hWndCap!=NULL)
{
#ifdef _WIN64
m_pWndProcOld = (WNDPROC)::SetWindowLongPtr(hWnd , GWLP_WNDPROC, (DWORD_PTR)HookedWindowProc);
#else
m_pWndProcOld = (WNDPROC)::SetWindowLong(hWnd , GWL_WNDPROC, (DWORD)HookedWindowProc);
#endif
if(IsHooked())
m_ctrlTip.Create(CWnd::FromHandle(m_hWndCap),TTS_ALWAYSTIP);
}
}
void CCapBtnWnd::UnHook()
{
if(IsHooked())
{
#ifdef _WIN64
SetWindowLongPtr(GetHWnd() , GWLP_WNDPROC, (DWORD_PTR)m_pWndProcOld);
#else
SetWindowLong(GetHWnd() , GWL_WNDPROC, (DWORD)m_pWndProcOld);
#endif
m_pWndProcOld=NULL;
m_hWndCap=NULL;
}
}
void CCapBtnWnd::AddCapBtn(CCaptionButton*pBtn)
{
pBtn->SetParent(this);
pBtn->SetIndex(m_lstBtn.GetLength());
pBtn->CalcCapRect();
pBtn->m_TME.hwndTrack = m_hWndCap;
CRect rect(pBtn->m_rc);
GlobalFunc::Exchange(rect.top,rect.bottom);
rect.top*=-1;
rect.bottom*=-1;
m_ctrlTip.AddToolTip(pBtn->GetIndex(),rect,pBtn->m_sTip);
m_lstBtn.AddTail(pBtn);
}
BOOL CCapBtnWnd::IsWindowActive(BOOL &bActive)
{
// Mimic MFC kludge to stay active if WF_STAYACTIVE bit is on
if (CWnd::FromHandle(m_hWndCap)->m_nFlags & WF_STAYACTIVE)
bActive = TRUE;
if (!CWnd::FromHandle(m_hWndCap)->IsWindowEnabled()) // but not if disabled
bActive = FALSE;
if (bActive == m_bActive)
return TRUE; // nothing to do
m_bActive = bActive; // update the state of the Bitmaps
// do not call the base class because it will call Default()
// and we may have changed bActive.
return ::DefWindowProc(m_hWndCap, WM_NCACTIVATE, bActive, 0L);
}
LRESULT CCapBtnWnd::HookProc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_NCACTIVATE:
{
// intercept WM_NCACTIVATE and call the static function isWindowActive!
// do not call the base class because it will call Default()
// and we may have changed bActive.
// get object for this buttons from the map:
BOOL b = IsWindowActive((BOOL &)wParam);
// Now it's time to repaint the button(s):
// get object for this buttons from the map:
for(m_lstBtn.MoveToFirst();!m_lstBtn.IsOut();m_lstBtn.MoveToNext())
m_lstBtn.GetCurData()->PaintBmpCheckBtn();
return b;
}
break;
case WM_NCLBUTTONDOWN:
case WM_NCLBUTTONDBLCLK:
{
for(m_lstBtn.MoveToFirst();!m_lstBtn.IsOut();m_lstBtn.MoveToNext())
m_lstBtn.GetCurData()->ButtonHitTest((CPoint)lParam);
break;
}
case WM_NCRBUTTONDOWN:
case WM_NCRBUTTONUP:
case WM_NCRBUTTONDBLCLK:
case WM_NCMBUTTONDOWN:
case WM_NCMBUTTONUP:
case WM_NCMBUTTONDBLCLK:
return 0;
case WM_NCMOUSEMOVE:
{
for(m_lstBtn.MoveToFirst();!m_lstBtn.IsOut();m_lstBtn.MoveToNext())
{
if(m_lstBtn.GetCurData()->ButtonHitTest((CPoint)lParam, TRUE))
return 0;
else
_TrackMouseEvent(&(m_lstBtn.GetCurData()->m_TME));
}
}
break;
#if(WINVER >= 0x0500)
case WM_NCMOUSELEAVE:
{
for(m_lstBtn.MoveToFirst();!m_lstBtn.IsOut();m_lstBtn.MoveToNext())
{
m_lstBtn.GetCurData()->ButtonHitTest((CPoint)lParam, TRUE);
_TrackMouseEvent(&(m_lstBtn.GetCurData()->m_TME));
}
}
break;
#endif
case WM_NCPAINT:
{
LRESULT nRet=::CallWindowProc(m_pWndProcOld, GetHWnd(), message, wParam, lParam);
// get object for this buttons from the map:
for(m_lstBtn.MoveToFirst();!m_lstBtn.IsOut();m_lstBtn.MoveToNext())
m_lstBtn.GetCurData()->PaintBmpCheckBtn();
return nRet;
}
}
// if the message is not handled yet then return to the original window proc:
return ::CallWindowProc(m_pWndProcOld, m_hWndCap, message, wParam, lParam);
}